openbox-langgraph-sdk-python 0.2.0__tar.gz → 1.1.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.
Files changed (157) hide show
  1. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.coverage +0 -0
  2. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.github/workflows/pr-quality.yml +1 -1
  3. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.github/workflows/publish.yml +1 -1
  4. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.gitignore +4 -1
  5. openbox_langgraph_sdk_python-1.1.0/CHANGELOG.md +77 -0
  6. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/CLAUDE.md +4 -2
  7. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/PKG-INFO +58 -13
  8. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/README.md +53 -10
  9. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/coverage.xml +1709 -1216
  10. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/.env.example +16 -0
  11. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/.gitignore +5 -0
  12. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/AGENTS.md +43 -0
  13. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/README.md +68 -0
  14. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/pyproject.toml +31 -0
  15. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/skills/blog-post/SKILL.md +126 -0
  16. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/skills/social-media/SKILL.md +177 -0
  17. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/__init__.py +1 -0
  18. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/agent.py +74 -0
  19. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/main.py +101 -0
  20. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/paths.py +10 -0
  21. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/prompt.py +77 -0
  22. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/tools_content.py +84 -0
  23. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/src/demo_04_content_builder_langgraph/tools_fs.py +63 -0
  24. openbox_langgraph_sdk_python-1.1.0/demo/demo_04_content_builder_langgraph/uv.lock +2143 -0
  25. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/__init__.py +5 -0
  26. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/activity_context_binding.py +126 -0
  27. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/client.py +259 -51
  28. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/config.py +86 -1
  29. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/core_adapter.py +228 -0
  30. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/core_events.py +141 -0
  31. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/core_runtime.py +175 -0
  32. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/errors.py +30 -1
  33. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/identity.py +51 -27
  34. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/langgraph_handler.py +839 -301
  35. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/langgraph_hook_runtime.py +210 -0
  36. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/otel_setup.py +36 -0
  37. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/span_processor.py +18 -6
  38. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/tool_activity_binding.py +339 -0
  39. openbox_langgraph_sdk_python-1.1.0/openbox_langgraph/trace_context_registry.py +197 -0
  40. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/tracing.py +7 -127
  41. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/types.py +168 -9
  42. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/pyproject.toml +19 -2
  43. openbox_langgraph_sdk_python-1.1.0/tests/conftest.py +69 -0
  44. openbox_langgraph_sdk_python-1.1.0/tests/golden/README.md +171 -0
  45. openbox_langgraph_sdk_python-1.1.0/tests/golden/__init__.py +6 -0
  46. openbox_langgraph_sdk_python-1.1.0/tests/golden/capture_harness.py +177 -0
  47. openbox_langgraph_sdk_python-1.1.0/tests/golden/chain_completed.normalized.json +60 -0
  48. openbox_langgraph_sdk_python-1.1.0/tests/golden/chain_completed.raw.json +60 -0
  49. openbox_langgraph_sdk_python-1.1.0/tests/golden/chain_started.handbuilt_serialization_pin.normalized.json +17 -0
  50. openbox_langgraph_sdk_python-1.1.0/tests/golden/chain_started.handbuilt_serialization_pin.raw.json +17 -0
  51. openbox_langgraph_sdk_python-1.1.0/tests/golden/fake_agent_graphs.py +125 -0
  52. openbox_langgraph_sdk_python-1.1.0/tests/golden/generate_fixtures.py +135 -0
  53. openbox_langgraph_sdk_python-1.1.0/tests/golden/graph_capture_harness.py +196 -0
  54. openbox_langgraph_sdk_python-1.1.0/tests/golden/headers_signed.normalized.json +34 -0
  55. openbox_langgraph_sdk_python-1.1.0/tests/golden/headers_signed.raw.json +34 -0
  56. openbox_langgraph_sdk_python-1.1.0/tests/golden/headers_unsigned.normalized.json +24 -0
  57. openbox_langgraph_sdk_python-1.1.0/tests/golden/headers_unsigned.raw.json +24 -0
  58. openbox_langgraph_sdk_python-1.1.0/tests/golden/id_normalization.py +135 -0
  59. openbox_langgraph_sdk_python-1.1.0/tests/golden/layer1_handbuilt_pins.py +71 -0
  60. openbox_langgraph_sdk_python-1.1.0/tests/golden/llm_completed.normalized.json +29 -0
  61. openbox_langgraph_sdk_python-1.1.0/tests/golden/llm_completed.raw.json +29 -0
  62. openbox_langgraph_sdk_python-1.1.0/tests/golden/llm_started.normalized.json +18 -0
  63. openbox_langgraph_sdk_python-1.1.0/tests/golden/llm_started.raw.json +18 -0
  64. openbox_langgraph_sdk_python-1.1.0/tests/golden/ordering_single_llm_turn.json +22 -0
  65. openbox_langgraph_sdk_python-1.1.0/tests/golden/ordering_tool_call_turn.json +38 -0
  66. openbox_langgraph_sdk_python-1.1.0/tests/golden/ordering_two_llm_calls_turn.json +30 -0
  67. openbox_langgraph_sdk_python-1.1.0/tests/golden/real_emitted_event_fixtures.py +136 -0
  68. openbox_langgraph_sdk_python-1.1.0/tests/golden/signal_received.normalized.json +16 -0
  69. openbox_langgraph_sdk_python-1.1.0/tests/golden/signal_received.raw.json +16 -0
  70. openbox_langgraph_sdk_python-1.1.0/tests/golden/subagent_tool_completed.normalized.json +30 -0
  71. openbox_langgraph_sdk_python-1.1.0/tests/golden/subagent_tool_completed.raw.json +30 -0
  72. openbox_langgraph_sdk_python-1.1.0/tests/golden/subagent_tool_started.normalized.json +31 -0
  73. openbox_langgraph_sdk_python-1.1.0/tests/golden/subagent_tool_started.raw.json +31 -0
  74. openbox_langgraph_sdk_python-1.1.0/tests/golden/tool_completed.normalized.json +28 -0
  75. openbox_langgraph_sdk_python-1.1.0/tests/golden/tool_completed.raw.json +28 -0
  76. openbox_langgraph_sdk_python-1.1.0/tests/golden/tool_started.normalized.json +23 -0
  77. openbox_langgraph_sdk_python-1.1.0/tests/golden/tool_started.raw.json +23 -0
  78. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_completed_error_close.normalized.json +14 -0
  79. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_completed_error_close.raw.json +14 -0
  80. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_failed.handbuilt_serialization_pin.normalized.json +16 -0
  81. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_failed.handbuilt_serialization_pin.raw.json +16 -0
  82. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_started.normalized.json +26 -0
  83. openbox_langgraph_sdk_python-1.1.0/tests/golden/workflow_started.raw.json +26 -0
  84. openbox_langgraph_sdk_python-1.1.0/tests/test_activity_context_binding.py +688 -0
  85. openbox_langgraph_sdk_python-1.1.0/tests/test_approval_strict_parsing.py +76 -0
  86. openbox_langgraph_sdk_python-1.1.0/tests/test_client_shim_compat.py +99 -0
  87. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/tests/test_config_client_core.py +4 -2
  88. openbox_langgraph_sdk_python-1.1.0/tests/test_config_resolution_precedence.py +29 -0
  89. openbox_langgraph_sdk_python-1.1.0/tests/test_context_cleanup_on_error.py +341 -0
  90. openbox_langgraph_sdk_python-1.1.0/tests/test_context_fallback_task_and_thread.py +194 -0
  91. openbox_langgraph_sdk_python-1.1.0/tests/test_context_turn_isolation.py +315 -0
  92. openbox_langgraph_sdk_python-1.1.0/tests/test_core_conformance_suite.py +173 -0
  93. openbox_langgraph_sdk_python-1.1.0/tests/test_core_context_binding.py +361 -0
  94. openbox_langgraph_sdk_python-1.1.0/tests/test_core_events_envelopes.py +299 -0
  95. openbox_langgraph_sdk_python-1.1.0/tests/test_core_runtime_config.py +126 -0
  96. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/tests/test_did_client_signing.py +0 -43
  97. openbox_langgraph_sdk_python-1.1.0/tests/test_fail_open_block_preserved.py +113 -0
  98. openbox_langgraph_sdk_python-1.1.0/tests/test_framework_adapter_translation.py +247 -0
  99. openbox_langgraph_sdk_python-1.1.0/tests/test_gate_error_translation.py +136 -0
  100. openbox_langgraph_sdk_python-1.1.0/tests/test_golden_baseline.py +214 -0
  101. openbox_langgraph_sdk_python-1.1.0/tests/test_governance_changes.py +158 -0
  102. openbox_langgraph_sdk_python-1.1.0/tests/test_halt_run_isolation.py +157 -0
  103. openbox_langgraph_sdk_python-1.1.0/tests/test_hook_approval_retry.py +242 -0
  104. openbox_langgraph_sdk_python-1.1.0/tests/test_hook_context_pinning.py +128 -0
  105. openbox_langgraph_sdk_python-1.1.0/tests/test_hook_family_exclusivity.py +207 -0
  106. openbox_langgraph_sdk_python-1.1.0/tests/test_langchain_callback_dedup.py +522 -0
  107. openbox_langgraph_sdk_python-1.1.0/tests/test_langchain_callback_llm_context.py +531 -0
  108. openbox_langgraph_sdk_python-1.1.0/tests/test_langchain_callback_tool_ordering.py +391 -0
  109. openbox_langgraph_sdk_python-1.1.0/tests/test_lifecycle_golden_parity.py +158 -0
  110. openbox_langgraph_sdk_python-1.1.0/tests/test_loop_liveness_on_sync_approval.py +131 -0
  111. openbox_langgraph_sdk_python-1.1.0/tests/test_public_exports_baseline.py +116 -0
  112. openbox_langgraph_sdk_python-1.1.0/tests/test_recording_client_seam.py +64 -0
  113. openbox_langgraph_sdk_python-1.1.0/tests/test_signed_headers_parity.py +74 -0
  114. openbox_langgraph_sdk_python-1.1.0/tests/test_types_hook_core.py +98 -0
  115. openbox_langgraph_sdk_python-1.1.0/tests/test_version_static.py +53 -0
  116. openbox_langgraph_sdk_python-1.1.0/tests/test_workload_identity.py +500 -0
  117. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/uv.lock +241 -117
  118. openbox_langgraph_sdk_python-0.2.0/openbox_langgraph/db_governance_hooks.py +0 -897
  119. openbox_langgraph_sdk_python-0.2.0/openbox_langgraph/file_governance_hooks.py +0 -419
  120. openbox_langgraph_sdk_python-0.2.0/openbox_langgraph/hook_governance.py +0 -424
  121. openbox_langgraph_sdk_python-0.2.0/openbox_langgraph/http_governance_hooks.py +0 -723
  122. openbox_langgraph_sdk_python-0.2.0/openbox_langgraph/otel_setup.py +0 -477
  123. openbox_langgraph_sdk_python-0.2.0/plans/260320-0329-remove-span-collector/plan.md +0 -121
  124. openbox_langgraph_sdk_python-0.2.0/plans/260321-2019-port-deepagent-fixes/phase-01-remove-hitl-gates.md +0 -53
  125. openbox_langgraph_sdk_python-0.2.0/plans/260321-2019-port-deepagent-fixes/phase-02-sqlalchemy-engine.md +0 -46
  126. openbox_langgraph_sdk_python-0.2.0/plans/260321-2019-port-deepagent-fixes/phase-03-hook-hitl-retry.md +0 -80
  127. openbox_langgraph_sdk_python-0.2.0/plans/260321-2019-port-deepagent-fixes/plan.md +0 -42
  128. openbox_langgraph_sdk_python-0.2.0/plans/reports/Explore-260330-1430-comprehensive-sdk-analysis.md +0 -1753
  129. openbox_langgraph_sdk_python-0.2.0/plans/reports/Explore-260330-2300-file-reference.md +0 -215
  130. openbox_langgraph_sdk_python-0.2.0/plans/reports/Explore-260330-2300-integration-guide.md +0 -747
  131. openbox_langgraph_sdk_python-0.2.0/plans/reports/code-reviewer-260323-1101-code-reuse-otel-hooks.md +0 -206
  132. openbox_langgraph_sdk_python-0.2.0/plans/reports/code-reviewer-260323-1101-efficiency-review-otel-http-hook-spans.md +0 -193
  133. openbox_langgraph_sdk_python-0.2.0/plans/reports/code-reviewer-260323-1101-hacky-patterns-review.md +0 -175
  134. openbox_langgraph_sdk_python-0.2.0/plans/reports/docs-manager-260321-2153-initial-documentation.md +0 -363
  135. openbox_langgraph_sdk_python-0.2.0/plans/reports/span-flow-visualization.html +0 -456
  136. openbox_langgraph_sdk_python-0.2.0/tests/test_governance_changes.py +0 -279
  137. openbox_langgraph_sdk_python-0.2.0/tests/test_telemetry_payload.py +0 -333
  138. openbox_langgraph_sdk_python-0.2.0/tests/test_types_hook_core.py +0 -214
  139. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.github/CODEOWNERS +0 -0
  140. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.github/workflows/pr-governance.yml +0 -0
  141. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.github/workflows/pr-security.yml +0 -0
  142. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/.gitleaks.toml +0 -0
  143. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/AGENTS.md +0 -0
  144. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/CODE_OF_CONDUCT.md +0 -0
  145. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/LICENSE +0 -0
  146. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/SECURITY.md +0 -0
  147. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/docs/code-standards.md +0 -0
  148. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/docs/codebase-summary.md +0 -0
  149. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/docs/project-overview-pdr.md +0 -0
  150. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/docs/project-roadmap.md +0 -0
  151. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/docs/system-architecture.md +0 -0
  152. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/hitl.py +0 -0
  153. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/openbox_langgraph/verdict_handler.py +0 -0
  154. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/sonar-project.properties +0 -0
  155. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/tests/test_agent_identity.py +0 -0
  156. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/tests/test_contextvars_propagation.py +0 -0
  157. {openbox_langgraph_sdk_python-0.2.0 → openbox_langgraph_sdk_python-1.1.0}/tests/test_verdict_span_hitl_core.py +0 -0
@@ -165,7 +165,7 @@ jobs:
165
165
  id: sonarqube_quality_gate
166
166
  if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
167
167
  continue-on-error: true
168
- uses: SonarSource/sonarqube-quality-gate-action@master
168
+ uses: SonarSource/sonarqube-quality-gate-action@v1.2.0
169
169
  with:
170
170
  pollingTimeoutSec: 600
171
171
  env:
@@ -342,7 +342,7 @@ jobs:
342
342
  id: sonarqube_quality_gate
343
343
  if: ${{ env.SONAR_TOKEN != '' && env.SONAR_HOST_URL != '' }}
344
344
  continue-on-error: true
345
- uses: SonarSource/sonarqube-quality-gate-action@master
345
+ uses: SonarSource/sonarqube-quality-gate-action@v1.2.0
346
346
  with:
347
347
  pollingTimeoutSec: 600
348
348
  env:
@@ -7,4 +7,7 @@ build/
7
7
  .idea/
8
8
  .DS_Store
9
9
  repomix-output.xml
10
- .vscode/
10
+ .vscode/
11
+ _notes/
12
+ plans/
13
+ .claude/
@@ -0,0 +1,77 @@
1
+ # Changelog
2
+
3
+ ## 1.1.0
4
+
5
+ - Upgrade `openbox-sdk-python` to `>=1.4.0` for IAM v3 workload identity. Keep
6
+ `openbox-langchain-sdk-python` at `>=1.0.0` (locked to 1.0.0).
7
+ - Update locked AnyIO to 4.14.2 and urllib3 to 2.8.0 in the SDK and demo, plus
8
+ pyasn1 to 0.6.4 in the demo, to address Trivy's critical/high findings.
9
+ - Add `workload_private_key` to initialization, graph creation, runtime creation,
10
+ and standalone governance clients, with framework/global environment support
11
+ during initialization and runtime creation.
12
+ - Delegate workload bootstrap, token exchange, caching, and refresh to the base
13
+ SDK. Reuse the handler's runtime client for validation, sync/raw evaluation,
14
+ and approval polling alongside callbacks and operation hooks.
15
+ - Preserve authentication, signing, and bootstrap/configuration errors under
16
+ fail-open policies. Export `OpenBoxSigningError` with Core's `reason_code`.
17
+ - Preserve legacy DID/API-key configuration and the base SDK's explicit
18
+ no-workload-authority fallback for rolling upgrades.
19
+
20
+ ## 0.3.0
21
+
22
+ Migrates the SDK onto the shared `openbox-sdk-python` (`openbox_core`) governance
23
+ core. The public API (classes, functions, `initialize()` signature, DID signing)
24
+ is preserved; the changes below are internal rewiring plus a small, deliberate
25
+ set of wire and semantic changes, each regression-gated by a reproducible
26
+ golden-payload oracle.
27
+
28
+ ### Changed — wire protocol (lifecycle events)
29
+
30
+ - Lifecycle events (`SignalReceived`, `WorkflowStarted`/`Completed`,
31
+ `LLMStarted`/`Completed`, `ToolStarted`/`Completed`) now serialize through the
32
+ shared `openbox_core` `EventEnvelope` + strict gate instead of hand-built
33
+ request bodies. The wire body is byte-identical to before **except** three
34
+ compatibility-noise fields the base envelope omits by construction and no
35
+ longer sends for lifecycle events: `hook_trigger: false`, `spans: []`,
36
+ `span_count: 0`. Core treats an absent `hook_trigger` as `false`; this is the
37
+ same envelope format the Temporal SDK already ships to Core.
38
+ - Lifecycle-event requests now carry the base SDK's `User-Agent`; hook-triggered
39
+ requests keep `OpenBox-LangGraph-SDK/<version>`.
40
+
41
+ ### Changed — semantics
42
+
43
+ - **Approval parsing is action-first and strict.** When both are present the
44
+ `action` field now wins over `verdict` (was verdict-first). An unknown or
45
+ empty approval response resolves to *pending* (keeps polling) — never an
46
+ implicit approve. The previous lenient "unknown → allow" fallback at the
47
+ human-approval boundary is removed.
48
+ - **Hook-level HITL approval retry now runs governed.** After an approval is
49
+ granted, the pending abort state is cleared on both the base and legacy stores
50
+ before the graph re-invokes. Previously the stale abort flag re-blocked the
51
+ approved retry (`clear_activity_abort` had no caller) — a genuine bug, now
52
+ fixed.
53
+ - **Fail-open is precise.** A governance transport/parse failure surfaces as
54
+ "no verdict" (fail-open, unchanged) only for a genuine client-synthesized
55
+ fallback; a real blocking verdict that happens to carry `fallback_used: true`
56
+ still enforces.
57
+ - Expired-approval-before-allow ordering is unchanged (an expired approval
58
+ raises even when allow-shaped).
59
+
60
+ ### Added
61
+
62
+ - **`use_core_instrumentation`** config flag (default `False`). When enabled,
63
+ covered hook families (`http`, `dbapi`, `asyncpg`, `sqlalchemy`, `file`) are
64
+ governed through the shared `openbox_core` hook runtime while uncovered
65
+ families (`urllib`, `urllib3`, `redis`, `mongo`) stay on the legacy hooks —
66
+ each operation governed exactly once. Approval on this path is raise-only and
67
+ never blocks the event loop. Per-family flips (making the core runtime the
68
+ default for a family) remain follow-up work.
69
+ - `openbox_langgraph.__version__`.
70
+ - `multi_agent_session_id` config/handler option (distinct from `session_id`).
71
+ - Dependency on `openbox-sdk-python` (the shared governance core).
72
+
73
+ ### Preserved (regression-gated)
74
+
75
+ DID request signing (byte-identical `X-OpenBox-Agent-*` headers), the
76
+ `(activity_id, event_type)` de-dup, transient-failure PII redaction, the
77
+ public `client=` injection seam, and every public class/function signature.
@@ -37,8 +37,10 @@ cd test-agent && uv run python agent.py
37
37
 
38
38
  The SDK has three governance layers that intercept operations at different levels:
39
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.
40
+ ### Layer 1: Tool/LLM Lifecycle (Producer-Owned via LangChain-Core Callback)
41
+ Tool and LLM lifecycle emission is **owned by the callback layer** (`openbox-langchain-sdk-python`). The `OpenBoxLangChainCoreAsyncCallbackHandler` / `...SyncCallbackHandler` emit lifecycle events (ActivityStarted, ActivityCompleted, LLMStarted, LLMCompleted) directly to OpenBox Core via the `ActivityBridge` ownership channel. This fixes span ordering/correlation bugs: tool hook spans now nest inside the tool's ActivityStarted activity; LLM provider hook spans map into the LLM activity; completions reuse the start activity_id (no more `-c` suffix).
42
+
43
+ The LangGraph stream-event layer serves as a **fallback for telemetry and span reconstruction** when the callback is not installed (e.g., injected clients or subagent-gated handlers). Completions use stream events for telemetry only — `gate.aevaluate()` polls and continues, never retries the graph. **Sync agents fail-shut on REQUIRE_APPROVAL** (no working sync approval poller).
42
44
 
43
45
  ### Layer 2: Hook Governance (http/db/file_governance_hooks.py)
44
46
  Intercepts low-level operations using built-in instrumentation:
@@ -1,14 +1,16 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: openbox-langgraph-sdk-python
3
- Version: 0.2.0
3
+ Version: 1.1.0
4
4
  Summary: OpenBox governance and observability SDK for LangGraph
5
5
  License: MIT
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.11
8
- Requires-Dist: cryptography>=42.0.0
9
8
  Requires-Dist: httpx>=0.27.0
10
9
  Requires-Dist: langchain-core>=1.3.3
11
10
  Requires-Dist: langgraph>=0.2.0
11
+ Requires-Dist: langsmith>=0.8.18
12
+ Requires-Dist: openbox-langchain-sdk-python>=1.0.0
13
+ Requires-Dist: openbox-sdk-python>=1.4.0
12
14
  Requires-Dist: opentelemetry-api>=1.20.0
13
15
  Requires-Dist: opentelemetry-instrumentation-asyncpg>=0.41b0
14
16
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.41b0
@@ -84,10 +86,11 @@ Your code SDK (3 layers) OpenBox Co
84
86
 
85
87
  governed.ainvoke()
86
88
  │
87
- ├─ Layer 1: LangGraph Event Stream (langgraph_handler.py)
88
- │ on_tool_start/end ─────────────────────────────────────────→ Policy engine
89
- │ on_chat_model_start/end ───────────────────────────────────→ Guardrails
90
- │ on_chain_start/end ────────────────────────────────────────→ HITL queue
89
+ ├─ Layer 1: Tool/LLM Lifecycle (openbox-langchain-sdk-python)
90
+ │ Tool lifecycle via LangChain-Core callback ────────────────→ Policy engine
91
+ │ LLM lifecycle via LangChain-Core callback ───────────────→ Guardrails
92
+ │ ActivityBridge deduplicates callback events
93
+ │ Stream events serve as fallback (when callback not installed)
91
94
  │ ↑ enforce verdict (allow / block / redact / pause)
92
95
  │
93
96
  ├─ Layer 2: Hook Governance (http/db/file hooks)
@@ -101,7 +104,7 @@ governed.ainvoke()
101
104
  Links hook-level operations to the tool call that triggered them
102
105
  ```
103
106
 
104
- **Layer 1** wraps your compiled LangGraph graph and intercepts the [v2 event stream](https://langchain-ai.github.io/langgraph/how-tos/streaming-events-from-within-tools/). It sends governance events (WorkflowStarted, ActivityStarted, etc.) to OpenBox Core and enforces verdicts.
107
+ **Layer 1** tool and LLM lifecycle is **producer-owned** via the LangChain-Core callback (owned by `openbox-langchain-sdk-python`). It sends governance events (ActivityStarted, LLMStarted, etc.) to OpenBox Core and enforces verdicts. The LangGraph event stream serves as a fallback when the callback is not installed (e.g., injected clients or subagent-gated handlers); completions use stream events for telemetry only via `gate.aevaluate` (poll-and-continue, never retry-the-graph).
105
108
 
106
109
  **Layer 2** uses built-in instrumentation to intercept low-level operations (HTTP requests, DB queries, file I/O) made by your tools. Each operation is evaluated at two stages: `started` (can block) and `completed` (informational).
107
110
 
@@ -133,17 +136,14 @@ uv add openbox-langgraph-sdk-python
133
136
 
134
137
  ### 1. Get your agent credentials
135
138
 
136
- Sign in to [dashboard.openbox.ai](https://dashboard.openbox.ai), create an agent called `"MyAgent"`, and copy the agent API key plus its DID credentials.
137
-
138
- New OpenBox agents have DID signing enabled by default. Keep the private key secret and load it from your environment.
139
+ Sign in to [dashboard.openbox.ai](https://dashboard.openbox.ai), create an agent called `"MyAgent"`, and copy its API key. For an IAM v3 workload-enabled agent, also load the PKCS8 PEM RSA private key registered for its active Keycloak service account. Keep the key secret.
139
140
 
140
141
  ### 2. Set environment variables
141
142
 
142
143
  ```bash
143
144
  export OPENBOX_URL="https://core.openbox.ai"
144
145
  export OPENBOX_API_KEY="obx_live_..."
145
- export OPENBOX_AGENT_DID="did:aip:..."
146
- export OPENBOX_AGENT_PRIVATE_KEY="..."
146
+ export OPENBOX_WORKLOAD_PRIVATE_KEY="$(cat /path/to/workload-private-key.pem)"
147
147
  ```
148
148
 
149
149
  ### 3. Wrap your graph
@@ -178,6 +178,50 @@ asyncio.run(main())
178
178
 
179
179
  That's it. Your agent now sends governance events to OpenBox on every tool call, LLM prompt, HTTP request, and database query.
180
180
 
181
+ ### IAM v3 workload identity
182
+
183
+ IAM v3 is provided by `openbox-sdk-python>=1.4.0`. The existing
184
+ `openbox-langchain-sdk-python` dependency remains at `>=1.0.0`; its callbacks
185
+ use the same base runtime as the LangGraph handler and operation hooks.
186
+
187
+ You can pass the workload key explicitly instead of setting an environment variable:
188
+
189
+ ```python
190
+ governed = create_openbox_graph_handler(
191
+ graph=agent,
192
+ api_url=os.environ["OPENBOX_URL"],
193
+ api_key=os.environ["OPENBOX_API_KEY"],
194
+ workload_private_key=os.environ["OPENBOX_WORKLOAD_PRIVATE_KEY"],
195
+ )
196
+ ```
197
+
198
+ Key resolution is explicit argument, then `OPENBOX_LANGGRAPH_WORKLOAD_PRIVATE_KEY`,
199
+ then `OPENBOX_WORKLOAD_PRIVATE_KEY`. The value is the PEM contents, not a file path.
200
+ The Python base SDK selects workload authentication from this key; no
201
+ `OPENBOX_AGENT_IDENTITY_METHOD` setting is needed for IAM v3.
202
+
203
+ The base SDK fetches `/api/v3/auth/bootstrap`, exchanges a signed `private_key_jwt`
204
+ for a short-lived Keycloak token, and sends the API key plus
205
+ `X-OpenBox-Workload-Token` on v3 validation, evaluation, and approval requests.
206
+ It owns token caching and refresh for OpenBox-, Okta-, and Entra-managed identities.
207
+ Lifecycle callbacks, hooks, synchronous/raw evaluations, and approval polling share
208
+ the handler's runtime client. A standalone `GovernanceClient` also accepts
209
+ `workload_private_key`; call `await client.close()` when finished with it.
210
+
211
+ Authentication and signing failures raise `OpenBoxAuthError` or its subclass
212
+ `OpenBoxSigningError` even with `on_api_error="fail_open"`. The signing error retains
213
+ Core's `reason_code`. Invalid bootstrap metadata raises `OpenBoxConfigError`, and
214
+ bootstrap/token service outages raise `OpenBoxNetworkError`; these do not become
215
+ implicit ALLOW or pending approval results. `validate=False` skips the startup
216
+ network check only: the key is still validated locally, and runtime requests
217
+ still authenticate.
218
+
219
+ The base SDK preserves rolling-upgrade compatibility: bootstrap HTTP 404, or
220
+ HTTP 409 with `workload_identity_unavailable`, retains the configured legacy route.
221
+ Other bootstrap failures do not downgrade. Existing DID signing remains available
222
+ through `agent_did`/`agent_private_key` or `OPENBOX_AGENT_DID`/`OPENBOX_AGENT_PRIVATE_KEY`.
223
+ Without identity credentials, the existing API-key-only behavior is preserved.
224
+
181
225
  ### Try it locally (included test agent)
182
226
 
183
227
  The repository includes a runnable LangGraph test agent under `test-agent/`.
@@ -204,6 +248,7 @@ See `test-agent/README.md` for setup and run instructions.
204
248
  | `api_key` | `str` | **required** | API key (`obx_live_*` or `obx_test_*`) |
205
249
  | `agent_did` | `str` | `OPENBOX_AGENT_DID` | Agent DID used to sign governance requests |
206
250
  | `agent_private_key` | `str` | `OPENBOX_AGENT_PRIVATE_KEY` | Base64 raw Ed25519 private key seed for the agent DID |
251
+ | `workload_private_key` | `str` | `OPENBOX_LANGGRAPH_WORKLOAD_PRIVATE_KEY`, then `OPENBOX_WORKLOAD_PRIVATE_KEY` | PKCS8 PEM RSA key for IAM v3 workload authentication |
207
252
  | `agent_name` | `str` | `None` | Agent name as configured in the dashboard |
208
253
  | `validate` | `bool` | `True` | Validate API key against server on startup |
209
254
  | `on_api_error` | `str` | `"fail_open"` | `"fail_open"` (allow on error) or `"fail_closed"` (block on error) |
@@ -44,10 +44,11 @@ Your code SDK (3 layers) OpenBox Co
44
44
 
45
45
  governed.ainvoke()
46
46
  │
47
- ├─ Layer 1: LangGraph Event Stream (langgraph_handler.py)
48
- │ on_tool_start/end ─────────────────────────────────────────→ Policy engine
49
- │ on_chat_model_start/end ───────────────────────────────────→ Guardrails
50
- │ on_chain_start/end ────────────────────────────────────────→ HITL queue
47
+ ├─ Layer 1: Tool/LLM Lifecycle (openbox-langchain-sdk-python)
48
+ │ Tool lifecycle via LangChain-Core callback ────────────────→ Policy engine
49
+ │ LLM lifecycle via LangChain-Core callback ───────────────→ Guardrails
50
+ │ ActivityBridge deduplicates callback events
51
+ │ Stream events serve as fallback (when callback not installed)
51
52
  │ ↑ enforce verdict (allow / block / redact / pause)
52
53
  │
53
54
  ├─ Layer 2: Hook Governance (http/db/file hooks)
@@ -61,7 +62,7 @@ governed.ainvoke()
61
62
  Links hook-level operations to the tool call that triggered them
62
63
  ```
63
64
 
64
- **Layer 1** wraps your compiled LangGraph graph and intercepts the [v2 event stream](https://langchain-ai.github.io/langgraph/how-tos/streaming-events-from-within-tools/). It sends governance events (WorkflowStarted, ActivityStarted, etc.) to OpenBox Core and enforces verdicts.
65
+ **Layer 1** tool and LLM lifecycle is **producer-owned** via the LangChain-Core callback (owned by `openbox-langchain-sdk-python`). It sends governance events (ActivityStarted, LLMStarted, etc.) to OpenBox Core and enforces verdicts. The LangGraph event stream serves as a fallback when the callback is not installed (e.g., injected clients or subagent-gated handlers); completions use stream events for telemetry only via `gate.aevaluate` (poll-and-continue, never retry-the-graph).
65
66
 
66
67
  **Layer 2** uses built-in instrumentation to intercept low-level operations (HTTP requests, DB queries, file I/O) made by your tools. Each operation is evaluated at two stages: `started` (can block) and `completed` (informational).
67
68
 
@@ -93,17 +94,14 @@ uv add openbox-langgraph-sdk-python
93
94
 
94
95
  ### 1. Get your agent credentials
95
96
 
96
- Sign in to [dashboard.openbox.ai](https://dashboard.openbox.ai), create an agent called `"MyAgent"`, and copy the agent API key plus its DID credentials.
97
-
98
- New OpenBox agents have DID signing enabled by default. Keep the private key secret and load it from your environment.
97
+ Sign in to [dashboard.openbox.ai](https://dashboard.openbox.ai), create an agent called `"MyAgent"`, and copy its API key. For an IAM v3 workload-enabled agent, also load the PKCS8 PEM RSA private key registered for its active Keycloak service account. Keep the key secret.
99
98
 
100
99
  ### 2. Set environment variables
101
100
 
102
101
  ```bash
103
102
  export OPENBOX_URL="https://core.openbox.ai"
104
103
  export OPENBOX_API_KEY="obx_live_..."
105
- export OPENBOX_AGENT_DID="did:aip:..."
106
- export OPENBOX_AGENT_PRIVATE_KEY="..."
104
+ export OPENBOX_WORKLOAD_PRIVATE_KEY="$(cat /path/to/workload-private-key.pem)"
107
105
  ```
108
106
 
109
107
  ### 3. Wrap your graph
@@ -138,6 +136,50 @@ asyncio.run(main())
138
136
 
139
137
  That's it. Your agent now sends governance events to OpenBox on every tool call, LLM prompt, HTTP request, and database query.
140
138
 
139
+ ### IAM v3 workload identity
140
+
141
+ IAM v3 is provided by `openbox-sdk-python>=1.4.0`. The existing
142
+ `openbox-langchain-sdk-python` dependency remains at `>=1.0.0`; its callbacks
143
+ use the same base runtime as the LangGraph handler and operation hooks.
144
+
145
+ You can pass the workload key explicitly instead of setting an environment variable:
146
+
147
+ ```python
148
+ governed = create_openbox_graph_handler(
149
+ graph=agent,
150
+ api_url=os.environ["OPENBOX_URL"],
151
+ api_key=os.environ["OPENBOX_API_KEY"],
152
+ workload_private_key=os.environ["OPENBOX_WORKLOAD_PRIVATE_KEY"],
153
+ )
154
+ ```
155
+
156
+ Key resolution is explicit argument, then `OPENBOX_LANGGRAPH_WORKLOAD_PRIVATE_KEY`,
157
+ then `OPENBOX_WORKLOAD_PRIVATE_KEY`. The value is the PEM contents, not a file path.
158
+ The Python base SDK selects workload authentication from this key; no
159
+ `OPENBOX_AGENT_IDENTITY_METHOD` setting is needed for IAM v3.
160
+
161
+ The base SDK fetches `/api/v3/auth/bootstrap`, exchanges a signed `private_key_jwt`
162
+ for a short-lived Keycloak token, and sends the API key plus
163
+ `X-OpenBox-Workload-Token` on v3 validation, evaluation, and approval requests.
164
+ It owns token caching and refresh for OpenBox-, Okta-, and Entra-managed identities.
165
+ Lifecycle callbacks, hooks, synchronous/raw evaluations, and approval polling share
166
+ the handler's runtime client. A standalone `GovernanceClient` also accepts
167
+ `workload_private_key`; call `await client.close()` when finished with it.
168
+
169
+ Authentication and signing failures raise `OpenBoxAuthError` or its subclass
170
+ `OpenBoxSigningError` even with `on_api_error="fail_open"`. The signing error retains
171
+ Core's `reason_code`. Invalid bootstrap metadata raises `OpenBoxConfigError`, and
172
+ bootstrap/token service outages raise `OpenBoxNetworkError`; these do not become
173
+ implicit ALLOW or pending approval results. `validate=False` skips the startup
174
+ network check only: the key is still validated locally, and runtime requests
175
+ still authenticate.
176
+
177
+ The base SDK preserves rolling-upgrade compatibility: bootstrap HTTP 404, or
178
+ HTTP 409 with `workload_identity_unavailable`, retains the configured legacy route.
179
+ Other bootstrap failures do not downgrade. Existing DID signing remains available
180
+ through `agent_did`/`agent_private_key` or `OPENBOX_AGENT_DID`/`OPENBOX_AGENT_PRIVATE_KEY`.
181
+ Without identity credentials, the existing API-key-only behavior is preserved.
182
+
141
183
  ### Try it locally (included test agent)
142
184
 
143
185
  The repository includes a runnable LangGraph test agent under `test-agent/`.
@@ -164,6 +206,7 @@ See `test-agent/README.md` for setup and run instructions.
164
206
  | `api_key` | `str` | **required** | API key (`obx_live_*` or `obx_test_*`) |
165
207
  | `agent_did` | `str` | `OPENBOX_AGENT_DID` | Agent DID used to sign governance requests |
166
208
  | `agent_private_key` | `str` | `OPENBOX_AGENT_PRIVATE_KEY` | Base64 raw Ed25519 private key seed for the agent DID |
209
+ | `workload_private_key` | `str` | `OPENBOX_LANGGRAPH_WORKLOAD_PRIVATE_KEY`, then `OPENBOX_WORKLOAD_PRIVATE_KEY` | PKCS8 PEM RSA key for IAM v3 workload authentication |
167
210
  | `agent_name` | `str` | `None` | Agent name as configured in the dashboard |
168
211
  | `validate` | `bool` | `True` | Validate API key against server on startup |
169
212
  | `on_api_error` | `str` | `"fail_open"` | `"fail_open"` (allow on error) or `"fail_closed"` (block on error) |