Skip to main content

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=True to 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_MODIFIED runs the tool with its original arguments; modifications are not applied.

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)

Source distribution for gaas-agent-framework 0.1.0
File Size Uploaded
gaas_agent_framework-0.1.0.tar.gz 23.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gaas-agent-framework 0.1.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page