entropy-sdk 0.1.5__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 (29) hide show
  1. entropy_sdk-0.1.5/LICENSE +21 -0
  2. entropy_sdk-0.1.5/PKG-INFO +198 -0
  3. entropy_sdk-0.1.5/README.md +174 -0
  4. entropy_sdk-0.1.5/pyproject.toml +39 -0
  5. entropy_sdk-0.1.5/setup.cfg +4 -0
  6. entropy_sdk-0.1.5/src/entropy_sdk/__init__.py +25 -0
  7. entropy_sdk-0.1.5/src/entropy_sdk/adapters/__init__.py +5 -0
  8. entropy_sdk-0.1.5/src/entropy_sdk/adapters/base.py +31 -0
  9. entropy_sdk-0.1.5/src/entropy_sdk/adapters/langchain.py +52 -0
  10. entropy_sdk-0.1.5/src/entropy_sdk/adapters/pydanticai.py +43 -0
  11. entropy_sdk-0.1.5/src/entropy_sdk/adapters/raw.py +38 -0
  12. entropy_sdk-0.1.5/src/entropy_sdk/fallback.py +45 -0
  13. entropy_sdk-0.1.5/src/entropy_sdk/gate.py +82 -0
  14. entropy_sdk-0.1.5/src/entropy_sdk/gear.py +35 -0
  15. entropy_sdk-0.1.5/src/entropy_sdk/policy.py +55 -0
  16. entropy_sdk-0.1.5/src/entropy_sdk/py.typed +0 -0
  17. entropy_sdk-0.1.5/src/entropy_sdk/runtime.py +278 -0
  18. entropy_sdk-0.1.5/src/entropy_sdk/state.py +156 -0
  19. entropy_sdk-0.1.5/src/entropy_sdk.egg-info/PKG-INFO +198 -0
  20. entropy_sdk-0.1.5/src/entropy_sdk.egg-info/SOURCES.txt +27 -0
  21. entropy_sdk-0.1.5/src/entropy_sdk.egg-info/dependency_links.txt +1 -0
  22. entropy_sdk-0.1.5/src/entropy_sdk.egg-info/requires.txt +8 -0
  23. entropy_sdk-0.1.5/src/entropy_sdk.egg-info/top_level.txt +1 -0
  24. entropy_sdk-0.1.5/tests/test_core.py +125 -0
  25. entropy_sdk-0.1.5/tests/test_hardening.py +259 -0
  26. entropy_sdk-0.1.5/tests/test_v012.py +158 -0
  27. entropy_sdk-0.1.5/tests/test_v013.py +89 -0
  28. entropy_sdk-0.1.5/tests/test_v014.py +45 -0
  29. entropy_sdk-0.1.5/tests/test_v015.py +104 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wang Miaosheng / CYD-PRC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: entropy-sdk
3
+ Version: 0.1.5
4
+ Summary: Gear-based safety control layer for autonomous agents (EntropyRuntime core, embeddable SDK)
5
+ Author-email: Wang Miaosheng <wmsmiaosheng@outlook.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/CYD-PRC/entropy-sdk
8
+ Project-URL: Paper, https://arxiv.org/abs/2607.00334
9
+ Keywords: ai-safety,agent,governance,runtime-verification,gear
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Provides-Extra: langchain
19
+ Requires-Dist: langchain-core<1.0,>=0.2.43; extra == "langchain"
20
+ Provides-Extra: pydanticai
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=8; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # entropy-sdk
26
+
27
+ **An embeddable, gear-based safety control layer for autonomous agents** — the
28
+ SDK distillation of the EntropyRuntime paper's core abstractions
29
+ ([arXiv:2607.00334](https://arxiv.org/abs/2607.00334)).
30
+
31
+ > Make an AI's degree of autonomy observable, governable, and accountable.
32
+
33
+ [![test](https://github.com/CYD-PRC/entropy-sdk/actions/workflows/test.yml/badge.svg)](https://github.com/CYD-PRC/entropy-sdk/actions/workflows/test.yml)
34
+ ![license](https://img.shields.io/badge/license-MIT-blue)
35
+ ![python](https://img.shields.io/badge/python-%3E%3D3.10-blue)
36
+
37
+ > Test readings are reported from **raw CI logs, not badge conclusions**:
38
+ > latest verified reading — **96 passed / 0 skipped** across Python 3.10–3.13
39
+ > (Actions run inspected line-by-line). A green badge alone is not evidence.
40
+
41
+ Unlike [CYD-PRC/entropyruntime](https://github.com/CYD-PRC/entropyruntime)
42
+ (the full production system — FastAPI + PostgreSQL + Redis + OPA), this
43
+ repository is the **zero-dependency, embeddable** minimal control layer:
44
+ `pip install` and five lines of code wire it into any agent loop.
45
+
46
+ ## Core abstractions
47
+
48
+ | Abstraction | Paper | SDK |
49
+ |---|---|---|
50
+ | Five-level gear ladder G0–G4 | Definition 1 (𝒜₀⊂…⊂𝒜₄) | `Gear` |
51
+ | Utility gate U(s,a) ≥ θ | Definitions 2–3, Theorem 2 | `UtilityGate` |
52
+ | Slow-up-fast-down state machine | §4 Gear state machine | `GearPolicy` |
53
+ | Event-driven fallback | Theorem 4 | `FallbackConfig` |
54
+ | Runtime state ρ=(g,σ,ϵ) | Definition 4 | `RuntimeState` |
55
+ | Audit chain | §5/§8 empirical requirements | `AuditLog` (append-only JSONL) |
56
+
57
+ ## Design rules
58
+
59
+ 1. **Pure stdlib core, zero dependencies.** Framework adapters (LangChain /
60
+ PydanticAI) ship as optional extras.
61
+ 2. **fail-closed.** The utility function must be injected explicitly; there is
62
+ no fail-open switch — the utility gate is the sole dispatch channel
63
+ (Theorem 2, enforced in code).
64
+ 3. **Audit chain built in.** Every gate decision, gear transition, and
65
+ suspension is appended to JSONL. `gate_acceptance_rate()` and
66
+ `gear_histogram()` produce the empirical data that the paper's Theorem 1
67
+ assumption and Theorem 3 prediction call for.
68
+
69
+ ## Quickstart
70
+
71
+ ```bash
72
+ pip install entropy-sdk
73
+ ```
74
+
75
+ ```python
76
+ from entropy_sdk import EntropyRuntime, Gear, action, observe
77
+
78
+ # 1. Inject your domain utility function (the SDK ships no built-in U)
79
+ def my_utility(state, act):
80
+ return state.task_gain(act) + 2.0 * state.safety(act) - 0.5 * act.cost
81
+
82
+ # Note: action()'s **kwargs are call parameters of the wrapped function,
83
+ # not utility metadata. Feed metadata to the utility via post-creation
84
+ # assignment (act.utility_value = ... style).
85
+ # 2. Create the runtime (theta is the only safety-vs-output knob)
86
+ runtime = EntropyRuntime(utility=my_utility, theta=0.15,
87
+ audit_log="audit.jsonl")
88
+
89
+ # 3. Every agent action goes through the gate
90
+ result = runtime.step(
91
+ state=my_state,
92
+ action=action(delete_records, "users", required_gear=Gear.EXECUTE),
93
+ execute=lambda a: a(),
94
+ propose_alternative=my_fallback_planner, # optional: rejected-action fallback
95
+ )
96
+
97
+ if result.suspended:
98
+ alert_human() # m consecutive rejections -> suspend at G0, await review
99
+ runtime.resume() # after human review, gears must be re-earned
100
+ ```
101
+
102
+ ### Gear semantics
103
+
104
+ | Gear | Name | Permitted actions |
105
+ |---|---|---|
106
+ | G0 | Observe | Read-only observation, safe holding |
107
+ | G1 | Suggest | Side-effect-free candidate plans |
108
+ | G2 | Plan | Bounded, reversible recovery actions |
109
+ | G3 | Execute | Independently chosen side-effecting actions |
110
+ | G4 | Integrate | System-level coordination (an emergent property of all-G3 fleets) |
111
+
112
+ **Slow up, fast down** (earned autonomy): escalation requires σ < σ_low **and**
113
+ h consecutive clean cycles — every gear must be re-earned (v0.1.2+);
114
+ de-escalation on σ overflow or error is immediate. Autonomy is earned, and it
115
+ can always be revoked.
116
+
117
+ A runnable version of this narrative lives in
118
+ [`examples/lifecycle_demo.py`](examples/lifecycle_demo.py)
119
+ (`python examples/lifecycle_demo.py`).
120
+
121
+ ## Framework adapters
122
+
123
+ ```python
124
+ # LangChain: pip install entropy-sdk[langchain]
125
+ from entropy_sdk.adapters.langchain import gated_tool
126
+ safe_tool = gated_tool(runtime, my_tool, required_gear=Gear.EXECUTE)
127
+
128
+ # PydanticAI-compatible callable decorator: pip install entropy-sdk[pydanticai]
129
+ from entropy_sdk.adapters.pydanticai import gated
130
+
131
+ @gated(runtime, required_gear=Gear.EXECUTE)
132
+ def delete_records(table: str) -> str: ...
133
+ ```
134
+
135
+ On rejection the adapters **return an explanatory string instead of raising** —
136
+ rejection itself is feedback the agent can act on next turn.
137
+
138
+ (Note on naming: this is a **PydanticAI-compatible callable decorator**, not a
139
+ true PydanticAI adapter — it is a pure stdlib decorator with zero framework
140
+ dependencies (the `pydanticai` extra list is intentionally empty, FIX-8) and has
141
+ **not been validated against a real PydanticAI runtime**. Just
142
+ `from entropy_sdk.adapters.pydanticai import gated`.)
143
+
144
+ (LangChain boundary: `args_schema` passthrough only works for real
145
+ StructuredTool instances carrying a schema; bare tool objects (func only, no
146
+ args_schema) remain limited by the wrapper's `*args/**kwargs` signature.)
147
+
148
+ ## Threat model boundaries (paper armor — read before deploying)
149
+
150
+ 1. **The gate is the sole dispatch channel — only inside execution paths the
151
+ SDK controls.** A caller holding the raw callable can bypass the gate
152
+ (`tool.func(...)` skips it); the SDK governs calls that go through
153
+ `runtime.step`, not references in the caller's hands.
154
+ 2. **`required_gear` is a caller-side attestation contract.** The SDK trusts
155
+ the label's truthfulness; whether labels may be trusted (who is allowed to
156
+ tag an action's gear) is the deployer's responsibility — the SDK
157
+ fail-closes on *invalid* values, but is not responsible for
158
+ under-tagged powerful actions.
159
+ 3. **The gate governs invocation, not transactions.** Side effects that
160
+ already happened inside `execute` are not rolled back — the semantics are
161
+ invocation control, not atomicity. Implement compensation in your own
162
+ `execute` if you need transactional behavior.
163
+ 4. **`resume()` does not clear σ** (design semantics, not a bug): human
164
+ review ≠ instant restoration of trust — σ persists after resuming, and
165
+ gears must be re-earned through clean cycles.
166
+ 5. **`except Exception` does not cover `BaseException`**: if a
167
+ proposer/execute callback raises SystemExit/KeyboardInterrupt, the state
168
+ machine can still desynchronize — this is standard Python practice;
169
+ callers must not raise BaseException inside callbacks.
170
+ 6. **Concurrency**: the runtime is lock-free. Under current CPython (GIL),
171
+ 8000/8000 cycles measured with no lost updates; on free-threaded Python
172
+ (3.13t+), the read-modify-write of cycle/σ can lose updates — serialize
173
+ externally when using multiple threads.
174
+ 7. **A deleted audit file reads as empty** (fail-open read path): in file
175
+ mode, `entries`/metrics return empty results for a missing chain file
176
+ rather than raising — asymmetric with the fail-closed write path. Deployers
177
+ should monitor the audit file's existence (a missing append-only chain file
178
+ is itself an event).
179
+
180
+ ## Empirical data API
181
+
182
+ ```python
183
+ runtime.audit.gate_acceptance_rate() # gate acceptance rate (Theorem 1, p1≥p3)
184
+ runtime.audit.gear_histogram() # gear transition histogram (Theorem 3)
185
+ ```
186
+
187
+ Every run produces data for the framework's empirical validation — a unique
188
+ value of the SDK relative to the full system.
189
+
190
+ ## Changelog & security record
191
+
192
+ - [CHANGELOG.md](CHANGELOG.md) — versioned changes, including behavior-change
193
+ and compatibility notes.
194
+ - 中文文档:[README.zh-CN.md](README.zh-CN.md)
195
+
196
+ ## License
197
+
198
+ MIT © Wang Miaosheng (ORCID: 0009-0003-2767-2421) — see [LICENSE](LICENSE).
@@ -0,0 +1,174 @@
1
+ # entropy-sdk
2
+
3
+ **An embeddable, gear-based safety control layer for autonomous agents** — the
4
+ SDK distillation of the EntropyRuntime paper's core abstractions
5
+ ([arXiv:2607.00334](https://arxiv.org/abs/2607.00334)).
6
+
7
+ > Make an AI's degree of autonomy observable, governable, and accountable.
8
+
9
+ [![test](https://github.com/CYD-PRC/entropy-sdk/actions/workflows/test.yml/badge.svg)](https://github.com/CYD-PRC/entropy-sdk/actions/workflows/test.yml)
10
+ ![license](https://img.shields.io/badge/license-MIT-blue)
11
+ ![python](https://img.shields.io/badge/python-%3E%3D3.10-blue)
12
+
13
+ > Test readings are reported from **raw CI logs, not badge conclusions**:
14
+ > latest verified reading — **96 passed / 0 skipped** across Python 3.10–3.13
15
+ > (Actions run inspected line-by-line). A green badge alone is not evidence.
16
+
17
+ Unlike [CYD-PRC/entropyruntime](https://github.com/CYD-PRC/entropyruntime)
18
+ (the full production system — FastAPI + PostgreSQL + Redis + OPA), this
19
+ repository is the **zero-dependency, embeddable** minimal control layer:
20
+ `pip install` and five lines of code wire it into any agent loop.
21
+
22
+ ## Core abstractions
23
+
24
+ | Abstraction | Paper | SDK |
25
+ |---|---|---|
26
+ | Five-level gear ladder G0–G4 | Definition 1 (𝒜₀⊂…⊂𝒜₄) | `Gear` |
27
+ | Utility gate U(s,a) ≥ θ | Definitions 2–3, Theorem 2 | `UtilityGate` |
28
+ | Slow-up-fast-down state machine | §4 Gear state machine | `GearPolicy` |
29
+ | Event-driven fallback | Theorem 4 | `FallbackConfig` |
30
+ | Runtime state ρ=(g,σ,ϵ) | Definition 4 | `RuntimeState` |
31
+ | Audit chain | §5/§8 empirical requirements | `AuditLog` (append-only JSONL) |
32
+
33
+ ## Design rules
34
+
35
+ 1. **Pure stdlib core, zero dependencies.** Framework adapters (LangChain /
36
+ PydanticAI) ship as optional extras.
37
+ 2. **fail-closed.** The utility function must be injected explicitly; there is
38
+ no fail-open switch — the utility gate is the sole dispatch channel
39
+ (Theorem 2, enforced in code).
40
+ 3. **Audit chain built in.** Every gate decision, gear transition, and
41
+ suspension is appended to JSONL. `gate_acceptance_rate()` and
42
+ `gear_histogram()` produce the empirical data that the paper's Theorem 1
43
+ assumption and Theorem 3 prediction call for.
44
+
45
+ ## Quickstart
46
+
47
+ ```bash
48
+ pip install entropy-sdk
49
+ ```
50
+
51
+ ```python
52
+ from entropy_sdk import EntropyRuntime, Gear, action, observe
53
+
54
+ # 1. Inject your domain utility function (the SDK ships no built-in U)
55
+ def my_utility(state, act):
56
+ return state.task_gain(act) + 2.0 * state.safety(act) - 0.5 * act.cost
57
+
58
+ # Note: action()'s **kwargs are call parameters of the wrapped function,
59
+ # not utility metadata. Feed metadata to the utility via post-creation
60
+ # assignment (act.utility_value = ... style).
61
+ # 2. Create the runtime (theta is the only safety-vs-output knob)
62
+ runtime = EntropyRuntime(utility=my_utility, theta=0.15,
63
+ audit_log="audit.jsonl")
64
+
65
+ # 3. Every agent action goes through the gate
66
+ result = runtime.step(
67
+ state=my_state,
68
+ action=action(delete_records, "users", required_gear=Gear.EXECUTE),
69
+ execute=lambda a: a(),
70
+ propose_alternative=my_fallback_planner, # optional: rejected-action fallback
71
+ )
72
+
73
+ if result.suspended:
74
+ alert_human() # m consecutive rejections -> suspend at G0, await review
75
+ runtime.resume() # after human review, gears must be re-earned
76
+ ```
77
+
78
+ ### Gear semantics
79
+
80
+ | Gear | Name | Permitted actions |
81
+ |---|---|---|
82
+ | G0 | Observe | Read-only observation, safe holding |
83
+ | G1 | Suggest | Side-effect-free candidate plans |
84
+ | G2 | Plan | Bounded, reversible recovery actions |
85
+ | G3 | Execute | Independently chosen side-effecting actions |
86
+ | G4 | Integrate | System-level coordination (an emergent property of all-G3 fleets) |
87
+
88
+ **Slow up, fast down** (earned autonomy): escalation requires σ < σ_low **and**
89
+ h consecutive clean cycles — every gear must be re-earned (v0.1.2+);
90
+ de-escalation on σ overflow or error is immediate. Autonomy is earned, and it
91
+ can always be revoked.
92
+
93
+ A runnable version of this narrative lives in
94
+ [`examples/lifecycle_demo.py`](examples/lifecycle_demo.py)
95
+ (`python examples/lifecycle_demo.py`).
96
+
97
+ ## Framework adapters
98
+
99
+ ```python
100
+ # LangChain: pip install entropy-sdk[langchain]
101
+ from entropy_sdk.adapters.langchain import gated_tool
102
+ safe_tool = gated_tool(runtime, my_tool, required_gear=Gear.EXECUTE)
103
+
104
+ # PydanticAI-compatible callable decorator: pip install entropy-sdk[pydanticai]
105
+ from entropy_sdk.adapters.pydanticai import gated
106
+
107
+ @gated(runtime, required_gear=Gear.EXECUTE)
108
+ def delete_records(table: str) -> str: ...
109
+ ```
110
+
111
+ On rejection the adapters **return an explanatory string instead of raising** —
112
+ rejection itself is feedback the agent can act on next turn.
113
+
114
+ (Note on naming: this is a **PydanticAI-compatible callable decorator**, not a
115
+ true PydanticAI adapter — it is a pure stdlib decorator with zero framework
116
+ dependencies (the `pydanticai` extra list is intentionally empty, FIX-8) and has
117
+ **not been validated against a real PydanticAI runtime**. Just
118
+ `from entropy_sdk.adapters.pydanticai import gated`.)
119
+
120
+ (LangChain boundary: `args_schema` passthrough only works for real
121
+ StructuredTool instances carrying a schema; bare tool objects (func only, no
122
+ args_schema) remain limited by the wrapper's `*args/**kwargs` signature.)
123
+
124
+ ## Threat model boundaries (paper armor — read before deploying)
125
+
126
+ 1. **The gate is the sole dispatch channel — only inside execution paths the
127
+ SDK controls.** A caller holding the raw callable can bypass the gate
128
+ (`tool.func(...)` skips it); the SDK governs calls that go through
129
+ `runtime.step`, not references in the caller's hands.
130
+ 2. **`required_gear` is a caller-side attestation contract.** The SDK trusts
131
+ the label's truthfulness; whether labels may be trusted (who is allowed to
132
+ tag an action's gear) is the deployer's responsibility — the SDK
133
+ fail-closes on *invalid* values, but is not responsible for
134
+ under-tagged powerful actions.
135
+ 3. **The gate governs invocation, not transactions.** Side effects that
136
+ already happened inside `execute` are not rolled back — the semantics are
137
+ invocation control, not atomicity. Implement compensation in your own
138
+ `execute` if you need transactional behavior.
139
+ 4. **`resume()` does not clear σ** (design semantics, not a bug): human
140
+ review ≠ instant restoration of trust — σ persists after resuming, and
141
+ gears must be re-earned through clean cycles.
142
+ 5. **`except Exception` does not cover `BaseException`**: if a
143
+ proposer/execute callback raises SystemExit/KeyboardInterrupt, the state
144
+ machine can still desynchronize — this is standard Python practice;
145
+ callers must not raise BaseException inside callbacks.
146
+ 6. **Concurrency**: the runtime is lock-free. Under current CPython (GIL),
147
+ 8000/8000 cycles measured with no lost updates; on free-threaded Python
148
+ (3.13t+), the read-modify-write of cycle/σ can lose updates — serialize
149
+ externally when using multiple threads.
150
+ 7. **A deleted audit file reads as empty** (fail-open read path): in file
151
+ mode, `entries`/metrics return empty results for a missing chain file
152
+ rather than raising — asymmetric with the fail-closed write path. Deployers
153
+ should monitor the audit file's existence (a missing append-only chain file
154
+ is itself an event).
155
+
156
+ ## Empirical data API
157
+
158
+ ```python
159
+ runtime.audit.gate_acceptance_rate() # gate acceptance rate (Theorem 1, p1≥p3)
160
+ runtime.audit.gear_histogram() # gear transition histogram (Theorem 3)
161
+ ```
162
+
163
+ Every run produces data for the framework's empirical validation — a unique
164
+ value of the SDK relative to the full system.
165
+
166
+ ## Changelog & security record
167
+
168
+ - [CHANGELOG.md](CHANGELOG.md) — versioned changes, including behavior-change
169
+ and compatibility notes.
170
+ - 中文文档:[README.zh-CN.md](README.zh-CN.md)
171
+
172
+ ## License
173
+
174
+ MIT © Wang Miaosheng (ORCID: 0009-0003-2767-2421) — see [LICENSE](LICENSE).
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "entropy-sdk"
7
+ version = "0.1.5"
8
+ description = "Gear-based safety control layer for autonomous agents (EntropyRuntime core, embeddable SDK)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Wang Miaosheng", email = "wmsmiaosheng@outlook.com" },
14
+ ]
15
+ keywords = ["ai-safety", "agent", "governance", "runtime-verification", "gear"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
22
+ ]
23
+ # 核心零依赖:纯 stdlib。框架适配器按需安装 extras。
24
+ dependencies = []
25
+
26
+ [project.optional-dependencies]
27
+ langchain = ["langchain-core>=0.2.43,<1.0"] # 地板钉实测值:0.2.0 实测不兼容(pydantic v1 shim 校验炸),0.2.43 实测通过
28
+ pydanticai = [] # FIX-8:该适配器为纯 stdlib 装饰器,实际零框架依赖(名实对齐)
29
+ dev = ["pytest>=8"]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/CYD-PRC/entropy-sdk"
33
+ Paper = "https://arxiv.org/abs/2607.00334"
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["src"]
37
+
38
+ [tool.pytest.ini_options]
39
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ """
2
+ entropy-sdk — EntropyRuntime 控制层的可嵌入 SDK
3
+
4
+ 论文同款核心抽象(arXiv:2607.00334):
5
+ Gear 五级档位 · Utility Gate 效用门 · 事件驱动 Fallback · append-only 审计链。
6
+
7
+ 设计铁律:
8
+ 1. 核心纯 stdlib,零依赖;
9
+ 2. fail-closed —— 效用函数必须显式注入,门是唯一调度通道;
10
+ 3. 每次判定自动落审计链,为经验验证生产数据。
11
+ """
12
+ from .adapters.raw import RawAction, action, observe
13
+ from .fallback import FallbackConfig
14
+ from .gate import GateDecision, UtilityGate
15
+ from .gear import Gear
16
+ from .policy import GearPolicy
17
+ from .runtime import CycleResult, EntropyRuntime
18
+ from .state import AuditLog, RuntimeState
19
+
20
+ __version__ = "0.1.5"
21
+ __all__ = [
22
+ "Gear", "UtilityGate", "GateDecision", "GearPolicy", "FallbackConfig",
23
+ "RuntimeState", "AuditLog", "EntropyRuntime", "CycleResult",
24
+ "RawAction", "action", "observe",
25
+ ]
@@ -0,0 +1,5 @@
1
+ """Agent 框架适配器。raw 零依赖;langchain/pydanticai 按需 extras 安装。"""
2
+ from .base import AgentAdapter, GatedAction
3
+ from .raw import RawAction, action, observe
4
+
5
+ __all__ = ["AgentAdapter", "GatedAction", "RawAction", "action", "observe"]
@@ -0,0 +1,31 @@
1
+ """适配器基座:一个动作协议 + 一个提案协议,接任何 agent 框架。"""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any, Protocol, runtime_checkable
5
+
6
+ from ..gear import Gear
7
+
8
+
9
+ @runtime_checkable
10
+ class GatedAction(Protocol):
11
+ """被门控的动作必须声明自己需要的最低档位。
12
+
13
+ 这是嵌套动作空间 A0⊂…⊂A4 的实现侧契约:
14
+ required_gear=G0 的动作(只读)在任何档位都允许;
15
+ required_gear=G3 的动作(有副作用)只在 Execute 以上放行。
16
+ """
17
+
18
+ required_gear: int | Gear
19
+
20
+
21
+ class AgentAdapter(Protocol):
22
+ """Agent 框架适配协议(对齐生产仓 interfaces/agent_adapter.py 的轻量版)。"""
23
+
24
+ def propose(self, state: Any, gear: Gear, history: list[dict]) -> GatedAction:
25
+ """按当前档位生成候选动作。实现侧应遵守档位语义:
26
+ 档位越低,生成的动作越保守。"""
27
+ ...
28
+
29
+ def execute(self, action: GatedAction) -> Any:
30
+ """真正执行。只会在门放行后被调用。"""
31
+ ...
@@ -0,0 +1,52 @@
1
+ """LangChain 适配:把 Tool 包成"门不过就不执行"的安全工具。
2
+
3
+ 需要 ``pip install entropy-sdk[langchain]``。
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from typing import Any
8
+
9
+ from ..gear import Gear
10
+ from ..runtime import EntropyRuntime, _safe_gear
11
+
12
+
13
+ def gated_tool(runtime: EntropyRuntime, tool: Any, required_gear: int | Gear = Gear.EXECUTE,
14
+ state_fn=lambda *a, **k: None):
15
+ """把一个 LangChain Tool 包装成受 EntropyRuntime 门控的工具。
16
+
17
+ 门拒绝时返回拒绝说明字符串(不执行、不抛异常),
18
+ 让 LLM 在下一轮自行调整——拒绝本身是反馈信号。
19
+ """
20
+ # FIX5-2:与 runtime 同一严格度——构造期即拒非法 gear(3.0/"3"/True 等),
21
+ # 消灭「adapter 静默截断、runtime 拒绝」的两处判定不一致
22
+ gear = _safe_gear(required_gear)
23
+ if gear is None:
24
+ raise ValueError(f"invalid required_gear {required_gear!r} "
25
+ "(want Gear instance or plain int 0-4)")
26
+
27
+ def _run(*args: Any, **kwargs: Any) -> str:
28
+ from .raw import action # 延迟导入,避免硬依赖
29
+
30
+ # FIX-7:description 透传,效用函数可按工具身份定价
31
+ act = action(tool.func if hasattr(tool, "func") else tool,
32
+ *args, required_gear=gear,
33
+ description=getattr(tool, "description", "") or getattr(tool, "name", ""),
34
+ **kwargs)
35
+ result = runtime.step(state=state_fn(), action=act, execute=lambda a: a())
36
+ if result.executed:
37
+ return str(result.result)
38
+ if result.suspended:
39
+ return "[GATE] runtime suspended after repeated rejections; human review required."
40
+ reason = result.gate.reason if result.gate else "gear does not permit this action"
41
+ return f"[GATE] action rejected: {reason}. Propose a safer alternative."
42
+
43
+ from langchain_core.tools import StructuredTool # noqa: 仅在调用时需要
44
+
45
+ return StructuredTool.from_function(
46
+ func=_run,
47
+ name=f"gated_{getattr(tool, 'name', 'tool')}",
48
+ description=(getattr(tool, "description", "") or "")
49
+ + f" [safety-gated, requires gear {gear.label}]",
50
+ # FIX-6:透传原工具的 args_schema——不带它,带参工具没有正常调用路径
51
+ args_schema=getattr(tool, "args_schema", None),
52
+ )
@@ -0,0 +1,43 @@
1
+ """PydanticAI 适配:工具函数装饰器,门控逻辑与框架解耦。
2
+
3
+ 需要 ``pip install entropy-sdk[pydanticai]``。
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import functools
8
+ from typing import Any, Callable
9
+
10
+ from ..gear import Gear
11
+ from ..runtime import EntropyRuntime
12
+
13
+
14
+ def gated(runtime: EntropyRuntime, required_gear: int | Gear = Gear.EXECUTE,
15
+ state_fn=lambda *a, **k: None):
16
+ """装饰任意工具函数,使其经过 EntropyRuntime 效用门。
17
+
18
+ 拒绝时返回说明字符串而非抛异常,让 agent 把拒绝当作反馈。
19
+ 用法::
20
+
21
+ @gated(runtime, required_gear=Gear.EXECUTE)
22
+ def delete_records(table: str) -> str: ...
23
+ """
24
+ def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
25
+ @functools.wraps(fn)
26
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
27
+ from .raw import action
28
+
29
+ # FIX-7:description 透传(docstring 优先,函数名兜底),效用可按工具身份定价
30
+ act = action(fn, *args, required_gear=required_gear,
31
+ description=(fn.__doc__ or "").strip() or fn.__name__,
32
+ **kwargs)
33
+ result = runtime.step(state=state_fn(), action=act, execute=lambda a: a())
34
+ if result.executed:
35
+ return result.result
36
+ if result.suspended:
37
+ return "[GATE] runtime suspended; human review required."
38
+ reason = result.gate.reason if result.gate else "gear does not permit this action"
39
+ return f"[GATE] rejected: {reason}"
40
+
41
+ return wrapper
42
+
43
+ return decorator
@@ -0,0 +1,38 @@
1
+ """零框架适配:把任意 Python callable 包装成被门控的动作。"""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass, field
5
+ from typing import Any, Callable
6
+
7
+ from ..gear import Gear
8
+
9
+
10
+ @dataclass
11
+ class RawAction:
12
+ """最小动作包装。"""
13
+
14
+ fn: Callable[..., Any]
15
+ args: tuple = ()
16
+ kwargs: dict = field(default_factory=dict)
17
+ required_gear: int | Gear = Gear.EXECUTE
18
+ description: str = ""
19
+
20
+ def __call__(self) -> Any:
21
+ return self.fn(*self.args, **self.kwargs)
22
+
23
+
24
+ def action(
25
+ fn: Callable[..., Any],
26
+ *args: Any,
27
+ required_gear: int | Gear = Gear.EXECUTE,
28
+ description: str = "",
29
+ **kwargs: Any,
30
+ ) -> RawAction:
31
+ """一行包装:``action(send_email, to, body, required_gear=Gear.EXECUTE)``。"""
32
+ return RawAction(fn=fn, args=args, kwargs=kwargs,
33
+ required_gear=required_gear, description=description)
34
+
35
+
36
+ def observe(fn: Callable[..., Any], *args: Any, **kwargs: Any) -> RawAction:
37
+ """只读动作快捷包装:required_gear=G0,任何档位可执行。"""
38
+ return action(fn, *args, required_gear=Gear.OBSERVE, **kwargs)