Skip to main content
Strands Agents is a Python SDK for building agents that use models and tools. The strands-neuraltrust package connects its agent lifecycle to TrustGuard, evaluating prompts, conversation history, model responses, tool arguments, and tool results. Use GuardedAgent when your application needs a complete, checked text response. Use TrustGuardIntervention when you manage the Strands agent and its callbacks, telemetry, and execution settings yourself.

Integration capabilities

Tool arguments are evaluated before execution. Completed tool results are evaluated before the next model call. A result check cannot undo effects the tool has already produced.

Before you start

Start with an Observe policy to review findings in Activity, then verify the intended outcomes in Enforce mode. An allow or report response does not prove that a detector matched or that an enforcing rule was enabled. See Policies.

1. Install

The Python import is strands_neuraltrust.

2. Configure credentials and tracing

Load the collector API key and deployment URL from your environment or secret store. Set trace redaction before the process creates any Strands agent or tracer:
The example below reads these variables explicitly. TrustGuardConfig does not discover environment variables, select a default endpoint, or select a model provider. base_url is the deployment root, optionally with a path prefix; the client appends /v1/evaluate.
The empty telemetry allowlist redacts the supported Strands content fields. GuardedAgent checks the initialized tracer state. Setting the variable after a tracer exists is insufficient; restart the process. Allowed system instructions can still appear in the SDK’s separate system_prompt span attribute. Keep secrets out of system instructions and configure other logging and telemetry sinks separately. See Streaming and telemetry.

3. Create a guarded agent

Pass your configured, stateless Strands Model to this function. The evaluator stays open for the invocation and closes when the context exits:
GuardedResult.text contains the accepted final text. decisions is a tuple of content-free DecisionRecord(stage, status) values, and stop_reason identifies the accepted completion reason. The result does not expose raw findings, model events, SDK history, or the underlying AgentResult. For a synchronous application, use agent.invoke(prompt) inside a with TrustGuardClient(config) context. Do not call the synchronous invocation from an already running event loop. Keep the agent and evaluator alive together to continue a conversation. Reuse the same agent only after successful calls, and use separate agents for concurrent conversations. After any failed or cancelled invocation, create a new agent.

Add tools

Pass registered Strands tools through tools:
Tools execute sequentially, and the guarded agent disables agent retries. A block prevents pending protected work from continuing. Tools that already ran may have changed external state; the integration does not provide rollback or authorize an entire batch atomically.

4. Handle decisions

The guarded agent and intervention enforce the following behavior: Catch TrustGuardBlocked when your application needs to display its own refusal message. Treat other TrustGuardError subclasses as terminal protection failures, and return an application-controlled error rather than retrying the same agent. asyncio.CancelledError remains cancellation.
The direct TrustGuardClient.evaluate() and aevaluate() methods return advisory Verdict values. They return block and ask without enforcing them. Use the guarded agent or intervention for lifecycle enforcement, or implement every decision in your own application.

Coverage

GuardedAgent returns complete checked text, so it can block or transform supported output before delivery. A native agent with only TrustGuardIntervention can expose raw streamed output before its completed output check. Transformations preserve supported text/JSON structure and refuse changes to tool schemas, names, routing identities, and other immutable metadata. See Supported content and transformations. Coverage applies to the configured agent path. Tool-result checks cannot undo completed tool effects. Models, tools, and application instrumentation remain trusted application components.

What gets evaluated

Every boundary normally makes two evaluations: a structured payload followed by a text assessment of its supported content. The second assessment presents history, tool content, and the values inside supported JSON as text. This lets text-oriented detectors inspect content that they may not extract from every structured field. Both assessments must pass before staged changes are applied. The second request uses the same collector, direction, session, and consumer. It adds service latency, quota usage, and ordinary evaluation records, and may affect stateful detector counters. It remains subject to all request, time, and invocation budgets. Logical decision records summarize both responses: transform takes precedence over report, then allow. An accepted text-only GuardedAgent invocation normally makes eight evaluation requests. A native agent with the intervention normally makes six. Tool calls and additional model turns add more; a block or failure can stop earlier. There is no policy-decision cache. Set text_assessment=False only after independently qualifying your collector’s structured assessment for every required history, tool, and metadata surface. This option removes the additional text coverage and is not equivalent protection with a collector that scans only the latest message.

Configuration

Collector client

TrustGuardConfig is immutable. Its representation omits the API key, and constructing it performs no evaluation. URLs containing credentials, query strings, fragments, encoded path segments, dot segments, or malformed hosts are rejected. Owned transports verify TLS, ignore environment proxy configuration, disable redirects, and request uncompressed JSON. The response must be HTTP 200, application/json, and identity encoding. The client performs no retries and fails closed on transport or protocol errors. Requests use protocol="llm" and an explicit direction. The direct client also accepts session_id, consumer_id, and JSON attributes on each evaluation; see the Evaluate API. These are evaluation routing fields and do not create Strands sessions.

Guarded agent

The caller owns model and evaluator lifetimes. Provider-managed conversation state cannot be inspected as local history, so use a fresh, stateless model instance with application-controlled settings. The facade accepts no arbitrary agent construction options, custom middleware, sessions, plugins, or executor configuration.
Owned synchronous transports reuse a serialized connection pool. Owned async evaluations create and close a client on the current loop for each request. This supports repeated synchronous guarded invocations that create distinct event loops, at the cost of async connection reuse.TrustGuardClient(config, http_client=..., async_http_client=...) accepts caller HTTPX clients. You own their transport, TLS, proxy, event-hook configuration, and lifetime. The adapter overrides request authentication and redirect behavior but cannot control arbitrary custom transport code. An injected async client binds to its first evaluation loop and refuses another loop. A sync HTTPX injection is not used by async evaluation; use owned transports for repeated synchronous guarded-agent calls.Close the adapter with close() / aclose() or its context managers. Closing it prevents new evaluations and never closes injected clients. Finish or cancel outstanding calls before closing shared resources. Async cancellation propagates and owned per-request resources are closed.Python cancellation is cooperative. Blocking user code cannot be forcibly interrupted by an async deadline. The sync elapsed bound can be exceeded by an in-flight HTTP phase. Limits bound accepted content sizes, not every allocation inside provider or tool implementations.

Supported content and transformations

Supported content is user/assistant text, model tool calls, and tool results containing text or JSON blocks. Other content fails closed. Images, audio, video, documents, binary attachments, reasoning/signatures, citations, cache points, and unknown message structures are unsupported. Transformations preserve message count, order, roles, block kinds, tool names, result success/error state, system instructions, and tool declarations. JSON transformations preserve object keys, array lengths, and scalar categories. Arguments must validate against the registered tool schema before execution. An invalid, partial, or ambiguous replacement stops the invocation. Tool schemas use reference-free JSON Schema 2020-12, or omit $schema and use that draft’s semantics. $ref, $dynamicRef, and $recursiveRef are rejected, including local references. Output schemas and extra provider-specific tool declaration fields are unsupported. Tool annotations are not policy input; keep authorization data in supported assessed content.
The evaluator receives normalized Anthropic-style messages. JSON tool results become individual text blocks for evaluation and are restored to their original JSON block types after validation.Opaque tool-call IDs are replaced with consistent, nonnumeric aliases for each structured assessment. Original IDs remain local, and are restored only after the returned aliases are validated unchanged. This prevents generic PII detection from treating SDK routing IDs as phone numbers. Unknown, swapped, added, or modified aliases are refused. Tool names, arguments, results, schemas, and system instructions remain subject to assessment. The direct advisory client sends caller-supplied payloads as given.The additional text assessment uses an immutable prefix and an ordered mapping to the original content locations. JSON values appear as individual units; repeated equal text does not replace unrelated fields. Changes remain staged until both decisions and all structural/schema checks succeed. A changed prefix, role, block count, or immutable metadata is refused.Encoded JSON objects, arrays, and quoted strings are decoded for text assessment. Unchanged encoded text keeps its original formatting. Bare numeric-looking, boolean-looking, and null-looking SDK strings remain strings; typed JSON values keep their categories. Traversal is bounded to 64 levels and 100,000 nodes, including encoded layers. Recognizable JSON that violates duplicate-key, nonfinite-number, or resource checks is refused.A full-message evaluation requires a matching structured replacement. A generic {"input": "replacement"} is not a valid rewrite of a multi-message payload. Message metadata and tracking IDs stay local and are omitted from evaluator payloads as non-provider content.

Streaming and telemetry

GuardedAgent returns complete accepted text and offers no token stream. Its internal callback validates and bounds raw model/tool events before the SDK consumes them. It refuses malformed or truncated streams and malformed tool argument JSON instead of allowing the SDK to repair it into an empty object. The supported model event protocol is the sequential Bedrock-style protocol; provider-specific fields and alternate tool-identity-in-delta protocols are refused. The lower-level intervention sees completed model output. Raw SDK streams and callbacks can expose tokens before a later output block. Setting callback_handler=None disables default printing, but does not make raw streaming preventive. Use the complete-result interface when response content must be checked before delivery. The guarded facade wraps the model through the public Strands Model interface and converts provider stream exceptions to content-free errors before SDK error instrumentation. The application still owns the provider lifetime. Local token estimation uses the base model heuristic rather than an optional remote token counting method. Trace redaction checks the supported SDK tracer fields at construction and on invocation. An absent or changed field refuses construction. The integration does not mutate global telemetry settings. Preflight keeps blocked system/tool context out of agent invocation; allowed system text can still appear in the separate system_prompt span attribute. Configure third-party spans, exception exporters, Python logging handlers, tool-owned stdout/stderr, HTTPX logging, callbacks, and provider instrumentation separately. Avoid recording prompts, tool results, request bodies, credentials, and raw exceptions. The supported return value and trace redaction do not imply that arbitrary application code cannot disclose data.

Using a native Strands agent

Use TrustGuardIntervention when your application owns the native agent:
This supplies lifecycle checks without the facade’s preflight, raw-event parser, complete-result interface, sequential executor, or provider-error wrapper. Your application owns callbacks, tracing, sessions, hooks, middleware, streaming, retries, and executor configuration. Do not mutate configuration while the agent is executing. The intervention accepts session_id, consumer_id, max_evaluations=128, and text_assessment=True. A shared intervention keeps separate failure and decision state for each agent. decisions(agent) returns bounded stage/status records. Failed agents cannot continue. Direct native tool calls share the agent’s evaluation counter until a normal invocation begins. Its async assess(payload, direction, stage) method performs a bounded standalone assessment with a fresh per-call budget. It does not authorize a later unassessed execution.
Native direct agent.tool calls copy keyword arguments into ToolContext.invocation_state. That separate state is outside the transformation boundary, so a tool reading it may see original arguments independently of its transformed input. The guarded facade exposes no direct-tool shortcut.

Errors

All protection errors inherit from TrustGuardError. Messages are content-free; raw upstream bodies and finding evidence are not exposed. Unknown statuses, duplicate JSON keys, nonfinite numbers, invalid Unicode, malformed transforms, and inconsistent finding-action precedence are refused. Transport fail-closed behavior cannot turn an allow from an unmatched, Observe, or fail-open server policy into a verified enforcing decision.

Verify your integration

  1. Use a dedicated test collector and synthetic content with known matching rules. Confirm Input and Output directions and the selected policy mode.
  2. Confirm an accepted prompt returns a complete response and stage/status decisions. Reconcile the conversation in Activity using your session_id.
  3. Trigger an input block and confirm the model is never called. Trigger an output block and confirm no response text reaches the application caller.
  4. Trigger a tool-argument block and confirm the tool performs no effect. Trigger a tool-result block and confirm the next model turn does not run.
  5. Test transformations in prompts, history, output, tool arguments, and results. Confirm only the accepted replacement continues and unsupported replacements fail closed. Include older history and nested JSON in your cases.
  6. Test unavailable service, invalid authentication, malformed decisions, resource limits, and cancellation. Confirm failed conversations refuse reuse.
  7. Review application logs and telemetry using synthetic markers. Verify the configured provider’s stream protocol separately before deployment.
The integration protects only the supported agent path. It does not sandbox models or tools, cover child agents or direct MCP clients automatically, inspect provider-managed hidden history, or control provider-side logging and retention. TrustGuard receives the content it evaluates, including supported history, system text, tool declarations, arguments, and results. Choose its deployment, retention, and access controls for that data. See Data handling for the service-side storage contract. Source and issues: NeuralTrust/strands-neuraltrust. For endpoint semantics, see the Evaluate API. For gateway enforcement across applications and clients, see TrustGate.
Install the locked development environment in the package checkout and run the standard checks:
Default tests disable network sockets and use synthetic data. Keep live service credentials and test evidence out of contributions. Add behavior-focused regressions for transport, enforcement, transformation, cancellation, and caller-visible results. Dependency updates require lifecycle, streaming, telemetry, cancellation, and failed-conversation checks. New content types require lossless reconstruction and schema/identity preservation.Report vulnerabilities privately to NeuralTrust maintainers through your existing project contact. Do not open a public issue containing exploit details, credentials, production prompts, service responses, or unredacted traces. Include the package, Strands, and Python versions; the affected lifecycle boundary; a synthetic reproduction; expected and observed behavior; and the relevant collector policy mode.