agentgovern 2.2.1__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentgovern-2.2.1 → agentgovern-2.4.0}/.gitignore +7 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/CHANGELOG.md +128 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/PKG-INFO +50 -29
- {agentgovern-2.2.1 → agentgovern-2.4.0}/README.md +46 -10
- agentgovern-2.4.0/RELEASING.md +72 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/__init__.py +55 -12
- agentgovern-2.4.0/agentgovern/_version.py +1 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/client.py +8 -1
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/data/hook.py +30 -5
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/drift.py +22 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/installer.py +124 -43
- {agentgovern-2.2.1 → agentgovern-2.4.0}/pyproject.toml +15 -6
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_context_snapshot.py +22 -4
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_payloads.py +77 -20
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_installer.py +151 -45
- agentgovern-2.4.0/tests/hook/test_matcher_coverage.py +115 -0
- agentgovern-2.4.0/tests/hook/test_tool_map_classification.py +68 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_client.py +40 -4
- agentgovern-2.4.0/tests/test_import_guard.py +222 -0
- agentgovern-2.4.0/tests/test_langchain_1x_agent.py +166 -0
- agentgovern-2.4.0/tests/test_policy_engine_url.py +79 -0
- agentgovern-2.2.1/RELEASING.md +0 -63
- agentgovern-2.2.1/agentgovern/_version.py +0 -1
- {agentgovern-2.2.1 → agentgovern-2.4.0}/LICENSE +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/__main__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/exceptions.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/gate2.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/cli.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/data/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/hook/settings.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/instrumentors/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/instrumentors/_base.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/instrumentors/langchain.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/instrumentors/langgraph.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentgovern/types.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentshield/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentshield/client.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/agentshield/types.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/examples/langgraph_credit_decision_agent.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/__init__.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/conftest.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_bundled_hook.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_drift.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_dispatch.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_outbox_queue.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_payload_extraction.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_remediation_message.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_timing_log.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_transcript_reading.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_turn_index.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_hook_v2_warn_verdict.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/hook/test_settings.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_base_instrumentor.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_evaluate_input.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_gate2_full_path.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_gate2_latency.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_gate2_verdict_handler.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_instrument_langchain.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_langchain.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_langchain_gate1.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_langchain_gate2_callbacks.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_langgraph.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_output_capture_contract.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_payload_schema.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_rate_limit_handling.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_register_contract.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_timestamp.py +0 -0
- {agentgovern-2.2.1 → agentgovern-2.4.0}/tests/test_version_consistency.py +0 -0
|
@@ -32,6 +32,13 @@ test-results/
|
|
|
32
32
|
# Not project config — skills/ and agents/ under .claude/ remain tracked.
|
|
33
33
|
.claude/settings.json
|
|
34
34
|
.claude/settings.local.json
|
|
35
|
+
# Backups of the above, which carry the same content and the same reason to stay
|
|
36
|
+
# untracked. Added 2026-08-21: the exact-filename rules above do not match a
|
|
37
|
+
# `.bak-*` sibling, so a pre-change backup sat untracked-but-not-ignored inside
|
|
38
|
+
# the repo, where a `git add -A` would have staged it — and, with both `ask`
|
|
39
|
+
# arrays now empty, without prompting.
|
|
40
|
+
.claude/settings.json.bak-*
|
|
41
|
+
.claude/settings.local.json.bak-*
|
|
35
42
|
|
|
36
43
|
.vercel
|
|
37
44
|
|
|
@@ -1,5 +1,133 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.4.0 — release date is the `sdk-v2.4.0` tag's (prepared 2026-09-30)
|
|
4
|
+
|
|
5
|
+
### Change — the SDK reaches the policy engine at a stable name, `https://engine.zirahn.com`
|
|
6
|
+
|
|
7
|
+
`evaluate_input()` (Gate 1) and Gate 2's output checks call the policy engine
|
|
8
|
+
directly. **Versions 2.3.0 and earlier call it at
|
|
9
|
+
`https://agentgovern.onrender.com`, a hostname Render issued for one specific
|
|
10
|
+
service.** Render cannot move a service to another region: a new service
|
|
11
|
+
means a new hostname. So an SDK pinned to that name cannot follow the engine
|
|
12
|
+
if it moves.
|
|
13
|
+
|
|
14
|
+
- The default `policy_engine_url` is now **`https://engine.zirahn.com`**. It
|
|
15
|
+
is a custom domain pointing at the same engine today, so **latency and
|
|
16
|
+
behaviour are unchanged**. What changes is that a future move of the engine
|
|
17
|
+
needs no SDK release.
|
|
18
|
+
- **2.3.0 and earlier keep working.** `agentgovern.onrender.com` still
|
|
19
|
+
serves the same engine, and it will not be removed while any supported
|
|
20
|
+
version defaults to it. Upgrading moves you to the stable name:
|
|
21
|
+
`pip install --upgrade agentgovern`.
|
|
22
|
+
- **Overrides are unchanged.** The `policy_engine_url` argument to `init()`,
|
|
23
|
+
then the `AGENTGOVERN_POLICY_ENGINE_URL` environment variable, still take
|
|
24
|
+
precedence over the default. **If you set either yourself, you are not
|
|
25
|
+
affected.**
|
|
26
|
+
- The Claude Code hook is unaffected. It reaches the engine through the
|
|
27
|
+
dashboard's API, not directly.
|
|
28
|
+
|
|
29
|
+
## 2.3.0 — release date is the `sdk-v2.3.0` tag's (prepared 2026-09-29)
|
|
30
|
+
|
|
31
|
+
### Security — the Claude Code hook now sees every tool call, but only after you reinstall it (NAGT-187)
|
|
32
|
+
|
|
33
|
+
Until this release, `agentgovern hook install` registered the hook for a fixed
|
|
34
|
+
list of tools (ten in 2.2.1: `Bash`, `Write`, `Edit`, `MultiEdit`,
|
|
35
|
+
`NotebookEdit`, `Read`, `Glob`, `Grep`, `WebFetch`, `WebSearch`). **A tool call
|
|
36
|
+
through any other tool never reached the hook, so no policy was applied to
|
|
37
|
+
it.** On Windows, Claude Code's `PowerShell` tool was one such tool: every
|
|
38
|
+
content rule could be bypassed by routing a command through it.
|
|
39
|
+
|
|
40
|
+
- The `PreToolUse` and `PostToolUse` matchers are now `*`: every tool,
|
|
41
|
+
including tools that do not exist yet.
|
|
42
|
+
- `PowerShell` is classified like `Bash` (`execute` / `code_execution`).
|
|
43
|
+
- A tool the hook has no classification for is recorded as
|
|
44
|
+
`action_type="unmapped_tool"`. Before, it was recorded as `"custom"`, the
|
|
45
|
+
value the SDK reserves for your own `track_action()` calls. **A policy that
|
|
46
|
+
relied on `"custom"` as a catch-all for unknown tools needs
|
|
47
|
+
`"unmapped_tool"` added.**
|
|
48
|
+
- The bundled hook script is version 2.3.0.
|
|
49
|
+
|
|
50
|
+
> **Action required for existing installs.** Upgrading the package does not
|
|
51
|
+
> change a hook that is already installed. Until you reinstall it, the hook
|
|
52
|
+
> keeps its old tool list:
|
|
53
|
+
>
|
|
54
|
+
> ```bash
|
|
55
|
+
> pip install --upgrade agentgovern
|
|
56
|
+
> agentgovern hook install --force # repeat --capture-mode=minimal, --matcher or --python-command if you used them
|
|
57
|
+
> agentgovern hook status # no [DRIFT] lines once it is current
|
|
58
|
+
> ```
|
|
59
|
+
>
|
|
60
|
+
> Then restart any running Claude Code session. `--force` writes the current
|
|
61
|
+
> defaults and does not remember options from the earlier install, so pass
|
|
62
|
+
> them again. Without `--capture-mode=minimal`, it turns a minimal install
|
|
63
|
+
> into a full one.
|
|
64
|
+
|
|
65
|
+
### Change — `hook install` tells you when an existing hook is stale (NAGT-200)
|
|
66
|
+
|
|
67
|
+
Before, running `agentgovern hook install` against an existing hook said
|
|
68
|
+
*"already installed"*, even when that hook was out of date. It now adds which
|
|
69
|
+
matcher, timeout or script version differs from what this package would
|
|
70
|
+
write, and says to re-run with `--force`. **It still does not upgrade the
|
|
71
|
+
hook itself.** The exit code and every refusal are unchanged, and `--force`
|
|
72
|
+
is still required to write anything.
|
|
73
|
+
|
|
74
|
+
### Fix — `httpx` and `pydantic` are now required dependencies (NAGT-324)
|
|
75
|
+
|
|
76
|
+
`pip install agentgovern` installed no dependencies at all. The package
|
|
77
|
+
imported cleanly, but 13 of its 23 public names, including `ActionType`,
|
|
78
|
+
`ActionStatus` and `AgentGovernClient`, were bound to `None`. `init()` raised
|
|
79
|
+
a clear `ImportError`, so any documented integration failed loudly at
|
|
80
|
+
startup. But `register_agent()`, `track_action()` and `shutdown()` return
|
|
81
|
+
silently when the SDK is uninitialised, so an integration that skipped or
|
|
82
|
+
swallowed `init()` recorded nothing and reported nothing.
|
|
83
|
+
|
|
84
|
+
This affected every release from 0.2.0 through 2.2.1. LangChain and LangGraph
|
|
85
|
+
users were unaffected in practice: `langchain-core` depends on both `httpx`
|
|
86
|
+
and `pydantic`, so those extras' own dependencies supplied them.
|
|
87
|
+
|
|
88
|
+
- `httpx>=0.27.0` and `pydantic>=2.10.0` are now unconditional dependencies.
|
|
89
|
+
A bare install now also brings in their own dependencies: `anyio`,
|
|
90
|
+
`certifi`, `h11`, `httpcore`, `idna`, `pydantic-core`, `annotated-types`,
|
|
91
|
+
`typing-extensions` and `typing-inspection`.
|
|
92
|
+
- **`python-dotenv` is removed.** No module in the package ever imported it.
|
|
93
|
+
If you relied on `agentgovern[sdk]` to install it, add it directly.
|
|
94
|
+
- The `[sdk]` extra is kept, now empty, so `pip install "agentgovern[sdk]"`,
|
|
95
|
+
`[langchain]` and `[langgraph]` keep working unchanged, with no pip warning.
|
|
96
|
+
- The import guard still catches any `ImportError`, so the hook CLI keeps
|
|
97
|
+
working in a `pip install --no-deps` or half-installed environment. **What
|
|
98
|
+
changed is the message:** `init()` now reports the error that actually
|
|
99
|
+
occurred. Before, it always told you to install the `[sdk]` extra, even
|
|
100
|
+
when that extra was already installed and something else had failed.
|
|
101
|
+
- `init()`'s docstring now says what the fail-silent promise covers
|
|
102
|
+
(AgentGovern being *unreachable* once initialised). It also says what it
|
|
103
|
+
does not cover (the SDK being absent or misconfigured), and why `init()`
|
|
104
|
+
should not be wrapped in a bare `except`.
|
|
105
|
+
|
|
106
|
+
### Docs
|
|
107
|
+
|
|
108
|
+
- The LangChain samples in this README are updated for langchain 1.x, which
|
|
109
|
+
removed `AgentExecutor` and `create_openai_tools_agent`. They now use
|
|
110
|
+
`langchain.agents.create_agent` and pass the handler as
|
|
111
|
+
`config={"callbacks": [handler]}`. A new test runs such an agent and
|
|
112
|
+
confirms the handler's callbacks fire.
|
|
113
|
+
- New README section: *Upgrading an existing install*.
|
|
114
|
+
|
|
115
|
+
### Internal (not part of the installed package)
|
|
116
|
+
|
|
117
|
+
- A new release gate: the wheel is built, its declared dependencies are
|
|
118
|
+
checked, and it is installed into a clean environment and imported before
|
|
119
|
+
it is uploaded. This runs on every pull request and in the publish workflow
|
|
120
|
+
itself.
|
|
121
|
+
- `langchain>=1.0.0` added to the `dev` extra, for the new test.
|
|
122
|
+
- Test fixes that make the suite trustworthy rather than change behaviour:
|
|
123
|
+
- NAGT-280: a test that pinned the hook version to the stale literal
|
|
124
|
+
`2.1.0` is removed; the test that checks the snapshot against the
|
|
125
|
+
module's own version stays;
|
|
126
|
+
- NAGT-326: Stop-hook tests no longer assume the temp directory is inside
|
|
127
|
+
`$HOME`;
|
|
128
|
+
- NAGT-327: the buffer-cap test is deterministic, with no live flush thread
|
|
129
|
+
and no network.
|
|
130
|
+
|
|
3
131
|
## 2.2.1 — 2026-08-13
|
|
4
132
|
|
|
5
133
|
### Fix — `register_agent()` silently no-op'd when called immediately after `init()`, the SDK's own documented call pattern (STORY-109)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agentgovern
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Compliance-as-code middleware for agentic AI workflows.
|
|
5
5
|
Project-URL: Homepage, https://agentgovern.zirahn.com
|
|
6
6
|
Project-URL: Repository, https://github.com/ahmedkhan-zirahn/agentgovern
|
|
@@ -20,40 +20,25 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Topic :: System :: Monitoring
|
|
22
22
|
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: httpx>=0.27.0
|
|
24
|
+
Requires-Dist: pydantic>=2.10.0
|
|
23
25
|
Provides-Extra: crewai
|
|
24
26
|
Requires-Dist: crewai>=0.80.0; extra == 'crewai'
|
|
25
|
-
Requires-Dist: httpx>=0.27.0; extra == 'crewai'
|
|
26
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'crewai'
|
|
27
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'crewai'
|
|
28
27
|
Provides-Extra: dev
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: langchain>=1.0.0; extra == 'dev'
|
|
31
29
|
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
32
30
|
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
33
31
|
Requires-Dist: pytest>=8.3.0; extra == 'dev'
|
|
34
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
|
|
35
32
|
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
36
33
|
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
37
34
|
Provides-Extra: langchain
|
|
38
|
-
Requires-Dist: httpx>=0.27.0; extra == 'langchain'
|
|
39
35
|
Requires-Dist: langchain-core>=0.3.0; extra == 'langchain'
|
|
40
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'langchain'
|
|
41
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'langchain'
|
|
42
36
|
Provides-Extra: langgraph
|
|
43
|
-
Requires-Dist: httpx>=0.27.0; extra == 'langgraph'
|
|
44
37
|
Requires-Dist: langchain-core>=0.3.0; extra == 'langgraph'
|
|
45
38
|
Requires-Dist: langgraph<2.0.0,>=0.2.0; extra == 'langgraph'
|
|
46
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'langgraph'
|
|
47
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'langgraph'
|
|
48
39
|
Provides-Extra: openai
|
|
49
|
-
Requires-Dist: httpx>=0.27.0; extra == 'openai'
|
|
50
40
|
Requires-Dist: openai>=1.50.0; extra == 'openai'
|
|
51
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'openai'
|
|
52
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'openai'
|
|
53
41
|
Provides-Extra: sdk
|
|
54
|
-
Requires-Dist: httpx>=0.27.0; extra == 'sdk'
|
|
55
|
-
Requires-Dist: pydantic>=2.10.0; extra == 'sdk'
|
|
56
|
-
Requires-Dist: python-dotenv>=1.0.0; extra == 'sdk'
|
|
57
42
|
Description-Content-Type: text/markdown
|
|
58
43
|
|
|
59
44
|
# AgentGovern Python SDK
|
|
@@ -74,7 +59,7 @@ pip install "agentgovern[langchain]"
|
|
|
74
59
|
|
|
75
60
|
```python
|
|
76
61
|
import agentgovern
|
|
77
|
-
from langchain.agents import
|
|
62
|
+
from langchain.agents import create_agent
|
|
78
63
|
from langchain_openai import ChatOpenAI
|
|
79
64
|
|
|
80
65
|
# 1. Initialize once at startup
|
|
@@ -94,12 +79,13 @@ agentgovern.register_agent(
|
|
|
94
79
|
# 3. Get the callback handler — binds to credit-scoring-v2 automatically
|
|
95
80
|
handler = agentgovern.instrument_langchain()
|
|
96
81
|
|
|
97
|
-
# 4.
|
|
98
|
-
|
|
99
|
-
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
100
|
-
executor = AgentExecutor(agent=agent, tools=tools, callbacks=[handler])
|
|
82
|
+
# 4. Build the agent and pass the handler via config — no other changes needed
|
|
83
|
+
agent = create_agent(model=ChatOpenAI(model="gpt-4o"), tools=tools)
|
|
101
84
|
|
|
102
|
-
result =
|
|
85
|
+
result = agent.invoke(
|
|
86
|
+
{"messages": [{"role": "user", "content": "Evaluate loan application for customer #12345"}]},
|
|
87
|
+
config={"callbacks": [handler]},
|
|
88
|
+
)
|
|
103
89
|
```
|
|
104
90
|
|
|
105
91
|
`instrument_langchain()` binds to the most recently registered agent. Every tool call,
|
|
@@ -154,8 +140,11 @@ agentgovern.register_agent("kyc-agent", name="KYC Agent")
|
|
|
154
140
|
handler_fraud = agentgovern.instrument_langchain("fraud-detector")
|
|
155
141
|
handler_kyc = agentgovern.instrument_langchain("kyc-agent")
|
|
156
142
|
|
|
157
|
-
|
|
158
|
-
|
|
143
|
+
fraud_agent = create_agent(model=..., tools=...)
|
|
144
|
+
kyc_agent = create_agent(model=..., tools=...)
|
|
145
|
+
|
|
146
|
+
fraud_agent.invoke(inputs, config={"callbacks": [handler_fraud]})
|
|
147
|
+
kyc_agent.invoke(inputs, config={"callbacks": [handler_kyc]})
|
|
159
148
|
```
|
|
160
149
|
|
|
161
150
|
## Manual instrumentation (all frameworks)
|
|
@@ -201,13 +190,22 @@ Enable policy packs from the [AgentGovern dashboard](https://agentgovern.zirahn.
|
|
|
201
190
|
| `api_key` | required | SDK ingest key from the dashboard |
|
|
202
191
|
| `base_url` | `https://agentgovern.zirahn.com` | API endpoint |
|
|
203
192
|
| `environment` | `"production"` | `"production"` \| `"staging"` \| `"development"` |
|
|
193
|
+
| `policy_engine_url` | `https://engine.zirahn.com` | Policy engine endpoint for Gate 1 (`evaluate_input`) and Gate 2 checks. Override with this argument or the `AGENTGOVERN_POLICY_ENGINE_URL` env var |
|
|
204
194
|
| `fail_silently` | `True` | If `True`, SDK errors never raise into your agent |
|
|
205
195
|
|
|
196
|
+
**Policy engine address (2.4.0).** The default engine address is now the stable name
|
|
197
|
+
`https://engine.zirahn.com`. Versions 2.3.0 and earlier call `https://agentgovern.onrender.com`
|
|
198
|
+
directly. That address keeps working, so nothing breaks if you stay on an older version, but only
|
|
199
|
+
the stable name can follow the engine if it moves. Upgrade with `pip install --upgrade agentgovern`.
|
|
200
|
+
If you set `policy_engine_url` or `AGENTGOVERN_POLICY_ENGINE_URL` yourself, it still takes precedence.
|
|
201
|
+
|
|
206
202
|
## Claude Code Hook
|
|
207
203
|
|
|
208
204
|
The SDK ships a built-in CLI for installing the AgentGovern hook into Claude Code. The hook
|
|
209
|
-
intercepts `PreToolUse` events and enforces your tenant policies in real
|
|
210
|
-
|
|
205
|
+
intercepts `PreToolUse` events for every tool call and enforces your tenant policies in real
|
|
206
|
+
time — before the tool executes. A tool AgentGovern doesn't yet have a specific classification
|
|
207
|
+
for is still captured and evaluated, tagged `action_type=unmapped_tool` rather than silently
|
|
208
|
+
skipped.
|
|
211
209
|
|
|
212
210
|
### Install
|
|
213
211
|
|
|
@@ -219,6 +217,29 @@ This deploys the hook script to `~/.agentgovern/hook.py`, merges the correct ent
|
|
|
219
217
|
`~/.claude/settings.json` (with an atomic backup), and prints instructions for any missing
|
|
220
218
|
env vars.
|
|
221
219
|
|
|
220
|
+
### Upgrading an existing install
|
|
221
|
+
|
|
222
|
+
Upgrading the package does **not** update a hook that is already installed. `hook install`
|
|
223
|
+
copies the hook script to `~/.agentgovern/hook.py` and writes its entries into
|
|
224
|
+
`~/.claude/settings.json`, and a plain `agentgovern hook install` against an existing install
|
|
225
|
+
reports it as already installed and changes nothing. After upgrading, reinstall with `--force`:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pip install --upgrade agentgovern # or the extra you installed with, e.g. "agentgovern[langchain]"
|
|
229
|
+
agentgovern hook install --force
|
|
230
|
+
agentgovern hook status # reports no [DRIFT] lines once the hook is current
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`--force` writes the current defaults. It does not remember options from the earlier install: if
|
|
234
|
+
you installed with `--capture-mode=minimal`, `--matcher` or `--python-command`, pass them again —
|
|
235
|
+
`--force` without `--capture-mode=minimal` turns a minimal install into a full one.
|
|
236
|
+
Your environment variables are not touched. Restart any running Claude Code session afterwards.
|
|
237
|
+
|
|
238
|
+
**If your hook was installed by 2.2.1 or earlier, this step matters for coverage, not just
|
|
239
|
+
freshness.** Those versions wrote a `PreToolUse` matcher naming a fixed list of tools (ten, in 2.2.1), so a call
|
|
240
|
+
through any other tool (`PowerShell`, for example) never reached the hook. Starting with 2.3.0
|
|
241
|
+
the matcher is `*`, every tool — but only once `hook install --force` has rewritten the entry.
|
|
242
|
+
|
|
222
243
|
### Required env vars
|
|
223
244
|
|
|
224
245
|
```bash
|
|
@@ -16,7 +16,7 @@ pip install "agentgovern[langchain]"
|
|
|
16
16
|
|
|
17
17
|
```python
|
|
18
18
|
import agentgovern
|
|
19
|
-
from langchain.agents import
|
|
19
|
+
from langchain.agents import create_agent
|
|
20
20
|
from langchain_openai import ChatOpenAI
|
|
21
21
|
|
|
22
22
|
# 1. Initialize once at startup
|
|
@@ -36,12 +36,13 @@ agentgovern.register_agent(
|
|
|
36
36
|
# 3. Get the callback handler — binds to credit-scoring-v2 automatically
|
|
37
37
|
handler = agentgovern.instrument_langchain()
|
|
38
38
|
|
|
39
|
-
# 4.
|
|
40
|
-
|
|
41
|
-
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
42
|
-
executor = AgentExecutor(agent=agent, tools=tools, callbacks=[handler])
|
|
39
|
+
# 4. Build the agent and pass the handler via config — no other changes needed
|
|
40
|
+
agent = create_agent(model=ChatOpenAI(model="gpt-4o"), tools=tools)
|
|
43
41
|
|
|
44
|
-
result =
|
|
42
|
+
result = agent.invoke(
|
|
43
|
+
{"messages": [{"role": "user", "content": "Evaluate loan application for customer #12345"}]},
|
|
44
|
+
config={"callbacks": [handler]},
|
|
45
|
+
)
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
`instrument_langchain()` binds to the most recently registered agent. Every tool call,
|
|
@@ -96,8 +97,11 @@ agentgovern.register_agent("kyc-agent", name="KYC Agent")
|
|
|
96
97
|
handler_fraud = agentgovern.instrument_langchain("fraud-detector")
|
|
97
98
|
handler_kyc = agentgovern.instrument_langchain("kyc-agent")
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
fraud_agent = create_agent(model=..., tools=...)
|
|
101
|
+
kyc_agent = create_agent(model=..., tools=...)
|
|
102
|
+
|
|
103
|
+
fraud_agent.invoke(inputs, config={"callbacks": [handler_fraud]})
|
|
104
|
+
kyc_agent.invoke(inputs, config={"callbacks": [handler_kyc]})
|
|
101
105
|
```
|
|
102
106
|
|
|
103
107
|
## Manual instrumentation (all frameworks)
|
|
@@ -143,13 +147,22 @@ Enable policy packs from the [AgentGovern dashboard](https://agentgovern.zirahn.
|
|
|
143
147
|
| `api_key` | required | SDK ingest key from the dashboard |
|
|
144
148
|
| `base_url` | `https://agentgovern.zirahn.com` | API endpoint |
|
|
145
149
|
| `environment` | `"production"` | `"production"` \| `"staging"` \| `"development"` |
|
|
150
|
+
| `policy_engine_url` | `https://engine.zirahn.com` | Policy engine endpoint for Gate 1 (`evaluate_input`) and Gate 2 checks. Override with this argument or the `AGENTGOVERN_POLICY_ENGINE_URL` env var |
|
|
146
151
|
| `fail_silently` | `True` | If `True`, SDK errors never raise into your agent |
|
|
147
152
|
|
|
153
|
+
**Policy engine address (2.4.0).** The default engine address is now the stable name
|
|
154
|
+
`https://engine.zirahn.com`. Versions 2.3.0 and earlier call `https://agentgovern.onrender.com`
|
|
155
|
+
directly. That address keeps working, so nothing breaks if you stay on an older version, but only
|
|
156
|
+
the stable name can follow the engine if it moves. Upgrade with `pip install --upgrade agentgovern`.
|
|
157
|
+
If you set `policy_engine_url` or `AGENTGOVERN_POLICY_ENGINE_URL` yourself, it still takes precedence.
|
|
158
|
+
|
|
148
159
|
## Claude Code Hook
|
|
149
160
|
|
|
150
161
|
The SDK ships a built-in CLI for installing the AgentGovern hook into Claude Code. The hook
|
|
151
|
-
intercepts `PreToolUse` events and enforces your tenant policies in real
|
|
152
|
-
|
|
162
|
+
intercepts `PreToolUse` events for every tool call and enforces your tenant policies in real
|
|
163
|
+
time — before the tool executes. A tool AgentGovern doesn't yet have a specific classification
|
|
164
|
+
for is still captured and evaluated, tagged `action_type=unmapped_tool` rather than silently
|
|
165
|
+
skipped.
|
|
153
166
|
|
|
154
167
|
### Install
|
|
155
168
|
|
|
@@ -161,6 +174,29 @@ This deploys the hook script to `~/.agentgovern/hook.py`, merges the correct ent
|
|
|
161
174
|
`~/.claude/settings.json` (with an atomic backup), and prints instructions for any missing
|
|
162
175
|
env vars.
|
|
163
176
|
|
|
177
|
+
### Upgrading an existing install
|
|
178
|
+
|
|
179
|
+
Upgrading the package does **not** update a hook that is already installed. `hook install`
|
|
180
|
+
copies the hook script to `~/.agentgovern/hook.py` and writes its entries into
|
|
181
|
+
`~/.claude/settings.json`, and a plain `agentgovern hook install` against an existing install
|
|
182
|
+
reports it as already installed and changes nothing. After upgrading, reinstall with `--force`:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
pip install --upgrade agentgovern # or the extra you installed with, e.g. "agentgovern[langchain]"
|
|
186
|
+
agentgovern hook install --force
|
|
187
|
+
agentgovern hook status # reports no [DRIFT] lines once the hook is current
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`--force` writes the current defaults. It does not remember options from the earlier install: if
|
|
191
|
+
you installed with `--capture-mode=minimal`, `--matcher` or `--python-command`, pass them again —
|
|
192
|
+
`--force` without `--capture-mode=minimal` turns a minimal install into a full one.
|
|
193
|
+
Your environment variables are not touched. Restart any running Claude Code session afterwards.
|
|
194
|
+
|
|
195
|
+
**If your hook was installed by 2.2.1 or earlier, this step matters for coverage, not just
|
|
196
|
+
freshness.** Those versions wrote a `PreToolUse` matcher naming a fixed list of tools (ten, in 2.2.1), so a call
|
|
197
|
+
through any other tool (`PowerShell`, for example) never reached the hook. Starting with 2.3.0
|
|
198
|
+
the matcher is `*`, every tool — but only once `hook install --force` has rewritten the entry.
|
|
199
|
+
|
|
164
200
|
### Required env vars
|
|
165
201
|
|
|
166
202
|
```bash
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Releasing agentgovern to PyPI
|
|
2
|
+
|
|
3
|
+
Releases are automated via `.github/workflows/publish-sdk.yml` using PyPI trusted publishing (OIDC — no API tokens needed). Pushing a `sdk-v*` tag triggers a build and publish automatically.
|
|
4
|
+
|
|
5
|
+
## Prerequisites (one-time PyPI setup)
|
|
6
|
+
|
|
7
|
+
Before the first automated publish, configure trusted publishing on PyPI:
|
|
8
|
+
|
|
9
|
+
1. Go to https://pypi.org/manage/project/agentgovern/settings/publishing/
|
|
10
|
+
2. Add a new trusted publisher with these exact values:
|
|
11
|
+
|
|
12
|
+
| Field | Value |
|
|
13
|
+
|-------------------|------------------------------|
|
|
14
|
+
| Owner | ZirahnAI |
|
|
15
|
+
| Repository name | agentgovern |
|
|
16
|
+
| Workflow filename | publish-sdk.yml |
|
|
17
|
+
| Environment name | pypi |
|
|
18
|
+
|
|
19
|
+
**Note:** the repository moved from `ahmedkhan-zirahn` to `ZirahnAI` in September 2026. A publisher for the old owner existed and was **deleted on 2026-09-14**. A trusted publisher that names a path the organisation no longer controls is a standing binding to a namespace someone else could later claim. See NAGT-314 in `docs/ROADMAP.md`.
|
|
20
|
+
|
|
21
|
+
3. Save. No API token needed after this.
|
|
22
|
+
|
|
23
|
+
Also create the `pypi` environment in GitHub, and restrict it to release tags:
|
|
24
|
+
- Go to https://github.com/ZirahnAI/agentgovern/settings/environments
|
|
25
|
+
- Create the environment named `pypi`.
|
|
26
|
+
- Under **Deployment branches and tags**, choose **Selected branches and tags** and add a **tag** rule `sdk-v*`. The publish job carries `environment: pypi`, so it can only run from an `sdk-v*` tag.
|
|
27
|
+
- **Required reviewers is not available here.** GitHub offers it for environments in private repositories only on Enterprise, and this repository is private on the Team plan (operator-confirmed 2026-09-30). So the publish does not pause for approval. **Pushing the tag is the release decision.**
|
|
28
|
+
- Optionally, add a repository **tag ruleset** on `refs/tags/sdk-v*` that restricts creation to admins. One named "sdk release tags" exists. It was **not enforced** when checked on 2026-09-30, so it has no effect until its enforcement is set to Active.
|
|
29
|
+
|
|
30
|
+
Check the environment with `gh api repos/ZirahnAI/agentgovern/environments/pypi/deployment-branch-policies`, which should list `{"name": "sdk-v*", "type": "tag"}`.
|
|
31
|
+
|
|
32
|
+
## Release steps
|
|
33
|
+
|
|
34
|
+
1. **Bump the version** in two places:
|
|
35
|
+
```
|
|
36
|
+
packages/sdk-python/agentgovern/_version.py → __version__ = "0.X.Y"
|
|
37
|
+
packages/sdk-python/pyproject.toml → version = "0.X.Y"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **Add a CHANGELOG entry** (if `CHANGELOG.md` exists) describing what changed.
|
|
41
|
+
|
|
42
|
+
3. **Commit the version bump:**
|
|
43
|
+
```bash
|
|
44
|
+
git add packages/sdk-python/agentgovern/_version.py packages/sdk-python/pyproject.toml
|
|
45
|
+
git commit -m "chore(sdk): bump version to 0.X.Y"
|
|
46
|
+
git push
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
4. **Tag the merged commit and push that one tag.** Never `git push --tags`, which pushes every local tag, and any stray `sdk-v*` among them would publish:
|
|
50
|
+
```bash
|
|
51
|
+
git fetch origin
|
|
52
|
+
git tag sdk-v0.X.Y <merged-commit-sha>
|
|
53
|
+
git push origin sdk-v0.X.Y
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The `publish-sdk.yml` workflow triggers on the tag push. It builds, checks the wheel's declared dependencies, installs that exact wheel in a clean venv, and then publishes to PyPI. **There is no approval step** (see above). PyPI never accepts a version twice, so a mistaken tag uses up that version for good.
|
|
57
|
+
|
|
58
|
+
5. **Verify** at https://pypi.org/project/agentgovern/ — the new version should appear within a few minutes.
|
|
59
|
+
|
|
60
|
+
## Manual fallback (workflow_dispatch)
|
|
61
|
+
|
|
62
|
+
To re-run a publish after a failed run, trigger the workflow manually **from the release tag**:
|
|
63
|
+
|
|
64
|
+
1. Go to https://github.com/ZirahnAI/agentgovern/actions/workflows/publish-sdk.yml
|
|
65
|
+
2. Click **Run workflow**, choose the **tag** `sdk-v0.X.Y` under "Use workflow from", then **Run workflow**.
|
|
66
|
+
|
|
67
|
+
**A run dispatched from `main` (or any branch) cannot publish.** Its build job runs, but the publish job targets the `pypi` environment, which only accepts `sdk-v*` tags. That comes from the environment restriction above, per GitHub's documented behaviour; it has not been tested by dispatching from `main`. The run publishes whatever version `pyproject.toml` says at that ref.
|
|
68
|
+
|
|
69
|
+
## Trusted-publisher history
|
|
70
|
+
|
|
71
|
+
- **2026-09-14:** run `34876650141` (dispatched from `main`) authenticated through the `ZirahnAI/agentgovern` publisher. PyPI then refused to re-upload 2.2.1 (`400 File already exists`), so the run's conclusion was `failure`.
|
|
72
|
+
- **2026-09-30:** 2.3.0 was the first version published end to end from the `ZirahnAI` repository, by run `36667118357` from tag `sdk-v2.3.0`.
|
|
@@ -29,9 +29,23 @@ from typing import Any
|
|
|
29
29
|
|
|
30
30
|
from agentgovern._version import __version__
|
|
31
31
|
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
32
|
+
# httpx and pydantic are REQUIRED dependencies (NAGT-324). A normal
|
|
33
|
+
# `pip install agentgovern` always has them, so this guard is not the
|
|
34
|
+
# optional-extra switch it used to be.
|
|
35
|
+
#
|
|
36
|
+
# It still exists for one case: an install that deliberately suppressed
|
|
37
|
+
# dependency resolution (`pip install --no-deps`), or one that is broken or
|
|
38
|
+
# half-finished. In those, the Claude Code hook CLI -- which is stdlib-only
|
|
39
|
+
# all the way down -- must keep working, and it cannot, because importing
|
|
40
|
+
# `agentgovern.__main__` imports THIS module first.
|
|
41
|
+
#
|
|
42
|
+
# The catch stays BROAD on purpose. Narrowing it to `_exc.name in ("httpx",
|
|
43
|
+
# "pydantic")` was tried and withdrawn: ImportError.name is the INNERMOST
|
|
44
|
+
# missing module, so a broken `pydantic_core` (a compiled wheel, and one of
|
|
45
|
+
# pydantic's most common real failures) reports 'pydantic_core', gets
|
|
46
|
+
# re-raised, and takes the hook CLI down in exactly the case this guard is
|
|
47
|
+
# for. What was actually wrong was the DIAGNOSTIC, not the breadth -- so the
|
|
48
|
+
# exception is recorded and `_require_sdk()` reports what really happened.
|
|
35
49
|
try:
|
|
36
50
|
from agentgovern.client import AgentGovernClient
|
|
37
51
|
from agentgovern.exceptions import (
|
|
@@ -51,8 +65,10 @@ try:
|
|
|
51
65
|
)
|
|
52
66
|
|
|
53
67
|
_SDK_AVAILABLE = True
|
|
54
|
-
|
|
68
|
+
_SDK_IMPORT_ERROR: ImportError | None = None
|
|
69
|
+
except ImportError as _exc:
|
|
55
70
|
_SDK_AVAILABLE = False
|
|
71
|
+
_SDK_IMPORT_ERROR = _exc
|
|
56
72
|
# Provide placeholder names so `from agentgovern import X` fails at call
|
|
57
73
|
# time with a clear message rather than at import time.
|
|
58
74
|
AgentGovernClient = None # type: ignore[assignment,misc]
|
|
@@ -71,12 +87,29 @@ except ImportError:
|
|
|
71
87
|
|
|
72
88
|
|
|
73
89
|
def _require_sdk() -> None:
|
|
90
|
+
"""Raise if the SDK half of this package could not be imported.
|
|
91
|
+
|
|
92
|
+
The message is derived from the exception actually raised, never assumed.
|
|
93
|
+
Before NAGT-324 this always said "install agentgovern[sdk]", which was
|
|
94
|
+
wrong whenever the real cause was anything else -- it told people to
|
|
95
|
+
install a dependency that was, in those cases, already installed.
|
|
96
|
+
"""
|
|
74
97
|
if not _SDK_AVAILABLE:
|
|
98
|
+
_missing = getattr(_SDK_IMPORT_ERROR, "name", None)
|
|
99
|
+
if _missing in ("httpx", "pydantic"):
|
|
100
|
+
raise ImportError(
|
|
101
|
+
f"The AgentGovern SDK requires {_missing}, which is not "
|
|
102
|
+
f"importable. It is a declared dependency, so this usually "
|
|
103
|
+
f"means the install skipped dependency resolution "
|
|
104
|
+
f"(pip install --no-deps) or is incomplete. Reinstall with: "
|
|
105
|
+
f"pip install --force-reinstall agentgovern"
|
|
106
|
+
) from _SDK_IMPORT_ERROR
|
|
75
107
|
raise ImportError(
|
|
76
|
-
"The AgentGovern SDK
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
|
|
108
|
+
f"The AgentGovern SDK failed to load: {_SDK_IMPORT_ERROR!r}. "
|
|
109
|
+
f"This is NOT a missing optional extra -- the installation is "
|
|
110
|
+
f"broken or incomplete. Reinstall with: "
|
|
111
|
+
f"pip install --force-reinstall agentgovern"
|
|
112
|
+
) from _SDK_IMPORT_ERROR
|
|
80
113
|
|
|
81
114
|
|
|
82
115
|
_client: AgentGovernClient | None = None
|
|
@@ -100,8 +133,17 @@ def init(
|
|
|
100
133
|
Initialize the AgentGovern SDK.
|
|
101
134
|
|
|
102
135
|
Must be called once at application startup before any other SDK calls.
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
|
|
137
|
+
The fail-silent contract covers AgentGovern being UNREACHABLE: once the
|
|
138
|
+
SDK is initialised, network errors, timeouts and policy-engine failures
|
|
139
|
+
are discarded rather than raised into your agent.
|
|
140
|
+
|
|
141
|
+
It does NOT cover AgentGovern being absent or misconfigured. This function
|
|
142
|
+
raises if the SDK's dependencies cannot be imported, and it is the only
|
|
143
|
+
place that failure is reported — do not wrap this call in a bare
|
|
144
|
+
``except``. If it raises, the SDK is not installed correctly and no action
|
|
145
|
+
will be recorded; ``status()`` returns ``{"initialized": False}`` for as
|
|
146
|
+
long as that is true.
|
|
105
147
|
|
|
106
148
|
Args:
|
|
107
149
|
api_key: SDK ingest key from the dashboard.
|
|
@@ -109,8 +151,9 @@ def init(
|
|
|
109
151
|
base_url: Vercel deployment URL (action ingest + agent registration).
|
|
110
152
|
policy_engine_url: Render policy engine URL (Gate 1 evaluate/input).
|
|
111
153
|
Defaults to ``AGENTGOVERN_POLICY_ENGINE_URL`` env var, then
|
|
112
|
-
``https://
|
|
113
|
-
fail_silently: If ``True``, SDK errors never raise into your agent
|
|
154
|
+
``https://engine.zirahn.com``.
|
|
155
|
+
fail_silently: If ``True``, SDK errors never raise into your agent,
|
|
156
|
+
after initialisation. It does not affect this function.
|
|
114
157
|
"""
|
|
115
158
|
_require_sdk()
|
|
116
159
|
global _client # noqa: PLW0603
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.4.0"
|
|
@@ -53,6 +53,13 @@ def _iso_timestamp_utc(dt: datetime | None = None) -> str:
|
|
|
53
53
|
return dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{dt.microsecond // 1000:03d}Z"
|
|
54
54
|
|
|
55
55
|
|
|
56
|
+
# The policy engine's stable name. SDK <= 2.3.0 defaulted to the Render-issued
|
|
57
|
+
# hostname https://agentgovern.onrender.com, which names one Render service and
|
|
58
|
+
# cannot follow the engine to a new one (Render cannot change a service's
|
|
59
|
+
# region: docs/audit-reports/engine-region-move-phase1-2026-09-30.md). A custom
|
|
60
|
+
# domain can be re-pointed, so a future engine move needs no SDK release.
|
|
61
|
+
DEFAULT_POLICY_ENGINE_URL = "https://engine.zirahn.com"
|
|
62
|
+
|
|
56
63
|
_FLUSH_INTERVAL = 1.0 # seconds between automatic flushes
|
|
57
64
|
_BATCH_SIZE = 100 # flush early when buffer hits this
|
|
58
65
|
_BUFFER_MAXLEN = 10_000 # drop oldest when full
|
|
@@ -107,7 +114,7 @@ class AgentGovernClient:
|
|
|
107
114
|
self.policy_engine_url = (
|
|
108
115
|
policy_engine_url
|
|
109
116
|
or os.environ.get("AGENTGOVERN_POLICY_ENGINE_URL")
|
|
110
|
-
or
|
|
117
|
+
or DEFAULT_POLICY_ENGINE_URL
|
|
111
118
|
).rstrip("/")
|
|
112
119
|
self.fail_silently = fail_silently
|
|
113
120
|
self.batch_size = batch_size
|