gaas-agent-framework
GaaS (Governance as a Service) integration for Microsoft Agent Framework (Python, 1.15 or later), the successor to AutoGen.
Every tool call is governed before it runs. The middleware submits a governance intent to
GaaS, and only an APPROVE (or an approved escalation) lets the tool run. On BLOCK,
GovernanceBlockedError stops agent.run(). It is an Agent Framework MiddlewareFailure, the one
exception the framework lets abort a run from function middleware; any other exception would be
turned into a tool result and the agent would carry on.
pip install "gaas-agent-framework[agent-framework]"
Fails closed by default. If GaaS cannot give a decision (unreachable, timeout, any HTTP error including a wrong API key), the tool does not run. Set
fail_open=Trueto run it anyway. See When GaaS can't answer.
Quickstart
from agent_framework import Agent, tool
from gaas_agent_framework import GaaSGovernanceConfig, GaaSGovernanceMiddleware
@tool
def search_web(query: str) -> str:
"""Search the web."""
return f"Results for {query}"
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email."""
return f"Sent to {to}"
config = GaaSGovernanceConfig(api_key="gsk_...", agent_id="my-agent")
agent = Agent(
client=chat_client, # any Agent Framework chat client, e.g. OpenAIChatClient()
tools=[search_web, send_email],
middleware=[GaaSGovernanceMiddleware(config)],
)
result = await agent.run("Email the Q3 report to finance@acme.com")
The middleware can also be attached to a single run (agent.run(..., middleware=[...])) or to a
chat client. A runnable script is in
examples/agent_framework_quickstart.py.
Verdict flow
tool call → GaaS intent → ┌─────────┐
│ APPROVE │ → tool runs
│ BLOCK │ → GovernanceBlockedError stops agent.run()
│ ESCALATE│ → treated as a block by default; hold-and-poll optional
│NO ANSWER│ → GovernanceBlockedError (UNEVALUATED) stops agent.run()
└─────────┘
Tell the model instead of stopping
With on_block="inform", a call GaaS does not allow still never runs, but the run continues and
the model receives a short notice as the tool's result ("The tool 'send_email' was not run: GaaS
governance did not allow it (verdict BLOCK, decision dec_…, policies pol_…)."). The model can then
explain or choose another step. The default, on_block="stop", is the safest choice.
Configuration
config = GaaSGovernanceConfig(
api_url="https://api.gaas.is", # GaaS API endpoint
api_key="gsk_...", # Your API key
agent_id="my-agent", # Appears in the audit trail
block_on_escalate=True, # Treat ESCALATE as a block (default)
timeout_seconds=240.0, # Covers a deliberated decision (about 40-60 s)
sensitivity="INTERNAL", # Default sensitivity for tool inputs
fail_open=False, # No decision from GaaS → the tool does not run (default)
raise_on_governance_error=False, # True: raise GaaSGovernanceError instead
on_block="stop", # or "inform": tell the model and continue
extra_regulatory_domains=["HIPAA"],
extra_data_categories=["PHI"],
hold_on_escalate=False, # Wait for the human decision on ESCALATE
escalation_poll_seconds=5.0,
escalation_max_wait_seconds=600.0,
hold_on_block=False, # Wait for a person to approve a BLOCK, then retry once
block_poll_seconds=10.0,
block_max_wait_seconds=900.0,
)
Hold-and-poll on ESCALATE
With hold_on_escalate=True, an ESCALATE verdict holds the tool call while GaaS routes the
escalation to a human reviewer: approve/modify lets the tool run; deny is a block
(ESCALATE_DENY); timeout is a block (ESCALATE_TIMEOUT).
Hold on BLOCK
With hold_on_block=True, a BLOCK waits for a person to approve the action (from the block email
or the dashboard). If they do, the call is submitted once more with the approval attached, and that
second verdict decides. Not approved in time, or still blocked: a block, as without the setting.
Handling blocked runs
from gaas_agent_framework import GovernanceBlockedError
try:
result = await agent.run("Wire $250k to the new vendor")
except GovernanceBlockedError as err:
print(err.verdict) # BLOCK / ESCALATE / ESCALATE_DENY / ESCALATE_TIMEOUT / UNEVALUATED
print(err.reason) # UNEVALUATED only, e.g. "HTTP 401", "timeout"
print(err.decision_id) # audit reference
print(err.blocking_policies) # policy IDs that triggered the block
print(err.governance_proof_token) # proof token ID for the audit trail
When GaaS can't answer
If GaaS gives no decision (a network error, a timeout, any HTTP status of 400 or above, where a
wrong API key is a 401, or a response without a verdict), the middleware fails closed: the tool
does not run, and GovernanceBlockedError is raised with verdict == "UNEVALUATED" and a short
reason such as "HTTP 401" or "timeout". It stops agent.run() exactly as a BLOCK does (or,
with on_block="inform", the model is told). The API key never appears in the message or the logs.
Three settings, checked in this order:
| Setting | When GaaS gives no decision |
|---|---|
raise_on_governance_error=True |
GaaSGovernanceError is raised, with the underlying error (e.g. httpx.HTTPStatusError, httpx.ReadTimeout) as its __cause__. |
fail_open=True |
The tool runs anyway, ungoverned, and a WARNING is logged on the gaas_agent_framework logger. |
| neither (default) | The tool does not run; GovernanceBlockedError with verdict UNEVALUATED. |
GaaSGovernanceError wraps the underlying error instead of re-raising it (as the other GaaS
plugins do) because Agent Framework turns any ordinary exception from middleware into a tool
result and keeps the run going.
Notes
- Tools the model provider runs on its side (hosted tools such as hosted web search or hosted MCP) never pass through function middleware, so GaaS cannot govern them here. Local tools, including local MCP tools, are governed.
- Intents are sent with
agent.framework = "custom", and carry the model's tool-call id and the Agent Framework session id when present, so an audit record can be matched to a run. APPROVE_MODIFIEDruns the tool with its original arguments; modifications are not applied.
Links
- Docs: https://gaas.to/sdks.html
- GaaS: https://gaas.is
Metadata
Release files for gaas-agent-framework 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gaas_agent_framework-0.1.0.tar.gz | 23.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gaas_agent_framework-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.3 kB
Release files / gaas_agent_framework-0.1.0.tar.gz
| Download URL | gaas_agent_framework-0.1.0.tar.gz |
|---|---|
| Size | 23.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e9c2c0d71644da5cce80a0f91ac9796146f69368b6261b9211446862ab6f1ec7
|
|
BLAKE2b-256 checksum How to use checksums |
08e30afc37e5ffffe40f4077bdbcb7a79f80be9e0a571ec45beb925c15ce9064
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency logRelease files / gaas_agent_framework-0.1.0-py3-none-any.whl
| Download URL | gaas_agent_framework-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3597cfc9d8831e223d43e685720b263b9f525d46e5b22210034a38edea2655d6
|
|
BLAKE2b-256 checksum How to use checksums |
546747d50e40caf3d19bb30486bfa715b6cdd3baca7da8ab432ffd9a595f43c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.
Transparency log