Skip to content

API Reference

ASHA v0.4.2 - canonical signatures and import paths.


Import map

# Root (only these): v0.4.2 public API
from asha import process, sanitize, optimize, Agent, anchor
from asha import process_async, sanitize_async, optimize_async
from asha import SecureLLM, Profile              # v0.4.2 client proxy + presets
from asha import PIIVault                        # v0.4.2 reversible PII masking
from asha import scan_rag_context                # v0.4.2 RAG injection scanner
from asha import AgentCostGuard, AgentBudgetExceeded  # v0.4.2 agentic guard

# ANCHOR (also available from root)
from asha.runtime.anchor import anchor_any
from asha.runtime.anchor.adapters import anchor_crewai, anchor_langchain

# Subpackages
from asha.integrations import wrap_llm, auto_patch
from asha.runtime import PromptProcessor, ExecutionProfile
from asha.types import ProcessResult, SanitizeResult, OptimizeResult, AgentResult
from asha.core.policy_config import PolicyConfig, PolicyMode
from asha.utils.dropin import process_async, optimize_async, sanitize_async
from asha.utils.unmask import unmask
from asha.runtime.local_advisor.advisor import recommend_local_model
from asha.runtime.adapters.factory import AdapterFactory
from asha.compat.legacy_results import to_legacy_pipeline_dict
from asha.cli.terminal import render_security_report  # v0.4.2 rich/ANSI diagnostics

Result types

result = process("prompt")  # ProcessResult

result.output
result.original
result.degraded
result.degraded_reason
result.security       # SecurityInfo | None
result.metrics        # MetricsInfo | None
result.trace          # dict | None (trace=True)
result.diff           # str | None (debug=True)
str(result)           # == result.output
result.to_dict()      # legacy dict shape

process()

from asha import process
from asha.core.policy_config import PolicyConfig

result = process(
    prompt="...",
    mode="balanced",           # strict | balanced | lite | off
    token_budget=1200,
    trace=False
)

Parameters: - prompt (str | bytes | Path): The input prompt or file to process. - mode (str, optional): Policy mode. Options: - strict: Fail-closed - raises on total failure - balanced: Fail-open fallback (default) - lite: Minimal policy; fail-open - off: Passthrough - policy (PolicyConfig, optional): Advanced runtime configuration (fields: pii_mode, reversible, preserve_intent, security_level, stage enable flags). - token_budget (int, optional): Maximum tokens permitted before truncation (default: 1200). - trace (bool, optional): If true, populates result.trace with internal execution steps. - debug (bool, optional): If true, populates result.diff with a text diff. - max_retries (int, optional): Number of retries for detector engines. - timeout_seconds (float, optional): Max timeout for execution. - verbose (bool, optional): Enables verbose console logs. - log_level (str, optional): Logging level (INFO, DEBUG). - log_output (str, optional): Output destination (console, etc). - log_file (str, optional): Path to a log file. - include_legacy_detail (bool, optional): Includes legacy dict schema.

Returns: - ProcessResult: Contains .output (scrubbed string) and .security (detection summary).


sanitize()

from asha import sanitize

result = sanitize(
    prompt: str,
    mode: str = "balanced",
    *,
    policy: PolicyConfig | None = None,
    trace: bool = False,
    debug: bool = False,
    max_retries: int = 0,
    timeout_seconds: float | None = None,
    verbose: bool = False,
) -> SanitizeResult

optimize()

from asha import optimize

result = optimize(
    prompt: str,
    *,
    token_budget: int = 1200,
    trace: bool = False,
    debug: bool = False,
    timeout_seconds: float | None = None,
) -> OptimizeResult

Token compression only - no security or compile stages.


wrap_llm()

from asha.integrations import wrap_llm

client = wrap_llm(
    client,
    mode: str = "balanced",
    token_budget: int = 1200,
    auto_select_local_model: bool = False,
    sample_prompts: list[str] | None = None,
)
  • mode="off" - no preprocessing
  • Processing errors: strict raises; balanced degrades
  • Wrap infrastructure errors raise when mode != "off"

auto_patch()

from asha.integrations import auto_patch
from asha.integrations.auto_patch import (
    get_patch_status,
    disable_auto_patch,
    enable_auto_patch,
)

auto_patch(mode: str = "strict", enable: bool = True, verbose: bool = False)

Globally patches installed SDKs. Prefer wrap_llm() for production.


Async

from asha.utils.dropin import process_async, sanitize_async, optimize_async

result = await process_async("prompt", mode="balanced")

unmask()

from asha.utils.unmask import unmask

restored = unmask(llm_output, masking_map)

Requires policy=PolicyConfig(reversible=True) during process() / sanitize().


Agent

from asha import Agent

agent = Agent(
    model: str = "gpt-4o-mini",
    privacy: bool = True,
    token_budget: int = 1200,
    provider: str | None = None,
    fallback_providers: list[dict] | None = None,
    routing_config: dict[str, str] | None = None,
    timeout: int = 10,
    retries: int = 3,
    api_key: str | None = None,
    local_model: str | None = None,
    sample_prompts: list[str] | None = None,
)

# Returns str by default
response = agent.run(prompt, trace=False, task_type="chat")

# Returns AgentResult when trace=True
result = agent.run(prompt, trace=True)

privacy=True → internal mode="strict". privacy=False → mode="off".


PromptProcessor

from asha.runtime import PromptProcessor, ExecutionProfile

processor = PromptProcessor()
result = processor.run("prompt", mode="balanced", profile=ExecutionProfile(...))

recommend_local_model() (experimental)

from asha.runtime.local_advisor.advisor import recommend_local_model

report = recommend_local_model(
    prompts: list[str] | None = None,
    prompts_file: str | None = None,
    mode: str = "balanced",
    top: int = 5,
    gpu: str | None = None,
    vram_gb: float | None = None,
    cpu_only: bool = False,
    refresh_catalog: bool = False,
    preferred_quant: str | None = None,
    probe: bool = False,
)

Experimental: API may change

See experimental-features.md.


AdapterFactory (experimental)

from asha.runtime.adapters.factory import AdapterFactory

adapter = AdapterFactory.create(provider="openai", model="gpt-4o-mini")
adapter = AdapterFactory.create(provider="mock")
adapter = AdapterFactory.create_smart_routing({"chat": "gpt-4o-mini"})

Providers: openai, anthropic, gemini, ollama, huggingface, grok, mock.

Smart routing and factory helpers may change (see experimental-features.md).


Legacy dict

from asha.compat.legacy_results import to_legacy_pipeline_dict

legacy = to_legacy_pipeline_dict(
    process("prompt", include_legacy_detail=True)
)

CLI

Command Description
asha "prompt" Demo process
asha quick-test Built-in tests
asha examples Sample transformations
asha benchmark Benchmark harness
asha recommend AshaFit advisor

Environment variables

Variable Purpose
OPENAI_API_KEY / ANTHROPIC_API_KEY / GOOGLE_API_KEY / GEMINI_API_KEY / GROK_API_KEY Provider adapters / live demos
ASHA_PROVIDER / ASHA_MODEL Agent.from_env() / adapter factory
ASHA_TOKEN_BUDGET / ASHA_TIMEOUT / ASHA_RETRIES Agent / adapter defaults
ASHA_PRIVACY Agent.from_env() privacy flag (true/false)
ASHA_MODELS_DIR Use a local models tree (skip default cache layout)
ASHA_MODELS_URL Override hardened-models download URL
ASHA_MODELS_ZIP Local zip fallback for the models bundle
ASHA_MODELS_CACHE Override cache directory (~/.cache/asha/models default)
ASHA_DISABLE_MODEL_DOWNLOAD 1: never fetch models (CI / air-gap)
ASHA_DISABLE_ML Disable ML/NER paths where checked
ASHA_THRESHOLDS_PATH Override packaged detector thresholds YAML
ASHA_INJECTION_MODE Injection detector mode override
ASHA_ENABLE_HF_SAFETY Opt-in Hugging Face safety path
ASHA_OPTIMIZER_EMBEDDING Optimizer embedding mode hint
ASHA_ANCHOR_INTERACTIVE ANCHOR interactive approval (0/1)
ASHA_ANCHOR_WARN_POLICY ANCHOR warn policy (strict / permissive / …)
ASHA_ANCHOR_TELEMETRY / ASHA_ANCHOR_TELEMETRY_PATH Opt-in ANCHOR telemetry
ASHA_CACHE_DIR Local advisor catalog cache

mode is not read from env: set per call. See also .env.example.


Errors

Exception When
ASHAProcessingError mode="strict" total failure
TypeError Unknown kwargs on process() / sanitize()
AttributeError Removed root exports (wrap_llm, Pipeline, etc.)
AgentBudgetExceeded Agent exceeded step, token, or cycle budget (v0.4.2)

See migration-v0.4.md and deprecations.md.


SecureLLM (v0.4.2)

Single-line transparent proxy for any LLM client.

from asha import SecureLLM, Profile
import openai

# One line: drop-in replacement with identical API
client = SecureLLM(openai.OpenAI(), profile=Profile.BALANCED())

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Email alice@corp.com the Q3 report"}]
)
# ↑ alice@corp.com is masked before going to OpenAI, re-hydrated in the response

Parameters: - client: Any LLM client (OpenAI, Anthropic, Gemini, Ollama). - profile (Profile, optional): Zero-config security preset. Defaults to Profile.BALANCED(). - mode (str, optional): Policy mode string ('strict', 'balanced', 'lite', 'off'). Ignored if profile is provided. - token_budget (int, optional): Override profile token budget. - rehydrate_pii (bool, optional): Re-hydrate masked PII in LLM responses. Defaults to True. - vault (PIIVault, optional): Existing vault for multi-session PII continuity.

Intercepted methods: chat.completions.create, messages.create, generate_content, generate, create.


Profile (v0.4.2)

Zero-config security profile presets.

from asha import Profile

# Factory classmethods
Profile.STRICT()      # Fail-closed, injection threshold 0.65, max 5 agent steps
Profile.BALANCED()    # Enterprise default: threshold 0.85, max 15 steps
Profile.PERMISSIVE()  # Audit/observe mode: never blocks, logs violations
Profile.DEVELOPER()   # Verbose + debug, rich terminal output, fail-open

# Custom profile
profile = Profile(
    mode="balanced",
    fail_closed=True,
    injection_threshold=0.80,
    token_budget=2048,
    max_agent_steps=10,
)

Preset comparison:

Preset Mode Fail-closed Threshold Token Budget Agent Steps
STRICT strict ✅ 0.65 1000 5
BALANCED balanced ✅ 0.85 2048 15
PERMISSIVE lite ❌ 0.95 4096 50
DEVELOPER balanced ❌ 0.80 2048 20

PIIVault (v0.4.2)

Thread-safe, session-scoped reversible PII masking.

from asha import PIIVault

vault = PIIVault()  # One vault per session/conversation

# Mask: replace PII with indexed tokens
masked = vault.mask("Email alice@corp.com or call 555-123-4567")
# → "Email <EMAIL_1> or call <PHONE_1>"

# Unmask: re-hydrate tokens in LLM responses
response_text = "I'll email <EMAIL_1> the report."
final = vault.unmask(response_text)
# → "I'll email alice@corp.com the report."

vault.summary()  # {'email': 1, 'phone': 1}
vault.clear()    # Wipe all vault entries

Detected PII types: email, phone, credit_card, ssn, api_key, jwt_token, bearer_token, address.


scan_rag_context() (v0.4.2)

Indirect injection scanner for RAG retrieved documents.

from asha import scan_rag_context

docs = retriever.get_relevant_documents(query)
result = scan_rag_context(docs, query=query)

if result.poisoned_count > 0:
    print(f"⚠️  {result.poisoned_count} poisoned chunks detected at indices: {result.poisoned_indices}")

# Use only verified safe chunks
safe_context = "\n\n".join(result.safe_documents)

Parameters: - documents (list[str] | list[dict]): Retrieved text chunks or dicts with text/page_content key. - query (str, optional): User query for relevance scoring. - include_sanitized (bool, optional): Include sanitized versions of poisoned chunks. Defaults to True. - confidence_threshold (float, optional): Minimum confidence to classify a chunk as poisoned. Defaults to 0.6.

Returns: RAGScanResult with .poisoned_indices, .safe_documents, .sanitized_documents, .poisoned_count.

Detected threats: delimiter_escape (</context>, [SYSTEM]), instruction_override (classic injection), exfiltration (webhook/POST patterns).


AgentCostGuard (v0.4.2)

Stateful agentic loop budget enforcement.

from asha import AgentCostGuard, AgentBudgetExceeded

guard = AgentCostGuard(
    max_steps=10,         # Hard step limit
    max_tokens=8000,      # Cumulative token budget
    max_cycle_repeat=3,   # Max identical tool+args repetitions
    raise_on_limit=True,  # Set False for audit mode
)

for tool_name, tool_args in agent.run():
    try:
        guard.record_tool_call(tool_name, tool_args, token_count=150)
    except AgentBudgetExceeded as e:
        print(f"Budget exceeded: {e.budget_type} {e.current}/{e.limit}")
        break
    result = execute_tool(tool_name, tool_args)

stats = guard.stats()
print(f"Steps: {stats.total_steps}, Tokens: {stats.total_tokens}, Healthy: {stats.is_healthy}")

Parameters: - max_steps (int, optional): Maximum execution steps. Defaults to 25. - max_tokens (int, optional): Cumulative token budget. Set to 0 to disable. Defaults to 50,000. - max_cycle_repeat (int, optional): Cycle detection threshold. Defaults to 3. - raise_on_limit (bool, optional): Raise on violation vs. audit-only. Defaults to True.

AgentBudgetExceeded attributes: .budget_type ('steps', 'tokens', 'cycle'), .current, .limit.