Imp 05: Operate And Live Checks
imp_checkout? = fn path ->
is_binary(path) and File.regular?(Path.join(path, "mix.exs")) and
File.regular?(Path.join(path, "lib/imp.ex"))
end
explicit_repo = System.get_env("IMP_PATH")
if explicit_repo && not imp_checkout?.(Path.expand(explicit_repo)) do
raise "IMP_PATH does not point to an Imp source checkout or unpacked package"
end
repo =
[explicit_repo, Path.expand("..", __DIR__), File.cwd!()]
|> Enum.reject(&is_nil/1)
|> Enum.map(&Path.expand/1)
|> Enum.find(imp_checkout?)
if repo do
# Prefer the notebook's own Imp checkout even when Livebook was launched
# from an unrelated Mix project. Unpacked package archives may omit
# mix.lock, so pin it only when the source checkout actually provides it.
install_opts =
if File.regular?(Path.join(repo, "mix.lock")),
do: [lockfile: Path.join(repo, "mix.lock")],
else: []
Mix.install([{:imp, path: repo}], install_opts)
else
# Standalone notebook: install the tagged Git source release.
Mix.install([{:imp, github: "deepfates/imp", tag: "v0.4.0"}])
end
live_provider_enabled? = System.get_env("LIVE_PROVIDER") == "1"
Operational boundaries
The earlier notebooks built Imp programs. This chapter is about the choices an application developer must make before putting provider calls in production: credentials, timeouts, retries, redaction, concurrency, cost limits, and failure behavior.
Application Checklist
Before swapping a useful deterministic program to a live provider, decide the host application's operational boundaries:
[
runtime_config: [:model_name, :api_key, :timeout, :temperature],
tests: [:static_lm_unit_tests, :opt_in_live_smoke],
safety: [:redaction, :tool_policy, :provider_failure_behavior],
operations: [:telemetry, :cost_limits, :rate_limits, :rollout_plan]
]
Security Posture
Unknown external keys remain strings:
key = "external_key_#{System.unique_integer([:positive])}"
example = Imp.example(%{key => "value"})
{
Imp.get(example, key),
try do
String.to_existing_atom(key)
rescue
ArgumentError -> :not_interned
end
}
Trace redaction — secret-shaped values in tool traffic are replaced before any event or log leaves the boundary:
echo = Imp.tool(:echo, "echo", fn input -> input end)
trace =
Imp.trace(fn ->
Imp.Tool.call(echo, %{api_key: "sk-live", nested: %{token: "secret"}})
end)
Enum.map(trace.events, fn {name, _measurements, metadata} -> {name, metadata} end)
Optional Live Provider
This cell requires LIVE_PROVIDER=1, OPENAI_API_KEY, and OPENAI_MODEL in
your environment. Do not paste secrets into the notebook.
if live_provider_enabled? && System.get_env("OPENAI_API_KEY") && System.get_env("OPENAI_MODEL") do
model = System.fetch_env!("OPENAI_MODEL")
lm =
Imp.req_llm("openai:#{model}",
api_key: System.fetch_env!("OPENAI_API_KEY"),
temperature: 0,
max_completion_tokens: 40
)
program = Imp.predict("question -> answer", lm: lm)
Imp.call(program, %{question: "Reply with exactly: pong"})
else
{:skip, "Set LIVE_PROVIDER=1, OPENAI_API_KEY, and OPENAI_MODEL before running the live provider cell."}
end
Live application probe
The next cell is the consumer-facing live probe. It runs only when the three explicit environment variables above are present and otherwise stays provider-free.
Exercise The Live Runtime
This cell validates the same live provider path and asserts the expected output when credentials are present.
if live_provider_enabled? && System.get_env("OPENAI_API_KEY") && System.get_env("OPENAI_MODEL") do
model = System.fetch_env!("OPENAI_MODEL")
lm =
Imp.req_llm("openai:#{model}",
api_key: System.fetch_env!("OPENAI_API_KEY"),
temperature: 0,
max_completion_tokens: 40
)
program = Imp.predict("question -> answer", lm: lm)
{:ok, prediction} = Imp.call(program, %{question: "Reply with exactly: pong"})
answer = prediction |> Imp.get(:answer, "") |> to_string() |> String.downcase()
unless String.contains?(answer, "pong") do
raise "live runtime returned an invalid result: #{inspect(Imp.to_map(prediction))}"
end
Imp.to_map(prediction)
else
{:skip, "Set LIVE_PROVIDER=1, OPENAI_API_KEY, and OPENAI_MODEL before running the live runtime cell."}
end
Saving Without Secrets
lm = Imp.req_llm("openai:gpt-test", api_key: "not-persisted", temperature: 0)
program = Imp.predict("question -> answer", lm: lm)
path = Path.join(System.tmp_dir!(), "imp-no-secret.json")
Imp.save!(program, path)
state = File.read!(path)
loaded = Imp.load!(path)
File.rm(path)
{
String.contains?(state, "not-persisted"),
Keyword.has_key?(loaded.lm.opts, :api_key),
loaded.lm
}
Canonical Deployment Reference
For a production application, use
examples/deployment. It is the canonical
Imp deployment path: a supervised application loads a checksummed artifact,
rebinds credentials from the environment, and runs provider calls through
bounded workers. The static answer setting in that reference is only a smoke
mode; production uses IMP_MODEL and IMP_API_KEY.