API reference¶
Hand-curated reference for the public Python API. For the stability contract and guidance on which symbols you should depend on, see Python API.
This page documents the symbols exported from amx.core.__all__. The canonical signatures
live in the AMX repository;
this page mirrors them with prose explanations.
amx.__version__¶
The installed AMX version. Useful for runtime feature checks and bug reports.
amx.init¶
Convenience wrapper around AMXApplication.load(config_path). Use it for one-line scripts:
import amx
app = amx.init() # loads ~/.amx/config.yml
app = amx.init("/path/to/team.yml") # custom config
Library code should prefer from amx.core import AMXApplication and call
AMXApplication.load(...) directly — same effect, no top-level import surprise.
amx.core.AMXApplication¶
@dataclass
class AMXApplication:
config: AMXConfig
catalog: SearchCatalog
store: SQLiteHistoryStore | None = None
The composable runtime that owns a config, a search catalog, and (optionally) the local
SQLite history store. Build it via AMXApplication.load(...) for the typical case;
constructing it directly is supported for tests and dependency injection.
AMXApplication.load¶
Loads config.yml (default ~/.amx/config.yml), initialises the local SQLite history
store, and constructs the search catalog. This is the standard entry point.
from amx.core import AMXApplication
app = AMXApplication.load()
print(app.config.active_db_profile) # name of active DB profile
AMXApplication.state¶
Returns a StateManager bound to this application's config,
history store, and active DB profile namespace. Use it for write-through config and
session-state mutations.
AMXApplication.ask¶
Run a single-shot ask question through the legacy SearchService pipeline.
SearchAnswer is the same shape used internally by /ask. Prefer ask_with_tools for
new code — it returns the richer ToolAskResponse with the full reasoning trace.
AMXApplication.ask_with_tools¶
Run the question through the loop-based ask agent. Returns a structured response with
the answer, intent, tool trace, and confidence — see ToolAskResponse.
response = app.ask_with_tools("which tables in sap_s6p store dates?")
print(response.answer)
for step in response.trace:
print(step.action, "→", step.observation)
AMXApplication.explain¶
Lower-level: returns the planner's reasoning + retrieval plan for a question without producing a final answer. Useful for debugging prompts.
AMXApplication.run_analysis¶
def run_analysis(
self,
scope: dict[str, list[str]] | None = None,
*,
apply: bool = False,
) -> dict[str, Any]
Headless-safe analysis entry point. Does not open interactive prompts — when no
explicit scope or saved selection exists, returns a structured skipped result.
For full inference + writeback, prefer infer_table_metadata
or the CLI /run.
result = app.run_analysis(scope={"sap_s6p": ["t001", "vbak"]}, apply=False)
print(result["status"]) # "planned" or "skipped"
print(result["scope"])
amx.core.infer_table_metadata¶
def infer_table_metadata(
cfg: AMXConfig,
schema: str,
table: str,
*,
include_rag: bool = True,
include_codebase: bool = False,
) -> list[dict[str, Any]]
One-call programmatic metadata inference for a single table. Skips the interactive review wizard — returns suggestion dicts ready for your own UI to consume.
import amx
from amx.core import infer_table_metadata
app = amx.init()
results = infer_table_metadata(
app.config,
schema="sap_s6p",
table="t001",
include_rag=True,
include_codebase=True,
)
for col in results:
print(f"{col['column']:30s} {col['confidence']:8s} {col['description']}")
Each result dict carries the column identifier, top description, alternatives, confidence band, logprob (when available), evidence sources, and provenance. The shape is stable across minor versions; new optional fields may be added.
If include_rag=True and the active doc profile has ingested documents, the RAG agent
contributes evidence. If include_codebase=True and a code profile is active, the Code
agent does the same. Both default to off-the-network behaviour when their stores are
empty (no LLM call, no error).
amx.core.AskToolbox¶
class AskToolbox:
def __init__(
self,
cfg: AMXConfig,
catalog: SearchCatalog,
*,
db_factory: Callable[[], DatabaseConnector] | None = None,
doc_query: Callable[[str, int], list[dict[str, Any]]] | None = None,
) -> None
Bounded set of metadata tools the loop-based ask agent can call. The tools include catalog lookups, schema exploration, safe live DB probes, and (when configured) a document-query hook.
You typically don't construct an AskToolbox directly — use AMXApplication.ask_with_tools
which builds one for you. Construct it manually only when you want to inject custom
db_factory or doc_query implementations (e.g. for tests).
from amx.core import AMXApplication, AskToolbox, LoopBasedAskAgent
app = AMXApplication.load()
toolbox = AskToolbox(app.config, app.catalog)
agent = LoopBasedAskAgent(toolbox)
response = agent.answer("which tables in sap_s6p store dates?")
amx.core.LoopBasedAskAgent¶
class LoopBasedAskAgent:
def __init__(self, toolbox: AskToolbox) -> None: ...
def answer(self, question: str) -> ToolAskResponse: ...
Headless re-implementation of /ask for scripts and notebooks. Wraps the multi-step
Search Agent pipeline (interpret → plan → retrieve → verify → synthesise) in a single
answer(question) call.
amx.core.ToolAskResponse¶
@dataclass(frozen=True)
class ToolAskResponse:
question: str
answer: str
trace: list[ReasoningTraceStep]
tool_results: list[ToolResult]
strategy: str = ""
def as_dict(self) -> dict[str, Any]
Structured response from LoopBasedAskAgent.answer(...) (and from
AMXApplication.ask_with_tools).
| Field | Description |
|---|---|
question |
The original question, echoed |
answer |
The synthesised natural-language answer |
trace |
Ordered ReasoningTraceStep objects: step, action, observation |
tool_results |
Raw ToolResult objects from each tool invocation: tool, query, rows, error |
strategy |
Picked answer shape (single_fact, short_table, full_table, ranked_list, table_summary, join_candidates, prose) |
as_dict() returns a JSON-safe dict for logging or transport.
ReasoningTraceStep and ToolResult are part of the ToolAskResponse shape and
therefore implicitly public — additive field changes only across minor versions.
amx.core.AbstractEntity¶
@dataclass(frozen=True)
class AbstractEntity:
entity_id: str
kind: str
lexical: LexicalSignal
structural: StructuralSignal
statistical: StatisticalSignal
semantic: SemanticSignal
provenance: tuple[str, ...] = ()
@property
def path(self) -> str # convenience: lexical.path
Backend-neutral entity abstraction used by the Universal Metadata Interface.
Every column or table profiled by an AMX adapter is normalised into an AbstractEntity
before reaching the agents.
The four sub-signals (LexicalSignal, StructuralSignal, StatisticalSignal,
SemanticSignal) are part of the AbstractEntity shape — implicitly public, additive
field changes only across minor versions.
| Sub-signal | Carries |
|---|---|
LexicalSignal |
name, path, aliases — the technical labels |
StructuralSignal |
dtype, nullable, asset_kind, primary_key, foreign_keys, referenced_by — shape and relationship facts |
StatisticalSignal |
row_count, null_count, distinct_count, cardinality_ratio, min_value, max_value, samples — profiled distribution facts |
SemanticSignal |
description, documentation, source, confidence — human-authored or model-derived semantic evidence |
amx.core.UniversalMetadataAdapter¶
class UniversalMetadataAdapter:
@staticmethod
def from_table_profile(profile: TableProfile) -> list[AbstractEntity]
Maps backend-specific column / table profiles into AbstractEntity instances. Returns one
AbstractEntity for the table itself plus one per column.
from amx.core import AMXApplication, UniversalMetadataAdapter
app = AMXApplication.load()
# (TableProfile is internal; in practice, AMXApplication.run_analysis or
# infer_table_metadata yield AbstractEntity objects already.)
In normal use, you don't call UniversalMetadataAdapter directly — the orchestrator
applies it internally. It's part of the public surface so external integrations (e.g. a
custom metadata UI) can produce the same canonical shape.
amx.core.StateManager¶
@dataclass
class StateManager:
config: AMXConfig
store: SQLiteHistoryStore | None = None
namespace: str = "default"
def set_config(self, key: str, value: Any) -> None
def set_session_state(self, key: str, value: Any) -> None
def get_session_state(self, key: str, default: Any = None) -> Any
def record_agent_state(self, agent_name: str, state: dict[str, Any]) -> None
Write-through persistence for config and SQLite-backed session state across AMX sessions.
from amx.core import AMXApplication
app = AMXApplication.load()
state = app.state # StateManager
state.set_config("active_db_profile", "snow_prod") # persists to config.yml
state.set_session_state("last_query", "tables with dates") # persists to history.db
prev = state.get_session_state("last_query")
set_config(key, value) raises KeyError if key isn't an attribute of the loaded
AMXConfig — guards against typos.
set_session_state / get_session_state / record_agent_state use the SQLite history
store; they're a no-op when store is None.
On-disk shapes (also part of the contract)¶
These are stable across minor versions:
~/.amx/config.yml— see Configuration → config.yml.~/.amx/history.db— SQLite tablesanalysis_runs,run_results,app_events,session_state,pending_shared_writes. Additive migrations within a major version.--jsonexport shape — keysschema_version,run_summary,per_column,aggregate_metricsare stable. Full shape documented attests/eval/README.md.
Internal symbols (do not depend on)¶
Anything not on this page is internal. Importing it works today but the symbol, signature, location, or behaviour can change in any release without notice. See Python API → What's internal for the highlights.