From a1c8444a2be57e8a6bc230f200207b6fdb0865d8 Mon Sep 17 00:00:00 2001 From: deepfates Date: Fri, 16 Oct 2026 00:08:34 -0700 Subject: [PATCH] Prepare Imp 0.14.0 release Version 0.14.0 with install lines and tag links for ~> 0.14.0 and v0.14.0, the changelog's Unreleased section under 0.14.0, and release notes. 0.14.0 rather than 0.13.1: ReActV2 gains last_request_tools (#340) and finish: :submit (#343), and every plain-text ReActV2 program's system message changes (#341), as do forced submit requests and extracted histories, so what callers' models read and what hosts store changes. --- CHANGELOG.md | 2 + README.md | 6 +- RELEASE_NOTES.md | 159 ++++++++---------- docs/coming-from-dspy.md | 4 +- docs/diving-deeper/modules-and-composition.md | 2 +- docs/diving-deeper/saving-and-artifacts.md | 2 +- .../running-in-your-application.md | 2 +- docs/getting-started/setting-up.md | 4 +- docs/getting-started/where-to-go-next.md | 2 +- docs/production.md | 8 +- examples/deployment/README.md | 2 +- examples/deployment/mix.exs | 2 +- livebooks/01_real_lm_front_door.livemd | 2 +- livebooks/02_without_a_provider.livemd | 2 +- livebooks/03_evaluate_and_optimize.livemd | 2 +- livebooks/04_tools_agents_mcp_rlm.livemd | 2 +- livebooks/05_operating_imp.livemd | 4 +- mix.exs | 2 +- priv/public_api.json | 2 +- test/package_contract_test.exs | 2 +- 20 files changed, 99 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b20628f..e0187faa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ User-visible changes to Imp are recorded here. ## Unreleased +## 0.14.0 — 2026-10-16 + ### Added - ReActV2 takes `last_request_tools:`, a list of tools whose calls run in diff --git a/README.md b/README.md index 0e9e0ae6..0f1d300e 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ text or JSON you can score, such as an agent's tool descriptions. ## Install ```elixir -{:imp, "~> 0.13.0"} +{:imp, "~> 0.14.0"} ``` Imp needs Elixir 1.19 or later and a C and C++ compiler, for the native code @@ -154,7 +154,7 @@ access, because erlexec's build fetches rebar3 plugins. It reaches models throug [ReqLLM](https://hex.pm/packages/req_llm), so any provider ReqLLM supports works. -Imp 0.13 is experimental. Its API may still change, and its optimizers need +Imp 0.14 is experimental. Its API may still change, and its optimizers need large-scale benchmarking. Bug reports and pull requests are welcome. ## Learn @@ -162,7 +162,7 @@ large-scale benchmarking. Bug reports and pull requests are welcome. - [Getting started](docs/getting-started/index.md) builds one program step by step, from the first call to a supervised server, with real scores. - [Coming from DSPy](docs/coming-from-dspy.md) maps DSPy's names to Imp's. -- [Tutorials](https://github.com/deepfates/imp/tree/v0.13.0/livebooks) are Livebook notebooks +- [Tutorials](https://github.com/deepfates/imp/tree/v0.14.0/livebooks) are Livebook notebooks you can run offline or with a key. - The [cheatsheet](docs/cheatsheet.cheatmd) has the common calls on one page. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b88df94b..45a3892e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,25 +1,24 @@ -# Imp v0.13.0 +# Imp v0.14.0 Imp is a framework for typed, optimizable language-model programs on the BEAM. -This release changes what a tool loop's model reads. A ReActV2, ReAct or -Avatar history keeps each input, tool call and tool result exactly as it was, -where before anything credential-shaped in them was replaced by -`"[REDACTED]"` on every later step. A ReActV2 step whose answer is its plain -reply no longer presents that answer as a named output field. It also adds -three things a host can use: a ReActV2 call can give its own tool runners, -tool results record when they came back, and usage says whether a call's -input token count already includes the cached prompt. A caller's model -reads different requests, and a host that stores histories stores different -data, so under Imp's versioning rule this is a minor release. +This release adds two ReActV2 options a caller opts into: `last_request_tools`, +which lets an interrupted turn's last request still run named tools, and +`finish: :submit`, which ends a plain-text turn through `submit` as DSPy's +ReActV2 does. It also changes requests every ReActV2 program with one plain +text output sends: the finish line is worded differently, a forced `submit` +request no longer ends on the model's own message, and an extracted turn's +history now holds its answer. New options and a change to what callers' +models read and what hosts store make this a minor release under Imp's +versioning rule. ## Install ```elixir -{:imp, "~> 0.13.0"} +{:imp, "~> 0.14.0"} ``` -`~> 0.13.0` takes later 0.13 patch releases and nothing newer. The two-part -form, `~> 0.13`, means `>= 0.13.0 and < 1.0.0` in Mix, so `mix deps.update +`~> 0.14.0` takes later 0.14 patch releases and nothing newer. The two-part +form, `~> 0.14`, means `>= 0.14.0 and < 1.0.0` in Mix, so `mix deps.update imp` under it takes every later 0.x release, including minor releases that change what callers receive. @@ -32,83 +31,67 @@ in its release definition; see [releases that use MCP or ACP](docs/production.md#releases-that-use-mcp-or-acp). Ordinary Imp startup starts no protocol endpoint. -## Changes and upgrading from 0.12 +## Changes and upgrading from 0.13 -Change the Imp dependency to `{:imp, "~> 0.13.0"}`, run `mix deps.update imp`, -and commit `mix.lock`. No data migration is needed. +Change the Imp dependency to `{:imp, "~> 0.14.0"}`, run `mix deps.update imp`, +and commit `mix.lock`. No data migration is needed: saved programs without +the new options load with their defaults. -- **Histories keep what the model read.** `Imp.Predict.ReActV2`, - `Imp.Predict.ReAct` and `Imp.Predict.Avatar` no longer run `Imp.Redaction` - over each input, tool call and tool result as they add it to the history. - Before, a result that only contained something credential-shaped, such as - a quoted `curl -H "Authorization: Bearer ..."` or a JWT under discussion, - was replaced whole by `"[REDACTED]"`, and the model read that placeholder - on every later step instead of what the tool returned. Run events, - telemetry, traces, `Imp.inspect_history/2` and saved artifacts still redact - their own copies. Migration: a host that stores a history now stores what - the model read. Store it privately, and use `Imp.History.redact/1` or the - run's events for anything shown or shipped elsewhere. A history stored - before this release keeps its `"[REDACTED]"` strings; the original text is - not recoverable from it. -- **A plain-text ReActV2 step does not present its answer as a field.** In a - ReActV2 step with one unconstrained text output and natively held tools, - the answer is the message the model sends without a tool call. The Chat - adapter's system message no longer lists that output under "Your output - fields are:" or "The outputs to produce are:", and its agent and finish - lines no longer name it. The finish line reads "When the final answer is - ready, reply without calling a tool.", followed by the field's description - if it has one. Models had been writing the field's name into the reply as - a label, and the label became part of the answer. Parsing is unchanged, so - a reply written in markers is still read. Signatures with `submit`, - written tool calls, and the JSON and XML adapters are unchanged. A - signature with no instructions of its own still opens with the default - "Given the fields ..., produce the fields ...". Migration: a test that - compares that system message exactly expects the new text. -- **Added: a ReActV2 call can give its own tool runners.** `Imp.call(react, - %{..., tools: [tool, ...]})` uses, for that call only, the runners of the - given tools in place of the program's, as a call can already give its own - `max_iters`, `last_request_note` and `config`. Each tool must be one the - program holds, with the same name, description and schema, so the request - and its cacheable prefix are unchanged; anything else is refused before - any request with `{:error, {:invalid_react_v2_tools, message}}`. The - program value is not changed, and `with_tools/2`, the path an optimizer's - updates take, still refuses a changed runner. A host can keep state that - belongs to one call in that call's runners, so copies of one program - called at once (by an optimizer, `Imp.parallel` or evaluation) never share - it. See "One call's own tool runners" in the ReAct guide. -- **Added: tool results carry when they came back.** ReActV2 records - `returned_at` (ISO 8601, UTC) beside each tool result in the history, and - the Chat adapter passes it to a `:tool_result_renderer` as - `%{id:, name:, returned_at:}` (`nil` for a result recorded without one, - such as one in a history saved by an earlier release). Nothing is shown by - default. A host that wants the model to know the time during a tool loop - renders it there. The stamp is recorded once, so every later request - carries the same bytes and a cached prompt prefix survives. GEPA leaves - these times out of what its reflection model reads. Two runs of the same - program no longer return equal histories. -- **Added: usage says whether input includes cached tokens.** A call through - `Imp.Clients.ReqLLM`, streamed or not, carries `input_includes_cached` in - its `usage`. OpenAI-style usage, as OpenAI and OpenRouter report it, - counts cache reads inside the input tokens (`true`). Anthropic-style usage - counts them apart (`false`). The flag is ReqLLM's own answer, the one it - prices the call by, and a flag the provider's usage already carries is - kept. The ATIF export's `prompt_tokens` for an Anthropic-style call now - counts its cache reads and writes; before, it was only the tokens after - the last cache breakpoint. A caller that matches a usage map exactly sees - the new key. +- **Added: `last_request_tools`.** ReActV2 takes a list of tools whose calls + run in the last request of an interrupted turn, for a signature with one + unconstrained text output. Those calls run as any step's do, under the same + tool policy and run authorization, and are recorded in the history; the + turn then ends with the request's text as the answer. Calls to other tools + are listed in `unexecuted_tool_calls` and not run. A program that acts + through a tool and reports in text what it did can still take that action + when a turn is interrupted. Each name must be a tool the program holds; a + signature with `submit`, or `finish: :submit`, refuses the option. The + default, `[]`, changes nothing. A call may give its own list, which replaces + the program's for that call. A one-request call (`max_iters: 0`) is a last + request, so a host asking for a summary gives `last_request_tools: []`. +- **Added: `finish: :submit`.** A one-unconstrained-text-output ReActV2 turn + can end through `submit`, as DSPy's ReActV2 ends every turn, so text the + model did not mean as its answer is not published as one. A step that + writes a thought and calls no tool is followed by an ordinary step in which + the thought stays the model's own message and a user message after it says + "Your message above was not sent. To reply, call `submit` with `answer`; to + keep working, call a tool." (naming the signature's outputs). A second + thought-only step in a row, an empty step, or `max_iters` forces `submit`. + The default, `finish: :auto`, keeps the current rule. +- **Changed: the plain-text finish line.** A plain-text ReActV2 step's system + message now reads "When the final answer is ready, write it as plain text + without calling a tool." where it read "... reply without calling a + tool.", which a program holding a `reply` tool read as being about that + tool. A provider's prompt cache for those programs misses once. Migration: + a test that compares that system message exactly expects the new text. +- **Changed: a forced `submit` request no longer ends on the model's + message.** When the step before it wrote a thought and called nothing, the + request ended on an assistant turn, which Mistral and Gemini refuse. The + request now shows that thought as its last user message under its field's + marker; the history still records it as the model's step. A provider's + refusal of the named `tool_choice`, including one OpenRouter relays, now + gets the `"required"` retry and then the extractor instead of failing the + call. +- **Changed: an extracted turn's history holds its answer.** An `:extracted` + ReActV2 turn's history ends with the extracted outputs, recorded as a step + that called no tool. Replaying such a history shows the model nothing for + that step. A host that stores histories stores one more step for such + turns. +- **Changed: no requests after the deadline.** Once the process's + `Imp.Deadline` has passed, ReActV2 sends no forced `submit`, no + `"required"` retry and no extraction request; the turn is `:incomplete` + with `termination_cause: :deadline_exceeded`. +- **Fixed: a resume with no new inputs.** A ReActV2 call that resumes a held + history with no new inputs, such as `max_iters: 0` with a + `last_request_note`, and whose forced `submit` gets no `submit` back, now + gets its answer from the extractor instead of failing with + `{:missing_input_fields, [...]}`. -Rollback means restoring `0.12.3` in the lock. Histories are then redacted as -they are built again, the plain-text step lists its output field again, -`returned_at` is no longer recorded (a renderer receives `nil`), usage -loses `input_includes_cached`, and a call that passes `tools` is not given -its own runners. Provider-free tests check that -the next request carries a tool result as the tool returned it, for each of -the three loops, along with the exact system message of a plain-text step, -the time a renderer receives, a call's own runners and the refusals of -tools shown differently, and the flag and ATIF prompt count for both -usage shapes. This release does not establish how any particular model -responds to the new system message. -See the [changelog](CHANGELOG.md) for every change. +Rollback means restoring `0.13.0` in the lock. 0.13.0 loads a program +saved with `last_request_tools` or `finish: :submit` without those options, +so it runs with none and with `finish: :auto`. +This release does not establish how any particular model responds to the new +wording. See the [changelog](CHANGELOG.md) for every change. ## Known limits diff --git a/docs/coming-from-dspy.md b/docs/coming-from-dspy.md index 26ed9410..7ef5fc02 100644 --- a/docs/coming-from-dspy.md +++ b/docs/coming-from-dspy.md @@ -12,7 +12,7 @@ brought in. ## The five-minute version ```elixir -# pip install dspy -> {:imp, "~> 0.13.0"} +# pip install dspy -> {:imp, "~> 0.14.0"} # lm = dspy.LM("openai/...") -> lm = Imp.req_llm("openai:gpt-5.4-mini", api_key: ...) # dspy.Predict("q -> a") -> program = Imp.predict("q -> a", lm: lm) # program(q="...") -> {:ok, pred} = Imp.call(program, %{q: "..."}) @@ -87,7 +87,7 @@ error row too. Each model request has a receive timeout, and has no time limit of its own (an MCP tool call does, 30 seconds by default), so to bound an agent, start it with `Imp.start_run/3` and cancel it when you choose. The -[deployment example](https://github.com/deepfates/imp/blob/v0.13.0/examples/deployment/README.md) +[deployment example](https://github.com/deepfates/imp/blob/v0.14.0/examples/deployment/README.md) is a complete OTP application. **Optimizers see what you name.** DSPy finds predictors by walking a module's diff --git a/docs/diving-deeper/modules-and-composition.md b/docs/diving-deeper/modules-and-composition.md index 917a50c6..94b90204 100644 --- a/docs/diving-deeper/modules-and-composition.md +++ b/docs/diving-deeper/modules-and-composition.md @@ -149,7 +149,7 @@ A custom module is your code, so it is not saved as a whole. What an optimizer chose for it is data: `Imp.ProgramParameters.values/1` reads it, `Imp.ProgramParameters.apply_values/2` puts it on a freshly built program, and `Imp.Optimizer.Artifact` writes it to a checksummed file. The -[deployment example](https://github.com/deepfates/imp/blob/v0.13.0/examples/deployment/README.md) +[deployment example](https://github.com/deepfates/imp/blob/v0.14.0/examples/deployment/README.md) does this in a supervised application. ### Built-in variants diff --git a/docs/diving-deeper/saving-and-artifacts.md b/docs/diving-deeper/saving-and-artifacts.md index 19a8b9d7..ba3956ba 100644 --- a/docs/diving-deeper/saving-and-artifacts.md +++ b/docs/diving-deeper/saving-and-artifacts.md @@ -21,7 +21,7 @@ Save the whole program when it is made of Imp's modules: `Imp.predict/2`, when the program is your own struct implementing `Imp.Module`, or when you want the program's code to live in your release and only its tuned text to cross the persistence boundary. The -[deployment example](https://github.com/deepfates/imp/tree/v0.13.0/examples/deployment) +[deployment example](https://github.com/deepfates/imp/tree/v0.14.0/examples/deployment) does the second. ### 2. JSON with a checksum diff --git a/docs/getting-started/running-in-your-application.md b/docs/getting-started/running-in-your-application.md index 14fadf0c..c84ccb76 100644 --- a/docs/getting-started/running-in-your-application.md +++ b/docs/getting-started/running-in-your-application.md @@ -121,7 +121,7 @@ Changing models is then a configuration change, and rotating a key is a restart. The -[deployment example](https://github.com/deepfates/imp/blob/v0.13.0/examples/deployment/README.md) +[deployment example](https://github.com/deepfates/imp/blob/v0.14.0/examples/deployment/README.md) is the complete version of this page: a two-stage program like `TicketTriage`, learned parameters loaded and reloaded as an `Imp.Optimizer.Artifact`, crashed and timed-out calls contained, and the whole thing restarted in a fresh OS diff --git a/docs/getting-started/setting-up.md b/docs/getting-started/setting-up.md index 2e63c4f8..cd5f0ce6 100644 --- a/docs/getting-started/setting-up.md +++ b/docs/getting-started/setting-up.md @@ -5,7 +5,7 @@ Add Imp to a Mix project: ~~~elixir def deps do [ - {:imp, "~> 0.13.0"} + {:imp, "~> 0.14.0"} ] end ~~~ @@ -13,7 +13,7 @@ end or, for a script or a Livebook notebook: ~~~elixir -Mix.install([{:imp, "~> 0.13.0"}]) +Mix.install([{:imp, "~> 0.14.0"}]) ~~~ Imp needs Elixir 1.19 and a C and C++ compiler, for the native code in two diff --git a/docs/getting-started/where-to-go-next.md b/docs/getting-started/where-to-go-next.md index b3bc3403..39df23d1 100644 --- a/docs/getting-started/where-to-go-next.md +++ b/docs/getting-started/where-to-go-next.md @@ -51,7 +51,7 @@ The module documentation is the reference for every function. [Running Imp in production](../production.md) covers what the last page began: supervision, provider failures, runs you can observe and cancel, and telemetry. The -[deployment example](https://github.com/deepfates/imp/blob/v0.13.0/examples/deployment/README.md) +[deployment example](https://github.com/deepfates/imp/blob/v0.14.0/examples/deployment/README.md) is a complete application to copy from. ## Try it in a notebook diff --git a/docs/production.md b/docs/production.md index 23d023fd..d57ec4bb 100644 --- a/docs/production.md +++ b/docs/production.md @@ -5,16 +5,16 @@ where its credentials come from, how long a call may take and what it may cost. This page covers those decisions in the order you meet them: starting Imp, credentials, concurrency, timeouts, cost and caching, persistence and telemetry. The -[deployment example](https://github.com/deepfates/imp/tree/v0.13.0/examples/deployment) +[deployment example](https://github.com/deepfates/imp/tree/v0.14.0/examples/deployment) is a complete OTP application that puts them together. ## Imp in your supervision tree -Imp is an OTP application, and adding `{:imp, "~> 0.13.0"}` to your +Imp is an OTP application, and adding `{:imp, "~> 0.14.0"}` to your dependencies starts it with yours. It supervises its settings, its response cache and the task pools that bound its work. It opens no listener and starts no subprocess, and the MCP and ACP runtimes start only when you use -them. In a script, `Mix.install([{:imp, "~> 0.13.0"}])` starts it too. +them. In a script, `Mix.install([{:imp, "~> 0.14.0"}])` starts it too. ## Credentials at runtime @@ -263,7 +263,7 @@ standard error. ## The reference application -[`examples/deployment`](https://github.com/deepfates/imp/tree/v0.13.0/examples/deployment) +[`examples/deployment`](https://github.com/deepfates/imp/tree/v0.14.0/examples/deployment) is a small OTP application that loads a checksummed artifact at startup, reads its key from the environment, serves calls from bounded supervised tasks, answers overload and timeouts with errors instead of blocking, and reloads diff --git a/examples/deployment/README.md b/examples/deployment/README.md index 44c34c36..3622c7d2 100644 --- a/examples/deployment/README.md +++ b/examples/deployment/README.md @@ -150,4 +150,4 @@ Use a whole-program artifact for a supported portable Imp shape. Use its selected predictor parameters should cross the persistence boundary. During source development set `IMP_PATH` to the Imp checkout. Other -applications use the Hex dependency in `mix.exs`, `{:imp, "~> 0.13.0"}`. +applications use the Hex dependency in `mix.exs`, `{:imp, "~> 0.14.0"}`. diff --git a/examples/deployment/mix.exs b/examples/deployment/mix.exs index 02f78803..704b3868 100644 --- a/examples/deployment/mix.exs +++ b/examples/deployment/mix.exs @@ -11,7 +11,7 @@ defmodule ImpDeployment.MixProject do defp deps do case System.get_env("IMP_PATH") do - nil -> [{:imp, "~> 0.13.0"}] + nil -> [{:imp, "~> 0.14.0"}] path -> [{:imp, path: path}] end end diff --git a/livebooks/01_real_lm_front_door.livemd b/livebooks/01_real_lm_front_door.livemd index 77e3f39a..615b8c6c 100644 --- a/livebooks/01_real_lm_front_door.livemd +++ b/livebooks/01_real_lm_front_door.livemd @@ -7,7 +7,7 @@ imp_path = System.get_env("IMP_PATH") lockfile = imp_path && Path.join(imp_path, "mix.lock") cond do - is_nil(imp_path) -> Mix.install([{:imp, "~> 0.13.0"}]) + is_nil(imp_path) -> Mix.install([{:imp, "~> 0.14.0"}]) File.regular?(lockfile) -> Mix.install([{:imp, path: imp_path}], lockfile: lockfile) true -> Mix.install([{:imp, path: imp_path}]) end diff --git a/livebooks/02_without_a_provider.livemd b/livebooks/02_without_a_provider.livemd index 748a11d5..962e464f 100644 --- a/livebooks/02_without_a_provider.livemd +++ b/livebooks/02_without_a_provider.livemd @@ -7,7 +7,7 @@ imp_path = System.get_env("IMP_PATH") lockfile = imp_path && Path.join(imp_path, "mix.lock") cond do - is_nil(imp_path) -> Mix.install([{:imp, "~> 0.13.0"}]) + is_nil(imp_path) -> Mix.install([{:imp, "~> 0.14.0"}]) File.regular?(lockfile) -> Mix.install([{:imp, path: imp_path}], lockfile: lockfile) true -> Mix.install([{:imp, path: imp_path}]) end diff --git a/livebooks/03_evaluate_and_optimize.livemd b/livebooks/03_evaluate_and_optimize.livemd index 1a4f62f6..17682b3b 100644 --- a/livebooks/03_evaluate_and_optimize.livemd +++ b/livebooks/03_evaluate_and_optimize.livemd @@ -7,7 +7,7 @@ imp_path = System.get_env("IMP_PATH") lockfile = imp_path && Path.join(imp_path, "mix.lock") cond do - is_nil(imp_path) -> Mix.install([{:imp, "~> 0.13.0"}]) + is_nil(imp_path) -> Mix.install([{:imp, "~> 0.14.0"}]) File.regular?(lockfile) -> Mix.install([{:imp, path: imp_path}], lockfile: lockfile) true -> Mix.install([{:imp, path: imp_path}]) end diff --git a/livebooks/04_tools_agents_mcp_rlm.livemd b/livebooks/04_tools_agents_mcp_rlm.livemd index 855260a4..9284c30f 100644 --- a/livebooks/04_tools_agents_mcp_rlm.livemd +++ b/livebooks/04_tools_agents_mcp_rlm.livemd @@ -7,7 +7,7 @@ imp_path = System.get_env("IMP_PATH") lockfile = imp_path && Path.join(imp_path, "mix.lock") cond do - is_nil(imp_path) -> Mix.install([{:imp, "~> 0.13.0"}]) + is_nil(imp_path) -> Mix.install([{:imp, "~> 0.14.0"}]) File.regular?(lockfile) -> Mix.install([{:imp, path: imp_path}], lockfile: lockfile) true -> Mix.install([{:imp, path: imp_path}]) end diff --git a/livebooks/05_operating_imp.livemd b/livebooks/05_operating_imp.livemd index 05d4dd84..d9295509 100644 --- a/livebooks/05_operating_imp.livemd +++ b/livebooks/05_operating_imp.livemd @@ -7,7 +7,7 @@ imp_path = System.get_env("IMP_PATH") lockfile = imp_path && Path.join(imp_path, "mix.lock") cond do - is_nil(imp_path) -> Mix.install([{:imp, "~> 0.13.0"}]) + is_nil(imp_path) -> Mix.install([{:imp, "~> 0.14.0"}]) File.regular?(lockfile) -> Mix.install([{:imp, path: imp_path}], lockfile: lockfile) true -> Mix.install([{:imp, path: imp_path}]) end @@ -103,7 +103,7 @@ Enum.each(busy, &Task.await/1) refused ``` -The [deployment example](https://github.com/deepfates/imp/tree/v0.13.0/examples/deployment) +The [deployment example](https://github.com/deepfates/imp/tree/v0.14.0/examples/deployment) wraps the same pattern in a `ProgramServer` that also reloads parameters while serving. diff --git a/mix.exs b/mix.exs index f7de42ee..33b1d9c0 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Imp.MixProject do use Mix.Project - @version "0.13.0" + @version "0.14.0" def project do [ diff --git a/priv/public_api.json b/priv/public_api.json index 99521030..1fd3096a 100644 --- a/priv/public_api.json +++ b/priv/public_api.json @@ -10357,7 +10357,7 @@ "types": [] } ], - "package_version": "0.13.0", + "package_version": "0.14.0", "schema_version": 3, "scope": "Curated Imp API compiled from package-shipped sources. Exports come from non-hidden documentation entries; callbacks, types, and struct fields are category- and policy-gated." } diff --git a/test/package_contract_test.exs b/test/package_contract_test.exs index 4b266564..93fcecee 100644 --- a/test/package_contract_test.exs +++ b/test/package_contract_test.exs @@ -114,7 +114,7 @@ defmodule PackageContractTest do version = Mix.Project.config()[:version] dependency = hex_dependency(version) - assert version == "0.13.0" + assert version == "0.14.0" assert File.read!("RELEASE_NOTES.md") =~ "# Imp v#{version}" assert File.read!("CHANGELOG.md") =~ "## #{version}" assert File.read!("examples/deployment/mix.exs") =~ dependency