kevros-agent-framework 0.1.1__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.
- kevros_agent_framework-0.1.1/.gitignore +266 -0
- kevros_agent_framework-0.1.1/PKG-INFO +87 -0
- kevros_agent_framework-0.1.1/README.md +65 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/__init__.py +44 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/client.py +146 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/config.py +35 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/embedded.py +269 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/function_middleware.py +153 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/middleware.py +185 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/models.py +163 -0
- kevros_agent_framework-0.1.1/kevros_agent_framework/provider.py +30 -0
- kevros_agent_framework-0.1.1/pyproject.toml +37 -0
- kevros_agent_framework-0.1.1/tests/__init__.py +0 -0
- kevros_agent_framework-0.1.1/tests/conftest.py +27 -0
- kevros_agent_framework-0.1.1/tests/test_client.py +133 -0
- kevros_agent_framework-0.1.1/tests/test_function_middleware.py +103 -0
- kevros_agent_framework-0.1.1/tests/test_middleware.py +183 -0
- kevros_agent_framework-0.1.1/tests/test_provider.py +100 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Python cache
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
venv/
|
|
10
|
+
env/
|
|
11
|
+
.venv/
|
|
12
|
+
.env/
|
|
13
|
+
**/venv/
|
|
14
|
+
**/env/
|
|
15
|
+
|
|
16
|
+
# Logs (generated at runtime)
|
|
17
|
+
logs/*.log
|
|
18
|
+
logs/*.out
|
|
19
|
+
logs/*.jsonl
|
|
20
|
+
logs/*.bak*
|
|
21
|
+
!logs/.gitkeep
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.vscode/
|
|
25
|
+
.idea/
|
|
26
|
+
*.swp
|
|
27
|
+
*.swo
|
|
28
|
+
|
|
29
|
+
# Backups
|
|
30
|
+
*.bak
|
|
31
|
+
*.tmp
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
*:Zone.Identifier
|
|
37
|
+
|
|
38
|
+
# Runtime state (regenerated)
|
|
39
|
+
run/aar/
|
|
40
|
+
run/*.css
|
|
41
|
+
run/*.js
|
|
42
|
+
|
|
43
|
+
# Temporary
|
|
44
|
+
temp/
|
|
45
|
+
tmp/
|
|
46
|
+
nohup.out
|
|
47
|
+
|
|
48
|
+
# Demo logs
|
|
49
|
+
demo_logs/*.log
|
|
50
|
+
adapter_logs/*.log
|
|
51
|
+
*.json.json
|
|
52
|
+
|
|
53
|
+
# Security: Prevent committing private keys
|
|
54
|
+
logs/keyprobe/
|
|
55
|
+
*.raw
|
|
56
|
+
**/ml_dsa_*
|
|
57
|
+
|
|
58
|
+
# Secrets and keys (added by prod_one_click_fix)
|
|
59
|
+
.env
|
|
60
|
+
.keys/
|
|
61
|
+
keys/
|
|
62
|
+
|
|
63
|
+
# A2A Gateway runtime data (API key store, payment ledger — NEVER commit)
|
|
64
|
+
a2a_gateway/data/
|
|
65
|
+
|
|
66
|
+
# Backups and archives
|
|
67
|
+
backups/
|
|
68
|
+
logs/archive/
|
|
69
|
+
|
|
70
|
+
# Production artifacts and vaults
|
|
71
|
+
taskhawk_production/
|
|
72
|
+
taskhawk_vault/
|
|
73
|
+
vault/
|
|
74
|
+
kernel/
|
|
75
|
+
|
|
76
|
+
# WASM artifacts
|
|
77
|
+
wasm_kernel/
|
|
78
|
+
wasm_kernel.zip
|
|
79
|
+
|
|
80
|
+
# Evidence and audit files
|
|
81
|
+
taskhawk_evidence_*.json
|
|
82
|
+
commit_audit_*.md
|
|
83
|
+
|
|
84
|
+
# Runtime generated
|
|
85
|
+
run/*.json
|
|
86
|
+
run/*.npy
|
|
87
|
+
!run/.keep
|
|
88
|
+
|
|
89
|
+
# Temporary docker compose files (keep only main, prod, and autogen)
|
|
90
|
+
docker-compose.override.yml
|
|
91
|
+
docker-compose.artifact_stable.yml
|
|
92
|
+
docker-compose.enforcer_module.yml
|
|
93
|
+
docker-compose.fix_enforcer_cmd.yml
|
|
94
|
+
docker-compose.fixpkg.yml
|
|
95
|
+
docker-compose.fixrun.yml
|
|
96
|
+
docker-compose.healthfix.yml
|
|
97
|
+
docker-compose.prod.hotfix.yml
|
|
98
|
+
docker-compose.runtime.stable.yml
|
|
99
|
+
docker-compose.verify.yml
|
|
100
|
+
*.pyd
|
|
101
|
+
run/
|
|
102
|
+
logs/
|
|
103
|
+
**/node_modules/
|
|
104
|
+
frontend/dist/
|
|
105
|
+
backend/__pycache__/
|
|
106
|
+
sdk/**/__pycache__/
|
|
107
|
+
formal/states/
|
|
108
|
+
formal/tla2tools.jar
|
|
109
|
+
*.st
|
|
110
|
+
*.fp
|
|
111
|
+
|
|
112
|
+
# --- local secrets ---
|
|
113
|
+
.secrets/
|
|
114
|
+
secrets/
|
|
115
|
+
*.key
|
|
116
|
+
*.pem
|
|
117
|
+
*.hex
|
|
118
|
+
|
|
119
|
+
# --- backups / junk ---
|
|
120
|
+
*.bak
|
|
121
|
+
*.bak.*
|
|
122
|
+
*.swp
|
|
123
|
+
*.tmp
|
|
124
|
+
|
|
125
|
+
# --- large artifacts ---
|
|
126
|
+
dist/images/
|
|
127
|
+
*.tar
|
|
128
|
+
*.tgz
|
|
129
|
+
*.zip
|
|
130
|
+
publish/
|
|
131
|
+
|
|
132
|
+
# Extra safety
|
|
133
|
+
**/.keys/
|
|
134
|
+
|
|
135
|
+
# Frontend build artifacts (do not commit)
|
|
136
|
+
frontend/*.tsbuildinfo
|
|
137
|
+
frontend/vite.config.d.ts
|
|
138
|
+
frontend/vite.config.js
|
|
139
|
+
|
|
140
|
+
# Git hooks are tracked (shared across team)
|
|
141
|
+
# .githooks/ is NOT ignored - it's version-controlled
|
|
142
|
+
|
|
143
|
+
# Managed app build artifacts (root-level only, allow marketplace plans)
|
|
144
|
+
mainTemplate.json
|
|
145
|
+
!marketplace/**/plans/**/mainTemplate.json
|
|
146
|
+
!marketplace-commercial/**/plans/**/mainTemplate.json
|
|
147
|
+
!marketplace-gov/**/plans/**/mainTemplate.json
|
|
148
|
+
|
|
149
|
+
# Marketplace distribution zips (built by packaging scripts)
|
|
150
|
+
**/dist/*.zip
|
|
151
|
+
|
|
152
|
+
# local per-worktree overrides
|
|
153
|
+
.env.local
|
|
154
|
+
.vs/
|
|
155
|
+
|
|
156
|
+
# RTL verification artifacts (untracked)
|
|
157
|
+
RTL-KAT/
|
|
158
|
+
|
|
159
|
+
# Marketing and documentation (untracked)
|
|
160
|
+
website-content/
|
|
161
|
+
/agents/
|
|
162
|
+
*.pptx
|
|
163
|
+
webflow.md
|
|
164
|
+
/wsl_ram_reset.ps1
|
|
165
|
+
|
|
166
|
+
# Business documents and proposals (confidential, not for code repo)
|
|
167
|
+
proposals/
|
|
168
|
+
patents/
|
|
169
|
+
*.docx
|
|
170
|
+
!correspondence_federal/TaskHawk_CAISI_RFI_Response_*.docx
|
|
171
|
+
!TaskHawk_CAISI_RFI_Response_*.docx
|
|
172
|
+
*_ORIGINAL_BACKUP.docx
|
|
173
|
+
*.xlsx
|
|
174
|
+
!NISTIR-8596-Comments_*.xlsx
|
|
175
|
+
csv/
|
|
176
|
+
|
|
177
|
+
# Rust build artifacts
|
|
178
|
+
**/target/
|
|
179
|
+
|
|
180
|
+
# C++ build artifacts
|
|
181
|
+
cpp_enforcer/out/
|
|
182
|
+
cpp_enforcer/build/
|
|
183
|
+
cpp_enforcer/_codeql_build_dir/
|
|
184
|
+
**/CMakeFiles/
|
|
185
|
+
**/cmake-build-*/
|
|
186
|
+
|
|
187
|
+
# External repositories (cloned locally, not submodules)
|
|
188
|
+
github-mcp-server/
|
|
189
|
+
enforcer-cpp/build/
|
|
190
|
+
|
|
191
|
+
# Binary documents (not source code)
|
|
192
|
+
*.pbix
|
|
193
|
+
*.pdf
|
|
194
|
+
!website/public/research/*.pdf
|
|
195
|
+
|
|
196
|
+
# Data exports (regenerable from Azure/compliance tools)
|
|
197
|
+
ControlsExport*.csv
|
|
198
|
+
GroupsExport*.csv
|
|
199
|
+
PolicyComplianceExport*.csv
|
|
200
|
+
|
|
201
|
+
# Build output (regenerable)
|
|
202
|
+
dist/
|
|
203
|
+
dist-gov/
|
|
204
|
+
|
|
205
|
+
# Scratch markers (accidental empty files)
|
|
206
|
+
/=
|
|
207
|
+
/reading
|
|
208
|
+
/transferring
|
|
209
|
+
|
|
210
|
+
# Benchmark and analysis output
|
|
211
|
+
analyze_*/
|
|
212
|
+
benchmarks/
|
|
213
|
+
compliance_report_*.txt
|
|
214
|
+
|
|
215
|
+
# Session artifacts (notes, dumps)
|
|
216
|
+
resume_session.md
|
|
217
|
+
interesting.md
|
|
218
|
+
think_on_this.md
|
|
219
|
+
|
|
220
|
+
# Traceability generated artifacts (regenerable via tools/generate_traceability_matrix.py)
|
|
221
|
+
TRACEABILITY_MATRIX.csv
|
|
222
|
+
TRACEABILITY_MATRIX.json
|
|
223
|
+
|
|
224
|
+
# Windsurf (not used)
|
|
225
|
+
.windsurf/
|
|
226
|
+
|
|
227
|
+
# Local exploration / scratch
|
|
228
|
+
potential/
|
|
229
|
+
|
|
230
|
+
# Benchmark dataset cache (downloaded from HuggingFace, regenerable)
|
|
231
|
+
data/benchmark_cache/
|
|
232
|
+
|
|
233
|
+
# Federal contracting documents (confidential, not for code repo)
|
|
234
|
+
Federal/
|
|
235
|
+
|
|
236
|
+
# Cost analysis (business document)
|
|
237
|
+
cost-analysis.csv
|
|
238
|
+
|
|
239
|
+
# MCP server artifacts (external, packaged separately)
|
|
240
|
+
quick_xfer/
|
|
241
|
+
|
|
242
|
+
# Azure Marketplace UI definition (generated artifacts)
|
|
243
|
+
createUiDefinition.json
|
|
244
|
+
!marketplace/**/plans/**/createUiDefinition.json
|
|
245
|
+
!marketplace-commercial/**/plans/**/createUiDefinition.json
|
|
246
|
+
!marketplace-gov/**/plans/**/createUiDefinition.json
|
|
247
|
+
viewDefinition.json
|
|
248
|
+
!marketplace/**/plans/**/viewDefinition.json
|
|
249
|
+
!marketplace-commercial/**/plans/**/viewDefinition.json
|
|
250
|
+
!marketplace-gov/**/plans/**/viewDefinition.json
|
|
251
|
+
|
|
252
|
+
# PyPI recovery codes (NEVER commit)
|
|
253
|
+
PyPI-Recovery-Codes-*
|
|
254
|
+
|
|
255
|
+
# MCP registry auth tokens (NEVER commit)
|
|
256
|
+
.mcpregistry_*
|
|
257
|
+
|
|
258
|
+
# CDP API keys (NEVER commit)
|
|
259
|
+
cdp_api_key*.json
|
|
260
|
+
|
|
261
|
+
# mcp-publisher binary (downloaded tool, not source)
|
|
262
|
+
mcp-publisher
|
|
263
|
+
|
|
264
|
+
# Revenue loop runtime artifacts
|
|
265
|
+
tools/.revenue_loop_state.json
|
|
266
|
+
tools/revenue_loop.log
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kevros-agent-framework
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Kevros Governance Middleware for Microsoft Agent Framework — cryptographic authorization, intent binding, and hash-chained provenance for AI agents.
|
|
5
|
+
Project-URL: Homepage, https://taskhawktech.com
|
|
6
|
+
Project-URL: Governance Gateway, https://governance.taskhawktech.com
|
|
7
|
+
Project-URL: Agent Card, https://governance.taskhawktech.com/.well-known/agent.json
|
|
8
|
+
Author-email: TaskHawk Systems <governance@taskhawktech.com>
|
|
9
|
+
License: BSL-1.1
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: agent-framework>=1.0.0b251001
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
Requires-Dist: pydantic>=2.0.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: opentelemetry-semantic-conventions-ai==0.4.1; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
19
|
+
Provides-Extra: embedded
|
|
20
|
+
Requires-Dist: kevros>=0.3.1; extra == 'embedded'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Kevros Governance Middleware for Microsoft Agent Framework
|
|
24
|
+
|
|
25
|
+
Cryptographic authorization, intent binding, and hash-chained provenance for AI agents built on the [Microsoft Agent Framework](https://github.com/microsoft/agent-framework).
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install kevros-agent-framework
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from kevros_agent_framework import (
|
|
37
|
+
KevrosGovernanceMiddleware,
|
|
38
|
+
KevrosFunctionMiddleware,
|
|
39
|
+
KevrosConfig,
|
|
40
|
+
KevrosGovernanceClient,
|
|
41
|
+
)
|
|
42
|
+
from agent_framework import Agent
|
|
43
|
+
|
|
44
|
+
# Configure -- API key auto-provisions on first use if omitted
|
|
45
|
+
config = KevrosConfig(api_key="kvrs_...")
|
|
46
|
+
client = KevrosGovernanceClient(config)
|
|
47
|
+
|
|
48
|
+
# Attach both middleware types, sharing a single client
|
|
49
|
+
agent = Agent(
|
|
50
|
+
client=chat_client,
|
|
51
|
+
name="governed-assistant",
|
|
52
|
+
instructions="You are a helpful assistant.",
|
|
53
|
+
middleware=[
|
|
54
|
+
KevrosGovernanceMiddleware(config=config, client=client),
|
|
55
|
+
KevrosFunctionMiddleware(config=config, client=client),
|
|
56
|
+
],
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What It Does
|
|
61
|
+
|
|
62
|
+
Every agent invocation and tool call is cryptographically governed:
|
|
63
|
+
|
|
64
|
+
- **Precision decisioning** -- Each agent run is verified against governance policy (ALLOW / CLAMP / DENY) with an HMAC-signed release token
|
|
65
|
+
- **Intent binding** -- Each function call gets a cryptographic intent-to-command binding before execution
|
|
66
|
+
- **Hash-chained provenance** -- Every decision is logged to an append-only, tamper-evident ledger
|
|
67
|
+
|
|
68
|
+
## Comparison with Purview Policy Middleware
|
|
69
|
+
|
|
70
|
+
| Aspect | Purview | Kevros |
|
|
71
|
+
|--------|---------|--------|
|
|
72
|
+
| Purpose | Content-level DLP (redact PII, block topics) | Cryptographic authorization + audit evidence |
|
|
73
|
+
| Proof | None (rule-based decision) | HMAC release tokens, hash-chained provenance |
|
|
74
|
+
| Scope | Message content filtering | Action authorization, intent binding, provenance |
|
|
75
|
+
| Relationship | Complementary | Complementary |
|
|
76
|
+
|
|
77
|
+
Use both: Purview for content safety, Kevros for authorization and evidence.
|
|
78
|
+
|
|
79
|
+
## Links
|
|
80
|
+
|
|
81
|
+
- [Kevros Governance Gateway](https://governance.taskhawktech.com)
|
|
82
|
+
- [Agent Card](https://governance.taskhawktech.com/.well-known/agent.json)
|
|
83
|
+
- [Website](https://taskhawktech.com)
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
BSL-1.1 -- See LICENSE for details.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Kevros Governance Middleware for Microsoft Agent Framework
|
|
2
|
+
|
|
3
|
+
Cryptographic authorization, intent binding, and hash-chained provenance for AI agents built on the [Microsoft Agent Framework](https://github.com/microsoft/agent-framework).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install kevros-agent-framework
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from kevros_agent_framework import (
|
|
15
|
+
KevrosGovernanceMiddleware,
|
|
16
|
+
KevrosFunctionMiddleware,
|
|
17
|
+
KevrosConfig,
|
|
18
|
+
KevrosGovernanceClient,
|
|
19
|
+
)
|
|
20
|
+
from agent_framework import Agent
|
|
21
|
+
|
|
22
|
+
# Configure -- API key auto-provisions on first use if omitted
|
|
23
|
+
config = KevrosConfig(api_key="kvrs_...")
|
|
24
|
+
client = KevrosGovernanceClient(config)
|
|
25
|
+
|
|
26
|
+
# Attach both middleware types, sharing a single client
|
|
27
|
+
agent = Agent(
|
|
28
|
+
client=chat_client,
|
|
29
|
+
name="governed-assistant",
|
|
30
|
+
instructions="You are a helpful assistant.",
|
|
31
|
+
middleware=[
|
|
32
|
+
KevrosGovernanceMiddleware(config=config, client=client),
|
|
33
|
+
KevrosFunctionMiddleware(config=config, client=client),
|
|
34
|
+
],
|
|
35
|
+
)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What It Does
|
|
39
|
+
|
|
40
|
+
Every agent invocation and tool call is cryptographically governed:
|
|
41
|
+
|
|
42
|
+
- **Precision decisioning** -- Each agent run is verified against governance policy (ALLOW / CLAMP / DENY) with an HMAC-signed release token
|
|
43
|
+
- **Intent binding** -- Each function call gets a cryptographic intent-to-command binding before execution
|
|
44
|
+
- **Hash-chained provenance** -- Every decision is logged to an append-only, tamper-evident ledger
|
|
45
|
+
|
|
46
|
+
## Comparison with Purview Policy Middleware
|
|
47
|
+
|
|
48
|
+
| Aspect | Purview | Kevros |
|
|
49
|
+
|--------|---------|--------|
|
|
50
|
+
| Purpose | Content-level DLP (redact PII, block topics) | Cryptographic authorization + audit evidence |
|
|
51
|
+
| Proof | None (rule-based decision) | HMAC release tokens, hash-chained provenance |
|
|
52
|
+
| Scope | Message content filtering | Action authorization, intent binding, provenance |
|
|
53
|
+
| Relationship | Complementary | Complementary |
|
|
54
|
+
|
|
55
|
+
Use both: Purview for content safety, Kevros for authorization and evidence.
|
|
56
|
+
|
|
57
|
+
## Links
|
|
58
|
+
|
|
59
|
+
- [Kevros Governance Gateway](https://governance.taskhawktech.com)
|
|
60
|
+
- [Agent Card](https://governance.taskhawktech.com/.well-known/agent.json)
|
|
61
|
+
- [Website](https://taskhawktech.com)
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
BSL-1.1 -- See LICENSE for details.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Kevros Governance Middleware for Microsoft Agent Framework.
|
|
3
|
+
|
|
4
|
+
pip install kevros-agent-framework
|
|
5
|
+
|
|
6
|
+
Two modes:
|
|
7
|
+
Remote (default): pip install kevros-agent-framework
|
|
8
|
+
Embedded: pip install kevros-agent-framework[embedded]
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .config import KevrosConfig
|
|
12
|
+
from .client import KevrosGovernanceClient
|
|
13
|
+
from .models import (
|
|
14
|
+
Decision, IntentType, IntentSource, OutcomeStatus,
|
|
15
|
+
VerifyRequest, VerifyResponse,
|
|
16
|
+
AttestRequest, AttestResponse,
|
|
17
|
+
BindIntentRequest, BindIntentResponse,
|
|
18
|
+
VerifyOutcomeRequest, VerifyOutcomeResponse,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from .middleware import KevrosGovernanceMiddleware, GovernanceDeniedException
|
|
22
|
+
from .function_middleware import KevrosFunctionMiddleware
|
|
23
|
+
|
|
24
|
+
# Embedded provider requires gateway internals (pip install kevros-agent-framework[embedded])
|
|
25
|
+
try:
|
|
26
|
+
from .embedded import EmbeddedGovernanceProvider
|
|
27
|
+
except ImportError:
|
|
28
|
+
EmbeddedGovernanceProvider = None # type: ignore[assignment,misc]
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"KevrosConfig",
|
|
32
|
+
"KevrosGovernanceClient",
|
|
33
|
+
"KevrosGovernanceMiddleware",
|
|
34
|
+
"KevrosFunctionMiddleware",
|
|
35
|
+
"GovernanceDeniedException",
|
|
36
|
+
"EmbeddedGovernanceProvider",
|
|
37
|
+
"Decision", "IntentType", "IntentSource", "OutcomeStatus",
|
|
38
|
+
"VerifyRequest", "VerifyResponse",
|
|
39
|
+
"AttestRequest", "AttestResponse",
|
|
40
|
+
"BindIntentRequest", "BindIntentResponse",
|
|
41
|
+
"VerifyOutcomeRequest", "VerifyOutcomeResponse",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Remote governance provider -- HTTP client for the Kevros A2A Gateway.
|
|
3
|
+
|
|
4
|
+
Implements GovernanceProvider protocol. Handles auto-signup, retry,
|
|
5
|
+
and connection lifecycle. Safe to share across middleware instances.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
import httpx
|
|
16
|
+
|
|
17
|
+
from .config import KevrosConfig
|
|
18
|
+
from .models import (
|
|
19
|
+
AttestRequest, AttestResponse,
|
|
20
|
+
BindIntentRequest, BindIntentResponse,
|
|
21
|
+
SignupRequest, SignupResponse,
|
|
22
|
+
VerifyRequest, VerifyResponse,
|
|
23
|
+
VerifyOutcomeRequest, VerifyOutcomeResponse,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger("kevros.middleware")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class KevrosGovernanceClient:
|
|
30
|
+
"""
|
|
31
|
+
HTTP client for Kevros A2A Governance Gateway.
|
|
32
|
+
|
|
33
|
+
Implements GovernanceProvider protocol.
|
|
34
|
+
Use as async context manager for proper lifecycle:
|
|
35
|
+
|
|
36
|
+
async with KevrosGovernanceClient(config) as client:
|
|
37
|
+
result = await client.verify(req)
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, config: KevrosConfig) -> None:
|
|
41
|
+
self._config = config
|
|
42
|
+
self._api_key: Optional[str] = config.api_key or os.environ.get("KEVROS_API_KEY")
|
|
43
|
+
self._signup_lock = asyncio.Lock()
|
|
44
|
+
self._http = httpx.AsyncClient(
|
|
45
|
+
base_url=config.gateway_url,
|
|
46
|
+
timeout=config.timeout_seconds,
|
|
47
|
+
headers={"Content-Type": "application/json"},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def __aenter__(self) -> KevrosGovernanceClient:
|
|
51
|
+
return self
|
|
52
|
+
|
|
53
|
+
async def __aexit__(self, *args) -> None:
|
|
54
|
+
await self.close()
|
|
55
|
+
|
|
56
|
+
async def _ensure_api_key(self) -> str:
|
|
57
|
+
"""Get or create API key via auto-signup. Thread-safe."""
|
|
58
|
+
if self._api_key:
|
|
59
|
+
return self._api_key
|
|
60
|
+
|
|
61
|
+
async with self._signup_lock:
|
|
62
|
+
# Double-check after acquiring lock
|
|
63
|
+
if self._api_key:
|
|
64
|
+
return self._api_key
|
|
65
|
+
|
|
66
|
+
agent_id = self._config.agent_id or "agent-framework-agent"
|
|
67
|
+
signup_req = SignupRequest(
|
|
68
|
+
agent_id=agent_id,
|
|
69
|
+
operator_email=self._config.operator_email or "",
|
|
70
|
+
operator_name=self._config.operator_name or "",
|
|
71
|
+
)
|
|
72
|
+
resp = await self._http.post(
|
|
73
|
+
"/signup",
|
|
74
|
+
json=signup_req.model_dump(exclude_none=True),
|
|
75
|
+
)
|
|
76
|
+
resp.raise_for_status()
|
|
77
|
+
signup_resp = SignupResponse.model_validate(resp.json())
|
|
78
|
+
self._api_key = signup_resp.api_key
|
|
79
|
+
logger.info(
|
|
80
|
+
"Kevros auto-signup complete: agent_id=%s tier=%s limit=%d",
|
|
81
|
+
agent_id, signup_resp.tier, signup_resp.monthly_limit,
|
|
82
|
+
)
|
|
83
|
+
return self._api_key
|
|
84
|
+
|
|
85
|
+
async def _request_with_retry(
|
|
86
|
+
self, method: str, path: str, json_body: dict
|
|
87
|
+
) -> httpx.Response:
|
|
88
|
+
"""Make an authenticated request with retry logic."""
|
|
89
|
+
api_key = await self._ensure_api_key()
|
|
90
|
+
headers = {"X-API-Key": api_key}
|
|
91
|
+
|
|
92
|
+
last_exc: Optional[Exception] = None
|
|
93
|
+
for attempt in range(1 + self._config.max_retries):
|
|
94
|
+
try:
|
|
95
|
+
resp = await self._http.request(
|
|
96
|
+
method, path, json=json_body, headers=headers,
|
|
97
|
+
)
|
|
98
|
+
resp.raise_for_status()
|
|
99
|
+
return resp
|
|
100
|
+
except (httpx.ConnectError, httpx.TimeoutException, httpx.HTTPStatusError) as exc:
|
|
101
|
+
last_exc = exc
|
|
102
|
+
# Don't retry on 4xx client errors (except 429)
|
|
103
|
+
if isinstance(exc, httpx.HTTPStatusError) and 400 <= exc.response.status_code < 500 and exc.response.status_code != 429:
|
|
104
|
+
raise
|
|
105
|
+
if attempt < self._config.max_retries:
|
|
106
|
+
await asyncio.sleep(self._config.retry_backoff_seconds * (attempt + 1))
|
|
107
|
+
|
|
108
|
+
raise last_exc # type: ignore[misc]
|
|
109
|
+
|
|
110
|
+
async def verify(self, request: VerifyRequest) -> VerifyResponse:
|
|
111
|
+
resp = await self._request_with_retry(
|
|
112
|
+
"POST", "/governance/verify",
|
|
113
|
+
request.model_dump(exclude_none=True),
|
|
114
|
+
)
|
|
115
|
+
return VerifyResponse.model_validate(resp.json())
|
|
116
|
+
|
|
117
|
+
async def attest(self, request: AttestRequest) -> AttestResponse:
|
|
118
|
+
resp = await self._request_with_retry(
|
|
119
|
+
"POST", "/governance/attest",
|
|
120
|
+
request.model_dump(exclude_none=True),
|
|
121
|
+
)
|
|
122
|
+
return AttestResponse.model_validate(resp.json())
|
|
123
|
+
|
|
124
|
+
async def bind_intent(self, request: BindIntentRequest) -> BindIntentResponse:
|
|
125
|
+
resp = await self._request_with_retry(
|
|
126
|
+
"POST", "/governance/bind",
|
|
127
|
+
request.model_dump(exclude_none=True),
|
|
128
|
+
)
|
|
129
|
+
return BindIntentResponse.model_validate(resp.json())
|
|
130
|
+
|
|
131
|
+
async def verify_outcome(self, request: VerifyOutcomeRequest) -> VerifyOutcomeResponse:
|
|
132
|
+
resp = await self._request_with_retry(
|
|
133
|
+
"POST", "/governance/verify-outcome",
|
|
134
|
+
request.model_dump(exclude_none=True),
|
|
135
|
+
)
|
|
136
|
+
return VerifyOutcomeResponse.model_validate(resp.json())
|
|
137
|
+
|
|
138
|
+
async def health(self) -> bool:
|
|
139
|
+
try:
|
|
140
|
+
resp = await self._http.get("/governance/health")
|
|
141
|
+
return resp.status_code == 200
|
|
142
|
+
except httpx.HTTPError:
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
async def close(self) -> None:
|
|
146
|
+
await self._http.aclose()
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Kevros middleware configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True)
|
|
10
|
+
class KevrosConfig:
|
|
11
|
+
"""Immutable configuration for Kevros governance middleware."""
|
|
12
|
+
|
|
13
|
+
# Gateway connection
|
|
14
|
+
gateway_url: str = "https://governance.taskhawktech.com"
|
|
15
|
+
api_key: Optional[str] = None # kvrs_... key. If None, auto-signup on first use.
|
|
16
|
+
|
|
17
|
+
# Behavior
|
|
18
|
+
fail_closed: bool = True # Block agent on gateway errors
|
|
19
|
+
log_decisions: bool = True # Log governance decisions to stderr
|
|
20
|
+
timeout_seconds: float = 5.0 # HTTP timeout per request
|
|
21
|
+
max_retries: int = 1 # Retries before declaring gateway unreachable (0 = no retry)
|
|
22
|
+
retry_backoff_seconds: float = 0.5 # Backoff between retries
|
|
23
|
+
|
|
24
|
+
# Intent binding
|
|
25
|
+
bind_intents: bool = True # Enable function middleware intent binding
|
|
26
|
+
record_outcomes: bool = True # Record function results as outcomes
|
|
27
|
+
|
|
28
|
+
# Agent identity
|
|
29
|
+
agent_id: Optional[str] = None # Override agent ID (defaults to agent name)
|
|
30
|
+
agent_namespace: Optional[str] = None # Organizational namespace
|
|
31
|
+
operator_name: Optional[str] = None # Legal entity name for signup
|
|
32
|
+
operator_email: Optional[str] = None # Contact email for signup
|
|
33
|
+
|
|
34
|
+
# Mode
|
|
35
|
+
embedded: bool = False # If True, use local GatewayServices instead of HTTP
|