Summary
Replace the PrebuiltInspector.<guard>() factory-classmethod API with marketplace-style
retrieval: aix.Inspector.get("aixplain/prompt-injection-guard") and aix.Inspector.search(...).
This makes guards discoverable (REPL-browsable like models/tools), keeps the aix.Agent(inspectors=[...])
attribute identical for prebuilt and custom inspectors, and means future guards ship with zero SDK
changes — they just appear in the marketplace.
Status: BETA / unreleased. Inspectors are not yet GA, so this redesign is non-breaking and can
hard-remove the current PrebuiltInspector surface.
Problem
Today (aixplain/v2/inspector.py) prebuilt inspectors are exposed as per-guard factory methods:
from aixplain.v2 import PrebuiltInspector
PrebuiltInspector.prompt_injection_guard()
PrebuiltInspector.pii_redaction(targets=["output"])
PrebuiltInspector.hallucination_guard()
This reintroduces the exact scattered-factory sprawl v2 deleted from v1 (create_sql_tool(),
create_python_interpreter_tool(), …):
- Not discoverable. There is no
aix.Inspector.search(). To learn which guards exist you must
read source/docs — you can't browse them in the REPL like every other asset.
- Not guessable. Every other "get a prebuilt thing from the marketplace" is a string path —
aix.Tool.get("microsoft/code-execution"), aix.Agent.get("…/research-agent/aixplain"). Here it's
a method name. A developer who learned .get(path) cannot guess .prompt_injection_guard().
- SDK change per guard. Each new guard requires a new classmethod and a hardcoded asset id in
the SDK (PROMPT_INJECTION_GUARDRAIL_ASSET_ID, PII_REDACTION_GUARDRAIL_ASSET_ID,
HALLUCINATION_GUARD_ASSET_ID), rather than just appearing as a marketplace entry.
- Config asymmetry.
pii_redaction(targets=[...]) takes targets, prompt_injection_guard()
takes nothing, and there's no runtime way to enumerate what a guard accepts.
- Split imports. Prebuilts come from
aixplain.v2 (PrebuiltInspector) while custom inspectors
come from aixplain.v2.inspector (Inspector) — two import depths for one concept family, so a
developer can't predict where Inspector-family symbols live.
Backend validation (guardrails is a first-class Function)
Confirmed against the backend that guards are ordinary marketplace assets, which is what makes
retrieval-by-path the correct model:
GET /sdk/functions returns {"id": "guardrails", "name": "Guardrails"} with a defined contract:
input text → output Label (dataType: label), modalities text-text / text-label.
Description: "governance rules that enforce security, compliance, and operational best practices."
- The model
69cbf63cd74e334a6bacfeb1 = "Sensitive Information Guardrail", function.id = "guardrails",
functionType = "ai", status onboarded — i.e. the exact id the SDK currently hardcodes as
PII_REDACTION_GUARDRAIL_ASSET_ID.
- The v2
FunctionType/Function enums do not yet include guardrails.
Since guards are real marketplace models under function=guardrails, they should be retrieved like
any other asset rather than mirrored as Python methods + hardcoded ids.
Proposed canonical interface
from aixplain import Aixplain
aix = Aixplain(api_key="<KEY>")
# Discover available guards like any other asset
aix.Inspector.search("guard")
# → {"results": [...], "page_number": 0, "page_total": 1, "total": 6}
# Retrieve a prebuilt by human-readable path (IDs also accepted)
guard = aix.Inspector.get("aixplain/prompt-injection-guard")
redactor = aix.Inspector.get("aixplain/pii-redaction")
redactor.targets = ["output"] # config as an inspectable attribute
research_agent = aix.Agent.get("aixplain-testing/research-agent/aixplain")
team = aix.Agent(
name="research-team",
agents=[research_agent],
inspectors=[guard, redactor], # same attribute — custom or prebuilt
)
team.save(save_subcomponents=True)
resp = team.run(query="My phone is +201097634134, repeat it back.")
print(resp.data.output) # {PHONE}
aix.Inspector.get(path) returns a ready-to-use Inspector (guard model as evaluator + sensible
default action/targets/severity). A prebuilt fetched by path and a hand-built Inspector(...)
are the same type, so inspectors=[...] never cares which it got.
Scope of change
- Add
aix.Inspector as a client resource backed by the guardrails marketplace Function:
.get(path_or_id) → returns a fully-configured Inspector.
.search(query, ...) → standard {results, page_number, page_total, total} shape.
- Hard-remove
PrebuiltInspector and its prompt_injection_guard() / pii_redaction() /
hallucination_guard() / list_presets() classmethods, plus the _PREBUILT_REGISTRY and the
hardcoded *_GUARDRAIL_ASSET_ID constants (unreleased — no deprecation shim needed).
- Keep the custom
Inspector(...) dataclass and the aix.Agent(inspectors=[...]) composition
(these are correct — no GuardedAgent subclass).
- Module layout. Co-locate the whole
Inspector family (Inspector, InspectorActionConfig,
EvaluatorConfig, EditorConfig, and the enums) under a single predictable module
(aixplain.v2.inspector). With aix.Inspector as the entry point, the common path needs no
direct import at all; power users have exactly one place to look for the config classes — not the
current aixplain.v2 vs aixplain.v2.inspector split.
- Standardize config overrides as attribute assignment (
guard.targets = [...]), matching how
model/tool config is set, and make the knobs inspectable.
- Consider adding
guardrails to the v2 Function enum.
Docs & security hygiene
- No internal endpoints in examples. Published notebooks/docs must use the default client
(aix = Aixplain(api_key="<KEY>")) — drop the BACKEND_URL / MODELS_RUN_URL dev-endpoint
overrides. Internal URLs leak infra and don't work for external readers.
- No live keys in committed artifacts. The source notebook (
pre_built_inspectors (1).ipynb)
committed a real TEAM_API_KEY in plaintext. Rotate that key now (treat as compromised) and
scrub it from history; never commit real keys to shared notebooks/docs.
- Use
query=. All examples should call team.run(query="…"), not pass the query positionally,
to match the canon and avoid training the wrong habit.
Out of scope / keep
inspectors=[...] as a plain attribute on aix.Agent — textbook v2 composition.
- Abort/redaction results flowing through the standard family (
resp.data.output, detail in
resp.data.steps).
Open questions
- Home of the resource. Is
aix.Inspector the right entry point, or should guards surface under
aix.Model.search(function="guardrails") with Inspector only as the wrapper? (Proposal: keep
aix.Inspector as the discoverable front door.)
- Config surface. Standardize
targets / severity / action overrides on the returned
Inspector — attribute assignment vs constructor args. Pick one and document it.
- Path naming. Final canonical paths for the three current guards
(aixplain/prompt-injection-guard, aixplain/pii-redaction, aixplain/hallucination-guard?).
Function enum. Add GUARDRAILS to the v2 enum, or treat it as a free-form function string?
References
- Current implementation:
aixplain/v2/inspector.py (PrebuiltInspector, _PREBUILT_REGISTRY).
- Agent attachment:
aixplain/v2/agent.py (inspectors field).
- Example guard model:
Sensitive Information Guardrail (69cbf63cd74e334a6bacfeb1, function=guardrails).
Summary
Replace the
PrebuiltInspector.<guard>()factory-classmethod API with marketplace-styleretrieval:
aix.Inspector.get("aixplain/prompt-injection-guard")andaix.Inspector.search(...).This makes guards discoverable (REPL-browsable like models/tools), keeps the
aix.Agent(inspectors=[...])attribute identical for prebuilt and custom inspectors, and means future guards ship with zero SDK
changes — they just appear in the marketplace.
Problem
Today (
aixplain/v2/inspector.py) prebuilt inspectors are exposed as per-guard factory methods:This reintroduces the exact scattered-factory sprawl v2 deleted from v1 (
create_sql_tool(),create_python_interpreter_tool(), …):aix.Inspector.search(). To learn which guards exist you mustread source/docs — you can't browse them in the REPL like every other asset.
aix.Tool.get("microsoft/code-execution"),aix.Agent.get("…/research-agent/aixplain"). Here it'sa method name. A developer who learned
.get(path)cannot guess.prompt_injection_guard().the SDK (
PROMPT_INJECTION_GUARDRAIL_ASSET_ID,PII_REDACTION_GUARDRAIL_ASSET_ID,HALLUCINATION_GUARD_ASSET_ID), rather than just appearing as a marketplace entry.pii_redaction(targets=[...])takestargets,prompt_injection_guard()takes nothing, and there's no runtime way to enumerate what a guard accepts.
aixplain.v2(PrebuiltInspector) while custom inspectorscome from
aixplain.v2.inspector(Inspector) — two import depths for one concept family, so adeveloper can't predict where
Inspector-family symbols live.Backend validation (
guardrailsis a first-class Function)Confirmed against the backend that guards are ordinary marketplace assets, which is what makes
retrieval-by-path the correct model:
GET /sdk/functionsreturns{"id": "guardrails", "name": "Guardrails"}with a defined contract:input
text→ outputLabel(dataType: label), modalitiestext-text/text-label.Description: "governance rules that enforce security, compliance, and operational best practices."
69cbf63cd74e334a6bacfeb1= "Sensitive Information Guardrail",function.id = "guardrails",functionType = "ai", statusonboarded— i.e. the exact id the SDK currently hardcodes asPII_REDACTION_GUARDRAIL_ASSET_ID.FunctionType/Functionenums do not yet includeguardrails.Since guards are real marketplace models under
function=guardrails, they should be retrieved likeany other asset rather than mirrored as Python methods + hardcoded ids.
Proposed canonical interface
aix.Inspector.get(path)returns a ready-to-useInspector(guard model as evaluator + sensibledefault
action/targets/severity). A prebuilt fetched by path and a hand-builtInspector(...)are the same type, so
inspectors=[...]never cares which it got.Scope of change
aix.Inspectoras a client resource backed by theguardrailsmarketplace Function:.get(path_or_id)→ returns a fully-configuredInspector..search(query, ...)→ standard{results, page_number, page_total, total}shape.PrebuiltInspectorand itsprompt_injection_guard()/pii_redaction()/hallucination_guard()/list_presets()classmethods, plus the_PREBUILT_REGISTRYand thehardcoded
*_GUARDRAIL_ASSET_IDconstants (unreleased — no deprecation shim needed).Inspector(...)dataclass and theaix.Agent(inspectors=[...])composition(these are correct — no
GuardedAgentsubclass).Inspectorfamily (Inspector,InspectorActionConfig,EvaluatorConfig,EditorConfig, and the enums) under a single predictable module(
aixplain.v2.inspector). Withaix.Inspectoras the entry point, the common path needs nodirect import at all; power users have exactly one place to look for the config classes — not the
current
aixplain.v2vsaixplain.v2.inspectorsplit.guard.targets = [...]), matching howmodel/tool config is set, and make the knobs inspectable.
guardrailsto the v2Functionenum.Docs & security hygiene
(
aix = Aixplain(api_key="<KEY>")) — drop theBACKEND_URL/MODELS_RUN_URLdev-endpointoverrides. Internal URLs leak infra and don't work for external readers.
pre_built_inspectors (1).ipynb)committed a real
TEAM_API_KEYin plaintext. Rotate that key now (treat as compromised) andscrub it from history; never commit real keys to shared notebooks/docs.
query=. All examples should callteam.run(query="…"), not pass the query positionally,to match the canon and avoid training the wrong habit.
Out of scope / keep
inspectors=[...]as a plain attribute onaix.Agent— textbook v2 composition.resp.data.output, detail inresp.data.steps).Open questions
aix.Inspectorthe right entry point, or should guards surface underaix.Model.search(function="guardrails")withInspectoronly as the wrapper? (Proposal: keepaix.Inspectoras the discoverable front door.)targets/severity/actionoverrides on the returnedInspector— attribute assignment vs constructor args. Pick one and document it.(
aixplain/prompt-injection-guard,aixplain/pii-redaction,aixplain/hallucination-guard?).Functionenum. AddGUARDRAILSto the v2 enum, or treat it as a free-form function string?References
aixplain/v2/inspector.py(PrebuiltInspector,_PREBUILT_REGISTRY).aixplain/v2/agent.py(inspectorsfield).Sensitive Information Guardrail(69cbf63cd74e334a6bacfeb1,function=guardrails).