openbox-langgraph-sdk-python 0.1.0__tar.gz → 0.1.2__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.
- openbox_langgraph_sdk_python-0.1.2/.gitignore +9 -0
- openbox_langgraph_sdk_python-0.1.2/AGENTS.md +91 -0
- openbox_langgraph_sdk_python-0.1.2/CLAUDE.md +91 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/PKG-INFO +195 -99
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/README.md +193 -97
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/docs/code-standards.md +5 -5
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/docs/codebase-summary.md +16 -16
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/docs/project-overview-pdr.md +7 -7
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/docs/project-roadmap.md +4 -4
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/docs/system-architecture.md +8 -8
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/config.py +4 -1
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/file_governance_hooks.py +7 -1
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/http_governance_hooks.py +32 -4
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/types.py +6 -3
- openbox_langgraph_sdk_python-0.1.2/plans/260320-0329-remove-span-collector/plan.md +121 -0
- openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-01-remove-hitl-gates.md +53 -0
- openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-02-sqlalchemy-engine.md +46 -0
- openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/phase-03-hook-hitl-retry.md +80 -0
- openbox_langgraph_sdk_python-0.1.2/plans/260321-2019-port-deepagent-fixes/plan.md +42 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-1430-comprehensive-sdk-analysis.md +1753 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-2300-file-reference.md +215 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/Explore-260330-2300-integration-guide.md +747 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-code-reuse-otel-hooks.md +206 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-efficiency-review-otel-http-hook-spans.md +193 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/code-reviewer-260323-1101-hacky-patterns-review.md +175 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/docs-manager-260321-2153-initial-documentation.md +363 -0
- openbox_langgraph_sdk_python-0.1.2/plans/reports/span-flow-visualization.html +456 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/pyproject.toml +2 -2
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/uv.lock +6 -6
- openbox_langgraph_sdk_python-0.1.0/.gitignore +0 -2
- openbox_langgraph_sdk_python-0.1.0/test-agent/.env +0 -11
- openbox_langgraph_sdk_python-0.1.0/test-agent/.env.example +0 -9
- openbox_langgraph_sdk_python-0.1.0/test-agent/README.md +0 -27
- openbox_langgraph_sdk_python-0.1.0/test-agent/SETUP.md +0 -455
- openbox_langgraph_sdk_python-0.1.0/test-agent/agent.py +0 -172
- openbox_langgraph_sdk_python-0.1.0/test-agent/pyproject.toml +0 -16
- openbox_langgraph_sdk_python-0.1.0/test-agent/uv.lock +0 -1218
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/.github/workflows/publish.yml +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/__init__.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/client.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/db_governance_hooks.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/errors.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/hitl.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/hook_governance.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/langgraph_handler.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/otel_setup.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/span_processor.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/tracing.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/openbox_langgraph/verdict_handler.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/tests/test_contextvars_propagation.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/tests/test_governance_changes.py +0 -0
- {openbox_langgraph_sdk_python-0.1.0 → openbox_langgraph_sdk_python-0.1.2}/tests/test_telemetry_payload.py +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What This Is
|
|
6
|
+
|
|
7
|
+
Python SDK (`openbox-langgraph-sdk`) that adds real-time governance to LangGraph agents via OpenBox. It intercepts LangGraph v2 stream events (tool calls, LLM prompts, chain executions), sends them to OpenBox Core's policy engine, and enforces verdicts (ALLOW/BLOCK/CONSTRAIN/REQUIRE_APPROVAL/HALT) — all without modifying agent code.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
uv sync
|
|
14
|
+
|
|
15
|
+
# Run all tests
|
|
16
|
+
pytest
|
|
17
|
+
|
|
18
|
+
# Run single test file / pattern
|
|
19
|
+
pytest tests/test_governance_changes.py
|
|
20
|
+
pytest -k "test_httpx"
|
|
21
|
+
|
|
22
|
+
# Lint & format
|
|
23
|
+
ruff check openbox_langgraph/
|
|
24
|
+
ruff format openbox_langgraph/
|
|
25
|
+
|
|
26
|
+
# Type check
|
|
27
|
+
mypy openbox_langgraph/
|
|
28
|
+
|
|
29
|
+
# Debug mode (verbose governance request/response logging)
|
|
30
|
+
OPENBOX_DEBUG=1 pytest -xvs
|
|
31
|
+
|
|
32
|
+
# Run test agent (requires .env with OPENBOX_URL, OPENBOX_API_KEY, OPENAI_API_KEY)
|
|
33
|
+
cd test-agent && uv run python agent.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
The SDK has three governance layers that intercept operations at different levels:
|
|
39
|
+
|
|
40
|
+
### Layer 1: LangGraph Event Stream (langgraph_handler.py)
|
|
41
|
+
`OpenBoxLangGraphHandler` wraps a compiled LangGraph graph. It processes the v2 event stream (`on_chain_start/end`, `on_tool_start/end`, `on_chat_model_start/end`), sends governance events to OpenBox Core via `GovernanceClient`, and enforces verdicts. This is the main entry point — users call `create_openbox_graph_handler()` (sync function, returns handler immediately) to wrap their graph.
|
|
42
|
+
|
|
43
|
+
### Layer 2: Hook Governance (http/db/file_governance_hooks.py)
|
|
44
|
+
Intercepts low-level operations using built-in instrumentation:
|
|
45
|
+
- **HTTP** (`http_governance_hooks.py`): httpx request/response hooks with started/completed stages
|
|
46
|
+
- **Database** (`db_governance_hooks.py`): SQLAlchemy event hooks for query classification
|
|
47
|
+
- **File I/O** (`file_governance_hooks.py`): Monkey-patches `os.fdopen()` for file operation tracking
|
|
48
|
+
|
|
49
|
+
Each hook module creates spans and calls `hook_governance.py` → `evaluate_event()` to get verdicts. `hook_governance.py` is the bridge that resolves the current activity context from the SpanProcessor and calls `GovernanceClient`.
|
|
50
|
+
|
|
51
|
+
### Layer 3: Activity Context (span_processor.py + otel_setup.py)
|
|
52
|
+
`WorkflowSpanProcessor` is a custom SpanProcessor that maps `trace_id` → governance `activity_id`. This lets hook-level governance (Layer 2) find which governance activity a given HTTP/DB/file operation belongs to. `otel_setup.py` initializes all instrumentation and registers the span processor.
|
|
53
|
+
|
|
54
|
+
### Supporting Modules
|
|
55
|
+
- **client.py**: Async HTTP client (`GovernanceClient`) for OpenBox Core API with dedup and connection pooling
|
|
56
|
+
- **types.py**: Verdict enum, event types, response parsing, utility functions
|
|
57
|
+
- **config.py**: `GovernanceConfig` dataclass, env var parsing, global config registry
|
|
58
|
+
- **verdict_handler.py**: Verdict enforcement logic (block/halt/redact)
|
|
59
|
+
- **hitl.py**: Human-in-the-loop approval polling loop
|
|
60
|
+
- **errors.py**: Exception hierarchy rooted at `OpenBoxError`
|
|
61
|
+
- **tracing.py**: `@traced` decorator and `create_span()` for manual span creation
|
|
62
|
+
|
|
63
|
+
### Data Flow
|
|
64
|
+
```
|
|
65
|
+
User calls governed.ainvoke()
|
|
66
|
+
→ OpenBoxLangGraphHandler streams LangGraph events
|
|
67
|
+
→ GovernanceClient sends event to OpenBox Core
|
|
68
|
+
→ Verdict received → enforce_verdict()
|
|
69
|
+
→ Meanwhile, hooks intercept HTTP/DB/file ops
|
|
70
|
+
→ hook_governance.evaluate_event() with activity context from SpanProcessor
|
|
71
|
+
→ Additional verdicts enforced at operation level
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tests
|
|
75
|
+
|
|
76
|
+
Three test files in `tests/`:
|
|
77
|
+
- `test_governance_changes.py` — core governance flow (event stream, verdicts, HITL, guardrails)
|
|
78
|
+
- `test_telemetry_payload.py` — hook payload structure and content
|
|
79
|
+
- `test_contextvars_propagation.py` — context variable propagation across async boundaries
|
|
80
|
+
|
|
81
|
+
Tests mock the OpenBox Core API; no live server needed. `pytest-asyncio` with `asyncio_mode = "auto"` means no `@pytest.mark.asyncio` decorator needed.
|
|
82
|
+
|
|
83
|
+
## Key Conventions
|
|
84
|
+
|
|
85
|
+
- **Python 3.11+**, async-first with sync fallbacks
|
|
86
|
+
- **Package manager**: `uv` (lockfile: `uv.lock`)
|
|
87
|
+
- **Build**: hatchling
|
|
88
|
+
- **Ruff config**: 100 char line length, rules: E/F/I/UP/B/C4/PIE/RUF
|
|
89
|
+
- **mypy**: strict mode
|
|
90
|
+
- Public API exported from `openbox_langgraph/__init__.py`
|
|
91
|
+
- The `test-agent/` directory is a standalone example agent for end-to-end validation, not part of the SDK package
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What This Is
|
|
6
|
+
|
|
7
|
+
Python SDK (`openbox-langgraph-sdk`) that adds real-time governance to LangGraph agents via OpenBox. It intercepts LangGraph v2 stream events (tool calls, LLM prompts, chain executions), sends them to OpenBox Core's policy engine, and enforces verdicts (ALLOW/BLOCK/CONSTRAIN/REQUIRE_APPROVAL/HALT) — all without modifying agent code.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
uv sync
|
|
14
|
+
|
|
15
|
+
# Run all tests
|
|
16
|
+
pytest
|
|
17
|
+
|
|
18
|
+
# Run single test file / pattern
|
|
19
|
+
pytest tests/test_governance_changes.py
|
|
20
|
+
pytest -k "test_httpx"
|
|
21
|
+
|
|
22
|
+
# Lint & format
|
|
23
|
+
ruff check openbox_langgraph/
|
|
24
|
+
ruff format openbox_langgraph/
|
|
25
|
+
|
|
26
|
+
# Type check
|
|
27
|
+
mypy openbox_langgraph/
|
|
28
|
+
|
|
29
|
+
# Debug mode (verbose governance request/response logging)
|
|
30
|
+
OPENBOX_DEBUG=1 pytest -xvs
|
|
31
|
+
|
|
32
|
+
# Run test agent (requires .env with OPENBOX_URL, OPENBOX_API_KEY, OPENAI_API_KEY)
|
|
33
|
+
cd test-agent && uv run python agent.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
The SDK has three governance layers that intercept operations at different levels:
|
|
39
|
+
|
|
40
|
+
### Layer 1: LangGraph Event Stream (langgraph_handler.py)
|
|
41
|
+
`OpenBoxLangGraphHandler` wraps a compiled LangGraph graph. It processes the v2 event stream (`on_chain_start/end`, `on_tool_start/end`, `on_chat_model_start/end`), sends governance events to OpenBox Core via `GovernanceClient`, and enforces verdicts. This is the main entry point — users call `create_openbox_graph_handler()` (sync function, returns handler immediately) to wrap their graph.
|
|
42
|
+
|
|
43
|
+
### Layer 2: Hook Governance (http/db/file_governance_hooks.py)
|
|
44
|
+
Intercepts low-level operations using built-in instrumentation:
|
|
45
|
+
- **HTTP** (`http_governance_hooks.py`): httpx request/response hooks with started/completed stages
|
|
46
|
+
- **Database** (`db_governance_hooks.py`): SQLAlchemy event hooks for query classification
|
|
47
|
+
- **File I/O** (`file_governance_hooks.py`): Monkey-patches `os.fdopen()` for file operation tracking
|
|
48
|
+
|
|
49
|
+
Each hook module creates spans and calls `hook_governance.py` → `evaluate_event()` to get verdicts. `hook_governance.py` is the bridge that resolves the current activity context from the SpanProcessor and calls `GovernanceClient`.
|
|
50
|
+
|
|
51
|
+
### Layer 3: Activity Context (span_processor.py + otel_setup.py)
|
|
52
|
+
`WorkflowSpanProcessor` is a custom SpanProcessor that maps `trace_id` → governance `activity_id`. This lets hook-level governance (Layer 2) find which governance activity a given HTTP/DB/file operation belongs to. `otel_setup.py` initializes all instrumentation and registers the span processor.
|
|
53
|
+
|
|
54
|
+
### Supporting Modules
|
|
55
|
+
- **client.py**: Async HTTP client (`GovernanceClient`) for OpenBox Core API with dedup and connection pooling
|
|
56
|
+
- **types.py**: Verdict enum, event types, response parsing, utility functions
|
|
57
|
+
- **config.py**: `GovernanceConfig` dataclass, env var parsing, global config registry
|
|
58
|
+
- **verdict_handler.py**: Verdict enforcement logic (block/halt/redact)
|
|
59
|
+
- **hitl.py**: Human-in-the-loop approval polling loop
|
|
60
|
+
- **errors.py**: Exception hierarchy rooted at `OpenBoxError`
|
|
61
|
+
- **tracing.py**: `@traced` decorator and `create_span()` for manual span creation
|
|
62
|
+
|
|
63
|
+
### Data Flow
|
|
64
|
+
```
|
|
65
|
+
User calls governed.ainvoke()
|
|
66
|
+
→ OpenBoxLangGraphHandler streams LangGraph events
|
|
67
|
+
→ GovernanceClient sends event to OpenBox Core
|
|
68
|
+
→ Verdict received → enforce_verdict()
|
|
69
|
+
→ Meanwhile, hooks intercept HTTP/DB/file ops
|
|
70
|
+
→ hook_governance.evaluate_event() with activity context from SpanProcessor
|
|
71
|
+
→ Additional verdicts enforced at operation level
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tests
|
|
75
|
+
|
|
76
|
+
Three test files in `tests/`:
|
|
77
|
+
- `test_governance_changes.py` — core governance flow (event stream, verdicts, HITL, guardrails)
|
|
78
|
+
- `test_telemetry_payload.py` — hook payload structure and content
|
|
79
|
+
- `test_contextvars_propagation.py` — context variable propagation across async boundaries
|
|
80
|
+
|
|
81
|
+
Tests mock the OpenBox Core API; no live server needed. `pytest-asyncio` with `asyncio_mode = "auto"` means no `@pytest.mark.asyncio` decorator needed.
|
|
82
|
+
|
|
83
|
+
## Key Conventions
|
|
84
|
+
|
|
85
|
+
- **Python 3.11+**, async-first with sync fallbacks
|
|
86
|
+
- **Package manager**: `uv` (lockfile: `uv.lock`)
|
|
87
|
+
- **Build**: hatchling
|
|
88
|
+
- **Ruff config**: 100 char line length, rules: E/F/I/UP/B/C4/PIE/RUF
|
|
89
|
+
- **mypy**: strict mode
|
|
90
|
+
- Public API exported from `openbox_langgraph/__init__.py`
|
|
91
|
+
- The `test-agent/` directory is a standalone example agent for end-to-end validation, not part of the SDK package
|