aigp-strands 1.0.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.
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
.eggs/
|
|
9
|
+
|
|
10
|
+
# Node
|
|
11
|
+
node_modules/
|
|
12
|
+
dist/
|
|
13
|
+
|
|
14
|
+
# Go
|
|
15
|
+
bin/
|
|
16
|
+
|
|
17
|
+
# Rust
|
|
18
|
+
target/
|
|
19
|
+
|
|
20
|
+
# .NET
|
|
21
|
+
bin/
|
|
22
|
+
obj/
|
|
23
|
+
|
|
24
|
+
# Java
|
|
25
|
+
*.class
|
|
26
|
+
out/
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.idea/
|
|
30
|
+
.vscode/
|
|
31
|
+
*.swp
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Secrets (never commit)
|
|
38
|
+
.env
|
|
39
|
+
*.pem
|
|
40
|
+
*.key
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""AigpGovernance — entry point for Strands agent governance."""
|
|
2
|
+
|
|
3
|
+
from aigp_agent_core import AgentGovernance
|
|
4
|
+
from .handler import AigpCallbackHandler
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AigpGovernance(AgentGovernance):
|
|
8
|
+
"""Strands-specific governance wrapper.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
governance = AigpGovernance(gov_url=..., app_id=..., hmac_secret=...)
|
|
12
|
+
agent = Agent(model=..., callback_handler=governance.callback_handler())
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def callback_handler(self) -> AigpCallbackHandler:
|
|
16
|
+
"""Create a Strands callback handler wired to this governance instance."""
|
|
17
|
+
return AigpCallbackHandler(self)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Strands Callback Handler — maps Strands lifecycle to AIGP governance."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AigpCallbackHandler:
|
|
11
|
+
"""Strands SDK callback handler implementing AIGP governance.
|
|
12
|
+
|
|
13
|
+
Attach to any Strands Agent:
|
|
14
|
+
agent = Agent(model=..., callback_handler=handler)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, governance):
|
|
18
|
+
self._gov = governance
|
|
19
|
+
self._tool_start_times: dict[str, float] = {}
|
|
20
|
+
|
|
21
|
+
def on_agent_start(self, agent_name: str, model_id: str, prompt: str, **kwargs):
|
|
22
|
+
"""Called when agent starts processing. Sends AIGP CHECK."""
|
|
23
|
+
user_id = kwargs.get("user_id", "")
|
|
24
|
+
self._gov.pre_invoke(agent_name, model_id, user_id)
|
|
25
|
+
|
|
26
|
+
def on_model_start(self, model_id: str, prompt: str, **kwargs):
|
|
27
|
+
"""Called before each model invocation within a cycle."""
|
|
28
|
+
pass # Trace stage already handled by pre_invoke
|
|
29
|
+
|
|
30
|
+
def on_model_end(self, response: str, usage: dict = None, **kwargs):
|
|
31
|
+
"""Called after model returns. Accumulates tokens."""
|
|
32
|
+
self._gov.on_model_call(usage=usage or {})
|
|
33
|
+
|
|
34
|
+
def on_tool_start(self, tool_name: str, params: dict = None, **kwargs):
|
|
35
|
+
"""Called before tool execution."""
|
|
36
|
+
self._tool_start_times[tool_name] = time.time()
|
|
37
|
+
|
|
38
|
+
def on_tool_end(self, tool_name: str, result: str = "", **kwargs):
|
|
39
|
+
"""Called after tool execution. Records tool span."""
|
|
40
|
+
start = self._tool_start_times.pop(tool_name, time.time())
|
|
41
|
+
duration_ms = int((time.time() - start) * 1000)
|
|
42
|
+
try:
|
|
43
|
+
asyncio.get_event_loop().run_until_complete(
|
|
44
|
+
self._gov.on_tool_call(tool_name, duration_ms=duration_ms, result=result)
|
|
45
|
+
)
|
|
46
|
+
except RuntimeError:
|
|
47
|
+
asyncio.run(self._gov.on_tool_call(tool_name, duration_ms=duration_ms, result=result))
|
|
48
|
+
|
|
49
|
+
def on_agent_end(self, result: str = "", **kwargs):
|
|
50
|
+
"""Called when agent completes. Sends RECORD + TRACE + evidence."""
|
|
51
|
+
try:
|
|
52
|
+
asyncio.get_event_loop().run_until_complete(self._gov.post_invoke())
|
|
53
|
+
except RuntimeError:
|
|
54
|
+
asyncio.run(self._gov.post_invoke())
|
|
55
|
+
|
|
56
|
+
def on_agent_error(self, error: Exception, **kwargs):
|
|
57
|
+
"""Called on agent error."""
|
|
58
|
+
try:
|
|
59
|
+
asyncio.get_event_loop().run_until_complete(self._gov.on_error(error))
|
|
60
|
+
except RuntimeError:
|
|
61
|
+
asyncio.run(self._gov.on_error(error))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "aigp-strands"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "AIGP governance adapter for Strands Agents SDK"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = ["aigp-agent-core>=1.0.0"]
|
|
11
|
+
|
|
12
|
+
[project.optional-dependencies]
|
|
13
|
+
otel = ["opentelemetry-api>=1.20"]
|