Calling rietx from a program

Two calls carry the whole integration surface. capabilities() says what this build can do; agent.refine_json does it.

For agents

This chapter is the machine-facing half of the package, and every shape in it was chosen for a caller that branches on a field rather than one that reads a sentence. You can read all of it from a REPL, and capabilities() is the fastest way to answer “did my jax extra take?”, but that is not what it is for.

refine_json: one call, five tasks

agent.refine_json takes a dict and returns a dict. It never raises and never returns a traceback:

from rietx import agent

envelope = agent.refine_json({"task": "capabilities-probe-is-not-a-task"})
envelope["ok"], envelope["error"]["code"]

Success is {"ok": true, …} with exactly one of result, series, indexing or suggestion set, so a consumer branches on the arm that arrived.

task

Does

Answers in

refine

fits one pattern

result

refine_multi

fits N patterns as one joint residual

result

refine_sequential

chains N patterns by warm start

series

index

determines a unit cell from peaks or a pattern

indexing

suggest

ranks held parameters by predicted Δχ², no solve, no mutation

suggestion

The four arms are separate because they are different shapes. For indexing the shape is the rule: the serialized answer carries no cell key, because a powder pattern does not measure one cell. It measures a ranked set of candidates, and a singleton would be a confident guess.

Failure is {"ok": false, "error": {code, message, suggestion, details}}. That is the grammar of a Diagnostic, so a consumer keeps one vocabulary for “the fit warns” and “the call failed”. Three codes, closed: INVALID_REQUEST (with per-field dot-paths in details), BACKEND_UNAVAILABLE (a valid backend name whose optional dependency is not installed here), and REFINEMENT_FAILED.

Two companions ride beside whichever arm arrived, rather than being arms themselves:

  • evidence — the answer projected for a reasoning consumer.

  • trajectory — the report at every stage boundary, off by default; ask with report_trajectory: true for a run you will read whole. A converged report is routinely the least informative one in the run. A plan absorbs an error it cannot free into whatever it can, then arrives converged with nothing to suggest, while its own first stage named the cause. Each rung’s actions are the ones the plan you ran will not fix. The default was measured, not assumed: two eval rounds found consumers handed the rungs unasked decided no better at more calls, so both halves of the surface now default off (Refinement.fit(stage_reports=True) is the library spelling, off because fit is called in loops).

Registering rietx as a tool

agent.tool_definition returns a ready-to-register definition — name, description, input_schema. agent.request_schema and agent.response_schema are the JSON Schemas alone.

from rietx import agent

definition = agent.tool_definition()
sorted(definition)
agent.request_schema()["$defs"] is not None

The vocabularies inside that schema are quoted from the live registries. The backend, solver, plan and indexing-engine names come from the same tuples the package dispatches on, and a meta-test fails when a registered member is missing from the exported schema. A third engine cannot ship invisible.

For agents

That description is the first thing a calling agent reads about this package, before any schema, any result and any part of this manual. It therefore carries the two rules agents get wrong most often: read the diagnostics before the statistics, and read the whole trajectory rather than only the final report.

It also points at docs/AGENT_PROTOCOL.md by repository-relative path, and a pip install gets the package without the docs/ tree. Until that is resolved at release, put the protocol into your agent’s context yourself, from the copy in the repository.

capabilities()

One call answers what this build supports, and every arm is quoted from a live registry rather than typed:

from rietx import capabilities

caps = capabilities()
[plan.name for plan in caps.plans]
[engine.name for engine in caps.indexing_engines]
sorted(caps.features)
  • Capabilities.backends, Capabilities.solvers, Capabilities.modes, Capabilities.anodes — the dispatch vocabularies. An AnodeCapability carries its own AnodeCapability.wavelengths and AnodeCapability.kbeta.

  • Capabilities.plans — each PlanCapability with PlanCapability.title, PlanCapability.description, PlanCapability.modes and PlanCapability.when_to_use, so a program can offer the choice in its own UI without hard-coding a list. PLAN_INFO is the same table in the library.

  • Capabilities.reader_formats — every pattern format read_pattern opens. Each ReaderCapability carries its own ReaderCapability.sniff (how the file is recognised), ReaderCapability.sigma (where the uncertainties come from, which differs per vendor) and ReaderCapability.refuses (what it declines, and why). Capabilities.reader_options documents scan=, block= and the rest.

  • Capabilities.indexing_engines and Capabilities.search_presets, with SearchPresetCapability.typical_seconds and SearchPresetCapability.total_budget_seconds. An indexing search is budgeted, and a caller that has to promise a response time reads it here.

  • Capabilities.features — feature flags, each derived from the thing it reports (a schema field’s presence, a top-level export’s existence) rather than written as a literal true. A flag flips by itself when its feature lands.

Quote this call rather than transcribing its contents. The reader-format list went from five to ten in two days once, and a table in prose would have been wrong by the following week.

Versioned contracts

Capabilities reports six version strings. They are separate because they move independently:

Field

Versions

Capabilities.schema_version

the pydantic schemas — the model, the pattern, the result

Capabilities.report_thresholds_version

the FitReport gates and their thresholds

Capabilities.event_schema_version

the streaming event ladder

Capabilities.project_format_version

the .rex project directory

Capabilities.textdoc_format_version

the .rxt text document

Capabilities.indexing_thresholds_version

the indexing gates, caveat and grade vocabularies

Capabilities.package_version is the seventh string, and the only one that moves on every release. Store the contract versions alongside any result you store: a threshold compared across two report_thresholds_version values compares two different questions.

Further reading: the agent protocol

This chapter describes the surface. docs/AGENT_PROTOCOL.md covers the half an integrator cannot derive from a schema: the turn-on order, the degeneracies to memorise, what to check before believing a number, how to read an abstention, and the measured findings that should change what a calling agent does.