Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
# defensive clause/guard: ReqLLM.Response types `usage` as map() on the
# struct, but its schema defaults the field to nil and Response.usage/1 is
# `map() | nil`, so the nil clause is reachable at runtime.
{"lib/imp/clients/req_llm.ex", :guard_fail, 1357},
{"lib/imp/clients/req_llm.ex", :pattern_match_cov, {1385, 8}},
{"lib/imp/clients/req_llm.ex", :guard_fail, 1414},
{"lib/imp/clients/req_llm.ex", :pattern_match_cov, {1442, 8}},
{"lib/imp/clients/req_llm.ex", :pattern_match_cov, {147, 7}},
# defensive error clause on an always-ok internal call
{"lib/imp/clients/training.ex", :pattern_match, {1215, 13}},
Expand Down Expand Up @@ -116,9 +116,6 @@
{"lib/mix/tasks/imp.benchmark.parity.ex", :pattern_match, {715, 11}},
# raise-only helper: invalid_snapshot!/2 exists to Mix.raise
{"lib/mix/tasks/imp.public_api.ex", :no_return, {838, 8}},
# dependency code: this file ships inside the req_llm package, not this
# repo; LLMDB.Model.t/0 is a Zoi-generated spec dialyzer cannot see
{"lib/req_llm.ex", :unknown_type, {109, 24}},

# --- Surfaced 2026-08-08 during ignore-file regeneration (imp-fkwy): 583
# commits landed without CI, and these warnings accumulated unpinned.
Expand Down Expand Up @@ -221,7 +218,7 @@

# Defensive fallbacks and MapSet opacity retained at the 0.3 cut. These are
# individually pinned so a changed success type makes the gate ask again.
{"bench/imp/benchmark_truth/multimodal_runner.ex", :pattern_match_cov, {341, 16}},
{"bench/imp/benchmark_truth/multimodal_runner.ex", :pattern_match_cov, {340, 16}},
{"lib/imp/adapter/chat.ex", :pattern_match_cov, {774, 8}},
{"lib/imp/adapter/xml.ex", :pattern_match_cov, {675, 8}},
{"lib/imp/mcp.ex", :pattern_match_cov, {372, 8}},
Expand Down
55 changes: 34 additions & 21 deletions bench/imp/benchmark_truth/multimodal_manifest.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,16 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
@moduledoc false

@payload_keys ~w(assets campaign_id claim_policy created_at limitations provider samples schema_version scoring signature)
@provider_keys ~w(api capabilities credential_env endpoint generation identity_evidence model name pricing profile req_llm_dependency req_llm_model)
@provider_keys ~w(api capabilities credential_env endpoint generation identity_evidence model name pricing profile req_llm_model)
@required_generation_keys ~w(max_tokens timeout_ms)
@optional_generation_keys ~w(seed temperature top_p)
@pricing_keys ~w(as_of cached_input_nano_usd_per_token cached_input_usd_per_1m currency input_nano_usd_per_token input_usd_per_1m output_nano_usd_per_token output_usd_per_1m pricing_basis source)
@req_llm_dependency_keys ~w(package package_sha256 repository source source_revision version)
@signature_keys ~w(input output output_schema prompt_contract)
@scoring_keys ~w(family_thresholds normalization scorer)
@claim_keys ~w(document_family image_family required_families)
@asset_keys ~w(bytes mime_type path sha256)
@sample_keys ~w(asset_ids delivery expected_capability family gold id prompt)
@deliveries ~w(typed_image_data_uri typed_native_file)
@req_llm_dependency %{
"package" => "req_llm",
"package_sha256" => "266c0e06c47b4562f243dcdf41332342cbed2ec37064750edd725fb66bb6e914",
"repository" => "https://github.com/agentjido/req_llm",
"source" => "hexpm",
"source_revision" => "33840077c2f1332eb6dff2d268dff02393014da4",
"version" => "1.17.1"
}
@provider_profiles %{
"google-gemini-2.5-flash-generate-content" => %{
"api" => "generateContent",
Expand All @@ -43,7 +34,6 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
"pricing_basis" => "standard_text_image_video",
"source" => "https://ai.google.dev/gemini-api/docs/pricing"
},
"req_llm_dependency" => @req_llm_dependency,
"req_llm_model" => "google:gemini-2.5-flash"
},
"openai-gpt-4.1-mini-2025-04-14-responses" => %{
Expand All @@ -66,7 +56,6 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
"pricing_basis" => "standard",
"source" => "https://developers.openai.com/api/docs/models/gpt-4.1-mini"
},
"req_llm_dependency" => @req_llm_dependency,
"req_llm_model" => "openai:gpt-4.1-mini-2025-04-14"
}
}
Expand All @@ -93,7 +82,7 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
root = Keyword.get(opts, :root, File.cwd!()) |> Path.expand()
exact_keys!(payload, @payload_keys, "manifest payload")

require_equal!(payload["schema_version"], 2, "schema_version")
require_equal!(payload["schema_version"], 3, "schema_version")
require_string!(payload["campaign_id"], "campaign_id")
require_string!(payload["created_at"], "created_at")

Expand Down Expand Up @@ -144,17 +133,44 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
end)
end

def runtime_dependency!(payload) when is_map(payload) do
dependency = payload["provider"]["req_llm_dependency"]
@doc """
Binds the loaded ReqLLM package into the manifest's provider, so the
checkpoint identity, request audits and artifact record the dependency that
actually serializes and sends each request. A checkpoint written under one
ReqLLM package cannot resume under another.
"""
def bind_runtime_dependency!(%{payload: payload} = manifest) do
%{
manifest
| payload: put_in(payload, ["provider", "req_llm_dependency"], runtime_dependency!())
}
end

runtime_version =
@doc """
The loaded ReqLLM package: its version and the Hex package checksum from the
project's lock. Raises when nothing is loaded or when the loaded version is
not the locked one.
"""
def runtime_dependency! do
loaded =
case Application.spec(:req_llm, :vsn) do
nil -> raise ArgumentError, "ReqLLM runtime dependency is not loaded"
version -> to_string(version)
end

require_equal!(runtime_version, dependency["version"], "ReqLLM runtime version")
dependency
case Mix.Dep.Lock.read()[:req_llm] do
{:hex, :req_llm, ^loaded, package_sha256, _managers, _deps, "hexpm", _outer} ->
%{
"package" => "req_llm",
"package_sha256" => package_sha256,
"source" => "hexpm",
"version" => loaded
}

locked ->
raise ArgumentError,
"loaded ReqLLM #{loaded} is not the Hex package locked in mix.lock: #{inspect(locked)}"
end
end

def profiles, do: Map.keys(@provider_profiles) |> Enum.sort()
Expand Down Expand Up @@ -217,9 +233,6 @@ defmodule Imp.BenchmarkTruth.MultimodalManifest do
require_string!(pricing[key], "pricing.#{key}")
end
)

exact_keys!(provider["req_llm_dependency"], @req_llm_dependency_keys, "req_llm_dependency")
require_equal!(provider["req_llm_dependency"], @req_llm_dependency, "req_llm_dependency")
end

defp validate_signature!(signature) do
Expand Down
3 changes: 1 addition & 2 deletions bench/imp/benchmark_truth/multimodal_runner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ defmodule Imp.BenchmarkTruth.MultimodalRunner do

root = Keyword.get(opts, :root, File.cwd!()) |> Path.expand()
manifest_path = Keyword.get(opts, :manifest, Path.join(root, @default_manifest))
manifest = Manifest.load!(manifest_path, root: root)
Manifest.runtime_dependency!(manifest.payload)
manifest = manifest_path |> Manifest.load!(root: root) |> Manifest.bind_runtime_dependency!()
max_concurrency = validate_concurrency!(Keyword.get(opts, :max_concurrency, 2))

case mode do
Expand Down
11 changes: 5 additions & 6 deletions bench/imp/benchmark_truth/optimize_anything/campaign.ex
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,11 @@ defmodule Imp.BenchmarkTruth.OptimizeAnything.Campaign do
do: raise(ArgumentError, "campaign options must be a keyword list, got: #{inspect(opts)}")

@doc false
def handle_usage(_event, _measurements, _metadata, {_agent, owner})
when owner != self(),
do: :ok

def handle_usage(event, measurements, metadata, {agent, _owner}),
do: handle_usage(event, measurements, metadata, agent)
def handle_usage(event, measurements, metadata, {agent, owner}) when is_pid(owner) do
if Imp.Telemetry.emitted_for?(owner),
do: handle_usage(event, measurements, metadata, agent),
else: :ok
end

def handle_usage(_event, measurements, _metadata, agent) do
Agent.update(agent, fn audit ->
Expand Down
10 changes: 5 additions & 5 deletions benchmarks/authorities.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@
"req_llm": {
"role": "beam_runtime_dependency",
"repository": "https://github.com/agentjido/req_llm",
"version": "1.17.1",
"git_ref": "refs/tags/v1.17.1",
"commit": "33840077c2f1332eb6dff2d268dff02393014da4",
"version": "1.24.0",
"git_ref": "refs/tags/v1.24.0",
"commit": "fd9e079fddf253e9b719b2d2c6920f4306592809",
"source_hashes": {
"hex_package": "266c0e06c47b4562f243dcdf41332342cbed2ec37064750edd725fb66bb6e914",
"hex_registry": "169d77a77bac5cee7655a7a9158ebea1c2a7857670f4104b29516a25a2d24f1e"
"hex_package": "cdc5c5cd7f38c0e17cf7a949ced99b6760dcba0d860cd4d066fea1aeba422929",
"hex_registry": "8ab6bda68e28afc3adf070cc6616d51831b42b8ff144116a9f104999af4c763f"
}
}
},
Expand Down
12 changes: 2 additions & 10 deletions benchmarks/data/multimodal/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,6 @@
"source": "https://ai.google.dev/gemini-api/docs/pricing"
},
"profile": "google-gemini-2.5-flash-generate-content",
"req_llm_dependency": {
"package": "req_llm",
"package_sha256": "266c0e06c47b4562f243dcdf41332342cbed2ec37064750edd725fb66bb6e914",
"repository": "https://github.com/agentjido/req_llm",
"source": "hexpm",
"source_revision": "33840077c2f1332eb6dff2d268dff02393014da4",
"version": "1.17.1"
},
"req_llm_model": "google:gemini-2.5-flash"
},
"samples": [
Expand Down Expand Up @@ -159,7 +151,7 @@
"prompt": "Use both pages of the attached synthetic PDF. Among projects with review code R7 on page 2, which owner on page 1 has the highest Units value? Return exactly one JSON object with one field and no markdown: {\"answer\": \"owner\"}"
}
],
"schema_version": 2,
"schema_version": 3,
"scoring": {
"family_thresholds": {
"image": 0.75,
Expand All @@ -180,5 +172,5 @@
"prompt_contract": "One pinned attachment followed by one pinned question; return only a single-field JSON object named answer."
}
},
"payload_sha256": "4b4c80497789d74dec60b2b26236f6eee2f1f9b29046f07ef95b3fa3faf8e50f"
"payload_sha256": "54bf6a6ca6bc66c42f927387409c5bc0ab6010a8b7b1c1fc7ef67cbbae0b930e"
}
12 changes: 2 additions & 10 deletions benchmarks/data/multimodal/openai-responses-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@
"source": "https://developers.openai.com/api/docs/models/gpt-4.1-mini"
},
"profile": "openai-gpt-4.1-mini-2025-04-14-responses",
"req_llm_dependency": {
"package": "req_llm",
"package_sha256": "266c0e06c47b4562f243dcdf41332342cbed2ec37064750edd725fb66bb6e914",
"repository": "https://github.com/agentjido/req_llm",
"source": "hexpm",
"source_revision": "33840077c2f1332eb6dff2d268dff02393014da4",
"version": "1.17.1"
},
"req_llm_model": "openai:gpt-4.1-mini-2025-04-14"
},
"samples": [
Expand Down Expand Up @@ -157,7 +149,7 @@
"prompt": "Use both pages of the attached synthetic PDF. Among projects with review code R7 on page 2, which owner on page 1 has the highest Units value? Return exactly one JSON object with one field and no markdown: {\"answer\": \"owner\"}"
}
],
"schema_version": 2,
"schema_version": 3,
"scoring": {
"family_thresholds": {
"image": 0.75,
Expand All @@ -178,5 +170,5 @@
"prompt_contract": "One pinned attachment followed by one pinned question; return only a single-field JSON object named answer."
}
},
"payload_sha256": "04daa155d3f97edfff62e329dfdca1248855f22b2271f7e954228432f1ae39d8"
"payload_sha256": "7e0f46b93d76a0f1703e6edce0276436ac686fc5dd2ad57a0e7a9826776e3a09"
}
10 changes: 7 additions & 3 deletions docs/differentials/MULTIMODAL_FIDELITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@ The provider manifests are:

Their strict, checksummed schema pins every sample ID, prompt, expected output,
family, delivery mode, asset byte count, MIME type, asset SHA-256, provider,
endpoint, API, exact model, generation options, ReqLLM dependency, and pricing.
Runtime ReqLLM version drift fails before dispatch.
endpoint, API, exact model, generation options, and pricing. The ReqLLM
dependency is not part of the manifest: the runner reads the loaded ReqLLM
version and its Hex package checksum from `mix.lock`, refuses to run when the
two disagree, and binds that dependency into the checkpoint identity, the
request audits and the artifact. A checkpoint cannot resume under a different
ReqLLM package.

All assets are synthetic and repository-owned. Images cover shape counting,
spatial relation, and OCR. The native-document family sends the original
Expand All @@ -57,7 +61,7 @@ observed. For every request, the redacted audit contains:
- sanitized endpoint, API, HTTP method, serialized model, and body SHA-256;
- ordered serialized part types;
- each part's MIME type, decoded byte count, and content SHA-256;
- ReqLLM package source, version, package hash, repository, and source revision;
- ReqLLM package source, version, and package hash;
- ReqLLM request ID and detected transport.

The audit never persists data URIs, base64 payloads, file bytes, prompt text, or
Expand Down
2 changes: 1 addition & 1 deletion docs/differentials/RESEARCH_LANDSCAPE.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ semantics, or produces useful held-out improvement.
| [Ax](https://github.com/ax-llm/ax) | Strongest independent implementation comparator for a typed TypeScript interpretation of DSPy-style programming. | Current product-semantic audit: npm `24.0.4`, registry `gitHead` `a366e49759bd596c8217eca91dfdc9dd8382835d`. Historical executable differential: `23.0.0` at `eb5835e54ba0c5b2fbac380daed1cb87faeefd5e`. Use for API and behavioral comparison, not as scientific authority. |
| [BAML](https://github.com/BoundaryML/baml) | Comparator for compiler diagnostics, generated typed clients, and partial structured streaming. | Study its contracts; do not add a separate Imp language unless Elixir modules and macros are demonstrably insufficient. |
| [AdalFlow](https://github.com/SylphAI-Inc/AdalFlow), [TextGrad](https://github.com/zou-group/textgrad), and [SAMMO](https://github.com/microsoft/sammo) | Comparators for explicit parameter graphs, textual feedback, and structure-aware prompt transformations. | Borrow mechanisms only after pinning code and paper protocols independently. |
| [ReqLLM](https://github.com/agentjido/req_llm) | Preferred BEAM provider substrate. | Release `v1.17.1` resolves to `33840077c2f1332eb6dff2d268dff02393014da4`. Integrate its provider, multimodal, tool, stream, usage, error, and telemetry contracts instead of rebuilding them. |
| [ReqLLM](https://github.com/agentjido/req_llm) | Preferred BEAM provider substrate. | Release `v1.24.0` resolves to `fd9e079fddf253e9b719b2d2c6920f4306592809`. Integrate its provider, multimodal, tool, stream, usage, error, and telemetry contracts instead of rebuilding them. |
| [Jido](https://github.com/agentjido/jido) and [Jido AI](https://github.com/agentjido/jido_ai) | Optional deployment and long-running-agent complements. | Study immutable state, explicit effects, supervision, and signals without making their agent model mandatory. |
| [LangGraph](https://github.com/langchain-ai/langgraph), [Pydantic AI](https://github.com/pydantic/pydantic-ai), [MLflow](https://mlflow.org/docs/latest/genai/prompt-registry/optimize-prompts), and [Promptfoo](https://github.com/promptfoo/promptfoo) | Production references for checkpoints, durable execution, registries, eval matrices, and adversarial testing. | Treat as operational comparators, not optimizer parity authorities. |

Expand Down
Loading
Loading