Skip to content

Server and Python SDK 3.2.2

DeepIntShield Server 3.2.2 and Python SDK 3.2.2 - 23 October 2026.

This is a correction release on 3.2.1. It carries the corrections made on 22 and 23 October after a review of every error the internal QA testers had recorded against the deployed 3.2.1 and a measured run of the QA catalogue against it, and aligns the SDK, gateway and documentation reference at 3.2.2; every 3.2.1 client keeps working unchanged. Check the version and enabled capabilities of your own gateway: a documentation release does not establish what is deployed.

Decision targets are validated before authorization

Section titled “Decision targets are validated before authorization”

POST /api/agentic-new/decide now checks the shape of object and permission before it asks OpenFGA anything. An object must be <type>:<id>, where the type is one of the authorization model’s object types and the id holds no :, #, * or whitespace; a permission must be a relation defined on that type (can_view, can_edit, can_fulfill, …) or a custom permission key containing : (invoice:approve), which is checked as a permission holder. A malformed target answers 400 invalid_object or 400 invalid_permission with a message that names the offending value and the accepted forms; error.param carries the field, the value and the accepted types or relations.

Until now such a request reached OpenFGA, which rejected the tuple, and the decision read authz_engine_error, which told nobody what was wrong. Decisions recorded by the MCP, task and rehearsal paths carry the same two reasons with the failed check target; a genuine authorization-engine failure still reads authz_engine_error. The rules follow the workspace’s pinned model, so types published through the authorization studio validate too. The Python SDK shows the code as the exception prefix (invalid_object: ...) followed by the gateway’s message.

An over-limit blueprint scan is incomplete coverage, not an outage

Section titled “An over-limit blueprint scan is incomplete coverage, not an outage”

A complete code capture whose static analysis produced more findings than one attestation holds could not be persisted: the discover call answered 503 blueprint_scan_unavailable and quarantined the reporter under that code, as if the scanner were down. Discovery now refuses more than 192 static findings as 400 blueprint_coverage_incomplete and quarantines the reporter under that exact code; the caps (256 findings in total, 64 from the model phase, 192 static) are shared by discovery, the scan store and the handler. blueprint_scan_unavailable is left for genuine store failures, so an operator who sees it knows the store failed, and one who sees blueprint_coverage_incomplete knows the scan ran and the program’s code is what needs attention.

Guardrail evaluation names the policies it evaluated

Section titled “Guardrail evaluation names the policies it evaluated”

The responses of POST /api/guardrails/evaluate and the simulate route gain an additive policies_evaluated list (id, version_id, name, scope, enforcement_mode, enabled, matched), omitted when nothing was evaluated. A caller can now tell that a policy was not part of the evaluation - a rule left disabled, for example - instead of inferring it from an allow. The decision fields are unchanged, and a client that ignores fields it does not know is unaffected.

Multipart uploads and SDP offers reach their handlers

Section titled “Multipart uploads and SDP offers reach their handlers”

The request prefilter’s fast JSON check applied to every /v1/* body, so POST /v1/files (multipart form data) and raw application/sdp bodies on /v1/realtime/calls were refused with 400 request body is not valid JSON. The check now applies only to bodies declared, or defaulted, as JSON: file uploads and realtime SDP offers go through to their handlers, and JSON bodies are checked exactly as before.

A provider error during a streaming response keeps its status and message

Section titled “A provider error during a streaming response keeps its status and message”

An upstream error that arrived once a stream had started was relayed with an empty message in every protocol format: OpenAI clients saw “An error occurred during streaming”, Anthropic clients an api_error with no text, Gemini clients a blank 500. An error that was the stream’s first event went out under 200 text/event-stream, so a caller whose account had no credits, no permission or an invalid request learned none of it.

The gateway now reads the first chunk before committing the stream. An error there answers the real status with the format’s JSON envelope: OpenAI error.type/code/message, Anthropic {"type":"error","error":{"type":"rate_limit_error",...}}, Gemini {"error":{"code":429,"status":"RESOURCE_EXHAUSTED",...}}. A mid-stream error is emitted as the format’s error event with the status, type and message, after which the stream ends. The status is the provider’s where it gives one and otherwise inferred from the error type (insufficient_quota and rate limits 429, authentication 401, permission 403, not found 404, invalid request 400, overloaded 529, unavailable 503). Native OpenAI-format streams no longer append [DONE] after an error event. A client that retries on status codes now sees the status it retries on; a stream that completes is delivered exactly as before.

  • Provider keys. A provider key created without an explicit enabled flag could not be disabled: the unchanged-content check skipped the write while the page reported success. The disabled state is now written.
  • Guardrail policies. A policy saved without a name was silently stored as “Untitled Policy”; the API answers 400 Policy name is required and the editor shows the message under the field.
  • Custom pattern cards. A card using JavaScript-only regex syntax (lookahead, lookbehind, backreferences, named groups) passed the browser check and failed at save with a generic prefix; the card editor names the RE2 incompatibility at Create card.
  • Numeric limits. Limit fields accepted 100abc or negative values; they accept unsigned decimals only, and the semantic-cache TTL shows its validation message beside the field.
  • RAG sources. A source could be saved with an empty name; the API answers 400 RAG source name is required.
  • Field-level errors. A field-level API error (a missing provider name in AI Models, for example) reached the page as “An unexpected error occurred”; the form shows the missing field.
  • Aligned with Server 3.2.2; the inference, guardrail, RAG, MCP and Agentic APIs are unchanged from 3.2.1.
  • A composite LangGraph node no longer quarantines the agent at its first execution. 3.2.1 covered a LangGraph node built from Runnables - a RunnableParallel, a chain such as itemgetter("messages") | model, a RunnableBranch, a ToolNode, a compiled subgraph - in the discovery report by the composition it dispatches, but the execution gate still attested the node by the framework method it wraps (the bound runnable’s invoke), which never matched the acknowledged artifact. The first run after approval therefore posted a second, “first-run” capture built from LangGraph’s own source, an incomplete artifact the gateway refuses as blueprint_coverage_incomplete and quarantines the reporting agent for. The gate now attests the node by the same composition text and digest the discovery report carried (the decision fingerprint too), so the approved blueprint is recognised and the run proceeds to the authorization decision. A composition that cannot be read still fails closed. With SDK 3.2.1, RunnableParallel and chain nodes quarantine the agent on their first executed run: upgrade before running such a program.

With AWS Strands Agents 1.62 installed, SDK 3.2.2 refuses to build a client once strands is imported (governance_configuration_error): it does not recognise the tool terminal Strands 1.62 introduced. The fix shipped as Server and Python SDK 3.2.3; until you upgrade, pin strands-agents<1.62.

The internal test catalogue was corrected with this release. From the error review: a case whose shared setting was never provided, whose source checkout is not found, or whose request the workspace’s provider key or model policy refuses records Blocked with the exact value or setting to change instead of a traceback; packs print UTF-8 on Windows consoles; source-test cases find the checkout from the working directory; the sign-in cases start with enabling MFA on the tester’s own account; a console page that shows a plan upgrade message is recorded as Blocked; and the console cases were reworded to what the product offers (Viewer invitations for read-only checks, CSV-only registry import, comma-separated roles, provider cards in the model catalog). From the measured run: SDK source cases prescribe the [dev,all] extras (the Strands, Google ADK and Temporal tests were skipping); the file round-trip cases compare the stored metadata of a user_data file instead of a download OpenAI refuses for that purpose; the agentic investigation cases send authorization targets the gateway evaluates (resource: objects with model relations, custom permission keys for the counter tools), with the QA provisioning writing the matching grants, group ownership and delegations; and two runner tools execute the guardrail-rule family with each rule switched on in turn and the whole automated catalogue with per-cause classification.

Terminal window
python -m pip install --upgrade "deepintshield==3.2.2"
# with gateway runtime authentication and LangGraph:
python -m pip install --upgrade "deepintshield[runtime,langgraph]==3.2.2"

The console ships inside the server image, so Server 3.2.2 and its UI upgrade together. No configuration change, no new variable and no migration are required; the authorization model republishes at start, so the decision-target rules follow each workspace’s pinned model without operator action. Streaming clients receive the provider’s status for an error from the first chunk on, and policies_evaluated is an additive field; nothing else changes for existing clients. For the 3.2.1 changes (MCP tool schemas only for callers that can use them, JSON 404s for unknown API paths, the cost-optimization cascade and the model policy, Gemini forced function calls), see Server and Python SDK 3.2.1.