pawly 0.1.0__py3-none-any.whl

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 (206) hide show
  1. pawly/__init__.py +154 -0
  2. pawly/__pycache__/__init__.cpython-311.pyc +0 -0
  3. pawly/__pycache__/__init__.cpython-313.pyc +0 -0
  4. pawly/__pycache__/action_selection.cpython-311.pyc +0 -0
  5. pawly/__pycache__/action_selection.cpython-313.pyc +0 -0
  6. pawly/__pycache__/api.cpython-311.pyc +0 -0
  7. pawly/__pycache__/api.cpython-313.pyc +0 -0
  8. pawly/__pycache__/contracts.cpython-311.pyc +0 -0
  9. pawly/__pycache__/contracts.cpython-313.pyc +0 -0
  10. pawly/__pycache__/decision_engine.cpython-311.pyc +0 -0
  11. pawly/__pycache__/decision_engine.cpython-313.pyc +0 -0
  12. pawly/__pycache__/pawprint_loader.cpython-311.pyc +0 -0
  13. pawly/__pycache__/pawprint_loader.cpython-313.pyc +0 -0
  14. pawly/__pycache__/protected_oss.cpython-311.pyc +0 -0
  15. pawly/__pycache__/protected_oss.cpython-313.pyc +0 -0
  16. pawly/__pycache__/runtime.cpython-311.pyc +0 -0
  17. pawly/__pycache__/runtime.cpython-313.pyc +0 -0
  18. pawly/__pycache__/runtime_bootstrap.cpython-311.pyc +0 -0
  19. pawly/__pycache__/runtime_bootstrap.cpython-313.pyc +0 -0
  20. pawly/__pycache__/runtime_decision.cpython-311.pyc +0 -0
  21. pawly/__pycache__/runtime_decision.cpython-313.pyc +0 -0
  22. pawly/__pycache__/runtime_execute.cpython-311.pyc +0 -0
  23. pawly/__pycache__/runtime_execute.cpython-313.pyc +0 -0
  24. pawly/__pycache__/runtime_flow.cpython-311.pyc +0 -0
  25. pawly/__pycache__/runtime_flow.cpython-313.pyc +0 -0
  26. pawly/__pycache__/runtime_ids.cpython-311.pyc +0 -0
  27. pawly/__pycache__/runtime_ids.cpython-313.pyc +0 -0
  28. pawly/__pycache__/runtime_report.cpython-311.pyc +0 -0
  29. pawly/__pycache__/runtime_report.cpython-313.pyc +0 -0
  30. pawly/__pycache__/runtime_request.cpython-311.pyc +0 -0
  31. pawly/__pycache__/runtime_request.cpython-313.pyc +0 -0
  32. pawly/__pycache__/runtime_result.cpython-311.pyc +0 -0
  33. pawly/__pycache__/runtime_result.cpython-313.pyc +0 -0
  34. pawly/__pycache__/runtime_scoring.cpython-311.pyc +0 -0
  35. pawly/__pycache__/runtime_scoring.cpython-313.pyc +0 -0
  36. pawly/__pycache__/shield.cpython-311.pyc +0 -0
  37. pawly/__pycache__/shield.cpython-313.pyc +0 -0
  38. pawly/__pycache__/skill_registry.cpython-311.pyc +0 -0
  39. pawly/__pycache__/skill_registry.cpython-313.pyc +0 -0
  40. pawly/__pycache__/task_request.cpython-311.pyc +0 -0
  41. pawly/__pycache__/task_request.cpython-313.pyc +0 -0
  42. pawly/__pycache__/types.cpython-311.pyc +0 -0
  43. pawly/__pycache__/types.cpython-313.pyc +0 -0
  44. pawly/action_selection.py +64 -0
  45. pawly/adapters/__init__.py +25 -0
  46. pawly/adapters/__pycache__/__init__.cpython-311.pyc +0 -0
  47. pawly/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
  48. pawly/adapters/__pycache__/claude_skills.cpython-311.pyc +0 -0
  49. pawly/adapters/__pycache__/claude_skills.cpython-313.pyc +0 -0
  50. pawly/adapters/__pycache__/openai_agents.cpython-311.pyc +0 -0
  51. pawly/adapters/__pycache__/openai_agents.cpython-313.pyc +0 -0
  52. pawly/adapters/claude_skills.py +210 -0
  53. pawly/adapters/openai_agents.py +208 -0
  54. pawly/api.py +57 -0
  55. pawly/approval/__init__.py +18 -0
  56. pawly/approval/__pycache__/__init__.cpython-311.pyc +0 -0
  57. pawly/approval/__pycache__/__init__.cpython-313.pyc +0 -0
  58. pawly/approval/__pycache__/callback.cpython-311.pyc +0 -0
  59. pawly/approval/__pycache__/callback.cpython-313.pyc +0 -0
  60. pawly/approval/__pycache__/handler.cpython-311.pyc +0 -0
  61. pawly/approval/__pycache__/handler.cpython-313.pyc +0 -0
  62. pawly/approval/__pycache__/models.cpython-311.pyc +0 -0
  63. pawly/approval/__pycache__/models.cpython-313.pyc +0 -0
  64. pawly/approval/__pycache__/queue.cpython-311.pyc +0 -0
  65. pawly/approval/__pycache__/queue.cpython-313.pyc +0 -0
  66. pawly/approval/__pycache__/router.cpython-311.pyc +0 -0
  67. pawly/approval/__pycache__/router.cpython-313.pyc +0 -0
  68. pawly/approval/__pycache__/timeout.cpython-311.pyc +0 -0
  69. pawly/approval/__pycache__/timeout.cpython-313.pyc +0 -0
  70. pawly/approval/callback.py +16 -0
  71. pawly/approval/handler.py +34 -0
  72. pawly/approval/models.py +119 -0
  73. pawly/approval/queue.py +109 -0
  74. pawly/approval/router.py +66 -0
  75. pawly/approval/timeout.py +18 -0
  76. pawly/audit/__pycache__/diff.cpython-311.pyc +0 -0
  77. pawly/audit/__pycache__/diff.cpython-313.pyc +0 -0
  78. pawly/audit/__pycache__/events.cpython-311.pyc +0 -0
  79. pawly/audit/__pycache__/events.cpython-313.pyc +0 -0
  80. pawly/audit/__pycache__/ledger.cpython-311.pyc +0 -0
  81. pawly/audit/__pycache__/ledger.cpython-313.pyc +0 -0
  82. pawly/audit/__pycache__/replay.cpython-311.pyc +0 -0
  83. pawly/audit/__pycache__/replay.cpython-313.pyc +0 -0
  84. pawly/audit/diff.py +24 -0
  85. pawly/audit/events.py +156 -0
  86. pawly/audit/ledger.py +39 -0
  87. pawly/audit/replay.py +45 -0
  88. pawly/backends/__init__.py +39 -0
  89. pawly/backends/__pycache__/__init__.cpython-311.pyc +0 -0
  90. pawly/backends/__pycache__/__init__.cpython-313.pyc +0 -0
  91. pawly/backends/__pycache__/approval.cpython-311.pyc +0 -0
  92. pawly/backends/__pycache__/approval.cpython-313.pyc +0 -0
  93. pawly/backends/__pycache__/audit.cpython-311.pyc +0 -0
  94. pawly/backends/__pycache__/audit.cpython-313.pyc +0 -0
  95. pawly/backends/__pycache__/reviewer.cpython-311.pyc +0 -0
  96. pawly/backends/__pycache__/reviewer.cpython-313.pyc +0 -0
  97. pawly/backends/__pycache__/risk.cpython-311.pyc +0 -0
  98. pawly/backends/__pycache__/risk.cpython-313.pyc +0 -0
  99. pawly/backends/approval.py +85 -0
  100. pawly/backends/audit.py +189 -0
  101. pawly/backends/reviewer.py +127 -0
  102. pawly/backends/risk.py +71 -0
  103. pawly/budget/__pycache__/checker.cpython-311.pyc +0 -0
  104. pawly/budget/__pycache__/checker.cpython-313.pyc +0 -0
  105. pawly/budget/__pycache__/state.cpython-311.pyc +0 -0
  106. pawly/budget/__pycache__/state.cpython-313.pyc +0 -0
  107. pawly/budget/checker.py +37 -0
  108. pawly/budget/state.py +15 -0
  109. pawly/cli.py +44 -0
  110. pawly/contracts.py +153 -0
  111. pawly/decision_engine.py +6 -0
  112. pawly/escalation/__pycache__/patterns.cpython-311.pyc +0 -0
  113. pawly/escalation/__pycache__/patterns.cpython-313.pyc +0 -0
  114. pawly/escalation/patterns.py +33 -0
  115. pawly/gateway/__init__.py +4 -0
  116. pawly/gateway/__pycache__/__init__.cpython-311.pyc +0 -0
  117. pawly/gateway/__pycache__/__init__.cpython-313.pyc +0 -0
  118. pawly/gateway/__pycache__/adapter_support.cpython-311.pyc +0 -0
  119. pawly/gateway/__pycache__/adapter_support.cpython-313.pyc +0 -0
  120. pawly/gateway/__pycache__/protocol.cpython-311.pyc +0 -0
  121. pawly/gateway/__pycache__/protocol.cpython-313.pyc +0 -0
  122. pawly/gateway/__pycache__/result.cpython-311.pyc +0 -0
  123. pawly/gateway/__pycache__/result.cpython-313.pyc +0 -0
  124. pawly/gateway/__pycache__/wrapper.cpython-311.pyc +0 -0
  125. pawly/gateway/__pycache__/wrapper.cpython-313.pyc +0 -0
  126. pawly/gateway/adapter_support.py +56 -0
  127. pawly/gateway/protocol.py +24 -0
  128. pawly/gateway/result.py +67 -0
  129. pawly/gateway/wrapper.py +273 -0
  130. pawly/loader/__pycache__/schema_loader.cpython-311.pyc +0 -0
  131. pawly/loader/__pycache__/schema_loader.cpython-313.pyc +0 -0
  132. pawly/loader/__pycache__/yaml_loader.cpython-311.pyc +0 -0
  133. pawly/loader/__pycache__/yaml_loader.cpython-313.pyc +0 -0
  134. pawly/loader/schema_loader.py +51 -0
  135. pawly/loader/yaml_loader.py +164 -0
  136. pawly/memory/__pycache__/store.cpython-311.pyc +0 -0
  137. pawly/memory/__pycache__/store.cpython-313.pyc +0 -0
  138. pawly/memory/__pycache__/tiers.cpython-311.pyc +0 -0
  139. pawly/memory/__pycache__/tiers.cpython-313.pyc +0 -0
  140. pawly/memory/store.py +23 -0
  141. pawly/memory/tiers.py +9 -0
  142. pawly/middleware/__init__.py +1 -0
  143. pawly/middleware/__pycache__/__init__.cpython-311.pyc +0 -0
  144. pawly/middleware/__pycache__/__init__.cpython-313.pyc +0 -0
  145. pawly/middleware/__pycache__/hooks.cpython-311.pyc +0 -0
  146. pawly/middleware/__pycache__/hooks.cpython-313.pyc +0 -0
  147. pawly/middleware/hooks.py +20 -0
  148. pawly/pawprint_loader.py +301 -0
  149. pawly/performance/__pycache__/metrics.cpython-311.pyc +0 -0
  150. pawly/performance/__pycache__/metrics.cpython-313.pyc +0 -0
  151. pawly/performance/__pycache__/report.cpython-311.pyc +0 -0
  152. pawly/performance/__pycache__/report.cpython-313.pyc +0 -0
  153. pawly/performance/metrics.py +48 -0
  154. pawly/performance/report.py +44 -0
  155. pawly/policy/__init__.py +15 -0
  156. pawly/policy/__pycache__/__init__.cpython-311.pyc +0 -0
  157. pawly/policy/__pycache__/__init__.cpython-313.pyc +0 -0
  158. pawly/policy/__pycache__/base.cpython-311.pyc +0 -0
  159. pawly/policy/__pycache__/base.cpython-313.pyc +0 -0
  160. pawly/policy/__pycache__/heuristic.cpython-311.pyc +0 -0
  161. pawly/policy/__pycache__/heuristic.cpython-313.pyc +0 -0
  162. pawly/policy/__pycache__/resolve.cpython-311.pyc +0 -0
  163. pawly/policy/__pycache__/resolve.cpython-313.pyc +0 -0
  164. pawly/policy/base.py +84 -0
  165. pawly/policy/cloud.py +18 -0
  166. pawly/policy/heuristic.py +141 -0
  167. pawly/policy/resolve.py +60 -0
  168. pawly/policy_engine/__pycache__/decision.cpython-311.pyc +0 -0
  169. pawly/policy_engine/__pycache__/decision.cpython-313.pyc +0 -0
  170. pawly/policy_engine/__pycache__/engine.cpython-311.pyc +0 -0
  171. pawly/policy_engine/__pycache__/engine.cpython-313.pyc +0 -0
  172. pawly/policy_engine/__pycache__/models.cpython-311.pyc +0 -0
  173. pawly/policy_engine/__pycache__/models.cpython-313.pyc +0 -0
  174. pawly/policy_engine/__pycache__/runtime_overlay.cpython-311.pyc +0 -0
  175. pawly/policy_engine/__pycache__/runtime_overlay.cpython-313.pyc +0 -0
  176. pawly/policy_engine/decision.py +40 -0
  177. pawly/policy_engine/engine.py +152 -0
  178. pawly/policy_engine/models.py +62 -0
  179. pawly/policy_engine/risk.py +24 -0
  180. pawly/policy_engine/runtime_overlay.py +37 -0
  181. pawly/protected_oss.py +168 -0
  182. pawly/runtime.py +1004 -0
  183. pawly/runtime_bootstrap.py +104 -0
  184. pawly/runtime_decision.py +52 -0
  185. pawly/runtime_execute.py +59 -0
  186. pawly/runtime_flow.py +50 -0
  187. pawly/runtime_ids.py +19 -0
  188. pawly/runtime_report.py +18 -0
  189. pawly/runtime_request.py +23 -0
  190. pawly/runtime_result.py +142 -0
  191. pawly/runtime_scoring.py +25 -0
  192. pawly/schemas/decision.schema.json +38 -0
  193. pawly/schemas/intent.schema.json +33 -0
  194. pawly/schemas/report.schema.json +36 -0
  195. pawly/shield.py +436 -0
  196. pawly/skill_registry.py +31 -0
  197. pawly/task_request.py +27 -0
  198. pawly/types.py +15 -0
  199. pawly/validator/__pycache__/validator.cpython-311.pyc +0 -0
  200. pawly/validator/__pycache__/validator.cpython-313.pyc +0 -0
  201. pawly/validator/validator.py +177 -0
  202. pawly-0.1.0.dist-info/METADATA +7 -0
  203. pawly-0.1.0.dist-info/RECORD +206 -0
  204. pawly-0.1.0.dist-info/WHEEL +4 -0
  205. pawly-0.1.0.dist-info/entry_points.txt +2 -0
  206. pawly-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from pathlib import Path
5
+ from typing import Any, Literal
6
+
7
+ from pawly.backends.audit import AuditSink, build_default_audit_sink
8
+ from pawly.backends.reviewer import ReviewerPolicy
9
+ from pawly.backends.risk import RiskProvider
10
+ from pawly.budget.state import BudgetState
11
+ from pawly.memory.store import MemoryStore
12
+ from pawly.middleware.hooks import HookRegistry
13
+ from pawly.pawprint_loader import PawprintConfig, load_pawprint_file
14
+ from pawly.policy import resolve_action_routing_policies, resolve_reviewer_policy, resolve_reviewer_selection
15
+ from pawly.policy.base import Policy
16
+ from pawly.protected_oss import ProtectedAuditRedactingSink, is_protected_skill
17
+ from pawly.runtime_ids import RuntimeIdSequence
18
+ from pawly.validator.validator import PawprintValidator
19
+
20
+ ScoringPolicyFallbackMode = Literal["review", "heuristic", "deny"]
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class RuntimeConfig:
25
+ agent_path: Path
26
+ raw_pawprint_config: dict
27
+ pawprint_config: PawprintConfig
28
+ reviewer_name: str
29
+ reviewer_policy: ReviewerPolicy
30
+ local_scoring_policy: Policy
31
+ scoring_policy: Policy
32
+ fallback_scoring_policy: Policy
33
+ scoring_policy_fallback_mode: ScoringPolicyFallbackMode
34
+
35
+
36
+ @dataclass(slots=True)
37
+ class RuntimeServices:
38
+ audit_sink: AuditSink
39
+ audit_ledger: object
40
+ validator: PawprintValidator
41
+ memory_store: MemoryStore
42
+ hooks: HookRegistry
43
+ budget_state: BudgetState = field(default_factory=BudgetState)
44
+ ids: RuntimeIdSequence = field(default_factory=RuntimeIdSequence)
45
+ decisions: list[dict[str, Any]] = field(default_factory=list)
46
+
47
+
48
+ @dataclass(slots=True)
49
+ class RuntimeBootstrap:
50
+ config: RuntimeConfig
51
+ services: RuntimeServices
52
+
53
+
54
+ def bootstrap_runtime(
55
+ *,
56
+ agent_path: str | Path,
57
+ audit_path: str | Path | None,
58
+ policy: str,
59
+ policy_impl: ReviewerPolicy | None,
60
+ risk_provider: RiskProvider | None,
61
+ audit_sink: AuditSink | None,
62
+ scoring_policy_fallback_mode: ScoringPolicyFallbackMode,
63
+ scoring_policy: Policy | str | None,
64
+ reviewer: str | None,
65
+ reviewer_backend: ReviewerPolicy | None,
66
+ ) -> RuntimeBootstrap:
67
+ resolved_agent_path = Path(agent_path)
68
+ validator = PawprintValidator()
69
+ loaded_pawprint = load_pawprint_file(resolved_agent_path, validator)
70
+
71
+ selected_policy, selected_policy_impl = resolve_reviewer_selection(
72
+ policy=policy,
73
+ policy_impl=policy_impl,
74
+ reviewer=reviewer,
75
+ reviewer_backend=reviewer_backend,
76
+ )
77
+ local_scoring_policy, scoring_policy_impl, fallback_scoring_policy = resolve_action_routing_policies(scoring_policy)
78
+ resolved_audit_sink = audit_sink or build_default_audit_sink(audit_path)
79
+ if is_protected_skill(loaded_pawprint.config):
80
+ resolved_audit_sink = ProtectedAuditRedactingSink(resolved_audit_sink, loaded_pawprint.config)
81
+ return RuntimeBootstrap(
82
+ config=RuntimeConfig(
83
+ agent_path=resolved_agent_path,
84
+ raw_pawprint_config=loaded_pawprint.raw_document,
85
+ pawprint_config=loaded_pawprint.config,
86
+ reviewer_name=selected_policy,
87
+ reviewer_policy=resolve_reviewer_policy(
88
+ selected_policy,
89
+ policy_impl=selected_policy_impl,
90
+ risk_provider=risk_provider,
91
+ ),
92
+ local_scoring_policy=local_scoring_policy,
93
+ scoring_policy=scoring_policy_impl,
94
+ fallback_scoring_policy=fallback_scoring_policy,
95
+ scoring_policy_fallback_mode=scoring_policy_fallback_mode,
96
+ ),
97
+ services=RuntimeServices(
98
+ audit_sink=resolved_audit_sink,
99
+ audit_ledger=getattr(resolved_audit_sink, "ledger", resolved_audit_sink),
100
+ validator=validator,
101
+ memory_store=MemoryStore("none"),
102
+ hooks=HookRegistry(),
103
+ ),
104
+ )
@@ -0,0 +1,52 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from pawly.contracts import Decision
6
+ from pawly.backends.reviewer import ReviewerPolicy, evaluate_reviewer_policy
7
+ from pawly.budget.checker import BudgetResult, check_budget
8
+ from pawly.budget.state import BudgetState
9
+ from pawly.pawprint_loader import PawprintConfig
10
+ from pawly.policy_engine.models import PolicyEvaluation
11
+ from pawly.policy_engine.runtime_overlay import apply_runtime_overlays
12
+ from pawly.types import Intent
13
+
14
+
15
+ @dataclass(slots=True)
16
+ class RuntimeDecisionState:
17
+ policy_evaluation: PolicyEvaluation
18
+ budget_result: BudgetResult
19
+ decision: Decision
20
+ runtime_overlays: dict[str, object]
21
+
22
+
23
+ def evaluate_core_policy(
24
+ policy: ReviewerPolicy,
25
+ *,
26
+ intent: Intent,
27
+ pawprint: PawprintConfig,
28
+ ) -> PolicyEvaluation:
29
+ return evaluate_reviewer_policy(policy, intent, pawprint)
30
+
31
+
32
+ def evaluate_runtime_decision(
33
+ *,
34
+ policy: ReviewerPolicy,
35
+ intent: Intent,
36
+ pawprint: PawprintConfig,
37
+ raw_pawprint_config: dict,
38
+ budget_state: BudgetState,
39
+ ) -> RuntimeDecisionState:
40
+ policy_evaluation = evaluate_core_policy(
41
+ policy,
42
+ intent=intent,
43
+ pawprint=pawprint,
44
+ )
45
+ budget_result = check_budget(raw_pawprint_config, budget_state, intent)
46
+ decision, runtime_overlays = apply_runtime_overlays(policy_evaluation, budget_result)
47
+ return RuntimeDecisionState(
48
+ policy_evaluation=policy_evaluation,
49
+ budget_result=budget_result,
50
+ decision=decision,
51
+ runtime_overlays=runtime_overlays,
52
+ )
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ from pawly.contracts import Intent
4
+ from pawly.loader.schema_loader import load_pawprint_version
5
+ from pawly.protected_oss import apply_extraction_guardrail
6
+ from pawly.runtime_decision import evaluate_runtime_decision
7
+ from pawly.runtime_bootstrap import RuntimeConfig, RuntimeServices
8
+ from pawly.runtime_flow import (
9
+ build_before_hook_payload,
10
+ finalize_runtime_artifacts,
11
+ remember_allowed_decision,
12
+ validate_intent_or_raise,
13
+ )
14
+ from pawly.runtime_result import RuntimeDecisionResult, build_runtime_decision_artifacts
15
+
16
+
17
+ def evaluate_runtime_intent(
18
+ *,
19
+ config: RuntimeConfig,
20
+ services: RuntimeServices,
21
+ intent: Intent,
22
+ ) -> RuntimeDecisionResult:
23
+ validate_intent_or_raise(services.validator, intent)
24
+ services.hooks.run_before(build_before_hook_payload(intent, config.pawprint_config.id))
25
+
26
+ decision_state = evaluate_runtime_decision(
27
+ policy=config.reviewer_policy,
28
+ intent=intent,
29
+ pawprint=config.pawprint_config,
30
+ raw_pawprint_config=config.raw_pawprint_config,
31
+ budget_state=services.budget_state,
32
+ )
33
+ guarded_decision, guarded_runtime_overlays = apply_extraction_guardrail(
34
+ pawprint=config.pawprint_config,
35
+ policy_evaluation=decision_state.policy_evaluation,
36
+ decision=decision_state.decision,
37
+ runtime_overlays=decision_state.runtime_overlays,
38
+ intent=intent,
39
+ )
40
+ remember_allowed_decision(services.memory_store, intent, guarded_decision)
41
+
42
+ artifacts = build_runtime_decision_artifacts(
43
+ event_id=services.ids.next_event_id(),
44
+ decision_id=services.ids.next_decision_id(),
45
+ agent_id=config.pawprint_config.id,
46
+ pawprint_version=load_pawprint_version(),
47
+ intent=intent,
48
+ policy_evaluation=decision_state.policy_evaluation,
49
+ runtime_overlays=guarded_runtime_overlays,
50
+ decision=guarded_decision,
51
+ budget_result=decision_state.budget_result,
52
+ )
53
+ return finalize_runtime_artifacts(
54
+ validator=services.validator,
55
+ audit_sink=services.audit_sink,
56
+ hooks=services.hooks,
57
+ decisions=services.decisions,
58
+ artifacts=artifacts,
59
+ )
pawly/runtime_flow.py ADDED
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from pawly.contracts import Decision, Intent
6
+ from pawly.memory.store import MemoryStore
7
+ from pawly.middleware.hooks import HookRegistry
8
+ from pawly.runtime_result import RuntimeDecisionArtifacts, RuntimeDecisionResult
9
+ from pawly.validator.validator import PawprintValidator, SchemaValidationError
10
+
11
+
12
+ def validate_intent_or_raise(validator: PawprintValidator, intent: Intent) -> None:
13
+ intent_validation = validator.validate_intent(intent.to_dict())
14
+ if not intent_validation.valid:
15
+ raise SchemaValidationError("; ".join(intent_validation.errors))
16
+
17
+
18
+ def build_before_hook_payload(intent: Intent, agent_id: str) -> dict[str, object]:
19
+ return {
20
+ "intent": intent.to_dict(),
21
+ "agent_id": agent_id,
22
+ }
23
+
24
+
25
+ def remember_allowed_decision(memory_store: MemoryStore, intent: Intent, decision: Decision) -> None:
26
+ if decision.type.value != "allow":
27
+ return
28
+ memory_store.remember(
29
+ "default",
30
+ {"intent": intent.to_dict(), "decision_type": decision.type.value},
31
+ )
32
+
33
+
34
+ def finalize_runtime_artifacts(
35
+ *,
36
+ validator: PawprintValidator,
37
+ audit_sink: Any,
38
+ hooks: HookRegistry,
39
+ decisions: list[dict[str, Any]],
40
+ artifacts: RuntimeDecisionArtifacts,
41
+ ) -> RuntimeDecisionResult:
42
+ audit_sink.append(artifacts.event)
43
+ decision_validation = validator.validate_decision(artifacts.result.decision.to_dict())
44
+ if not decision_validation.valid:
45
+ raise SchemaValidationError("; ".join(decision_validation.errors))
46
+
47
+ result_payload = artifacts.result.to_dict()
48
+ decisions.append(result_payload)
49
+ hooks.run_after(result_payload)
50
+ return artifacts.result
pawly/runtime_ids.py ADDED
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from itertools import count
5
+
6
+
7
+ @dataclass(slots=True)
8
+ class RuntimeIdSequence:
9
+ _decision_counter: count = field(default_factory=lambda: count(1))
10
+ _event_counter: count = field(default_factory=lambda: count(1))
11
+
12
+ def next_intent_id(self) -> str:
13
+ return f"intent-{next(self._decision_counter)}"
14
+
15
+ def next_decision_id(self) -> str:
16
+ return f"decision-{next(self._decision_counter)}"
17
+
18
+ def next_event_id(self) -> str:
19
+ return f"event-{next(self._event_counter)}"
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from pawly.pawprint_loader import PawprintConfig
4
+ from pawly.performance.report import build_daily_report
5
+ from pawly.validator.validator import PawprintValidator, SchemaValidationError
6
+
7
+
8
+ def build_validated_runtime_report(
9
+ *,
10
+ validator: PawprintValidator,
11
+ pawprint: PawprintConfig,
12
+ decisions: list[dict],
13
+ ) -> dict:
14
+ report = build_daily_report(pawprint, decisions)
15
+ validation = validator.validate_report(report)
16
+ if not validation.valid:
17
+ raise SchemaValidationError("; ".join(validation.errors))
18
+ return report
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from pawly.contracts import Intent
6
+ from pawly.task_request import TaskRequest
7
+
8
+
9
+ def build_task_request_intent(
10
+ *,
11
+ task: str,
12
+ action: str,
13
+ confidence: float,
14
+ metadata: dict[str, Any] | None = None,
15
+ intent_id: str = "intent-from-task-request",
16
+ ) -> Intent:
17
+ request = TaskRequest(
18
+ task=task,
19
+ action=action,
20
+ confidence=confidence,
21
+ metadata=metadata or {},
22
+ )
23
+ return request.to_intent(intent_id=intent_id)
@@ -0,0 +1,142 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from pawly.contracts import Decision, Intent
7
+ from pawly.audit.events import AuditEvent
8
+ from pawly.budget.checker import BudgetResult
9
+ from pawly.policy_engine.models import PolicyEvaluation
10
+
11
+
12
+ @dataclass(slots=True)
13
+ class RuntimeDecisionArtifacts:
14
+ event: AuditEvent
15
+ result: RuntimeDecisionResult
16
+
17
+
18
+ @dataclass(slots=True)
19
+ class RuntimeDecisionResult:
20
+ agent_id: str
21
+ pawprint_version: str
22
+ intent: Intent
23
+ policy_evaluation: PolicyEvaluation
24
+ runtime_overlays: dict[str, object]
25
+ decision_id: str
26
+ decision: Decision
27
+ budget_consumed: dict[str, float]
28
+
29
+ @classmethod
30
+ def from_dict(cls, payload: dict[str, Any]) -> "RuntimeDecisionResult":
31
+ return cls(
32
+ agent_id=str(payload["agent_id"]),
33
+ pawprint_version=str(payload["pawprint_version"]),
34
+ intent=Intent.from_dict(payload["intent"]),
35
+ policy_evaluation=PolicyEvaluation.from_dict(payload["policy_evaluation"]),
36
+ runtime_overlays=dict(payload["runtime_overlays"]),
37
+ decision_id=str(payload["decision_id"]),
38
+ decision=Decision.from_dict(payload),
39
+ budget_consumed=dict(payload.get("budget_consumed", {})),
40
+ )
41
+
42
+ def to_dict(self) -> dict[str, object]:
43
+ return {
44
+ "agent_id": self.agent_id,
45
+ "pawprint_version": self.pawprint_version,
46
+ "intent": self.intent.to_dict(),
47
+ "policy_evaluation": self.policy_evaluation.to_dict(),
48
+ "runtime_overlays": self.runtime_overlays,
49
+ "decision_id": self.decision_id,
50
+ **self.decision.to_dict(),
51
+ "budget_consumed": self.budget_consumed,
52
+ }
53
+
54
+
55
+ def build_decision_audit_event(
56
+ *,
57
+ event_id: str,
58
+ decision_id: str,
59
+ agent_id: str,
60
+ pawprint_version: str,
61
+ intent: Intent,
62
+ policy_evaluation: PolicyEvaluation,
63
+ runtime_overlays: dict[str, object],
64
+ decision: Decision,
65
+ ) -> AuditEvent:
66
+ intent_payload = intent.to_dict()
67
+ return AuditEvent.from_decision(
68
+ event_id=event_id,
69
+ decision_id=decision_id,
70
+ agent_id=agent_id,
71
+ pawprint_version=pawprint_version,
72
+ outcome=decision.type.value,
73
+ original_intent=intent_payload,
74
+ normalized_intent=intent_payload,
75
+ action_name=intent.action.name,
76
+ policy_evaluation=policy_evaluation.to_dict(),
77
+ runtime_overlays=runtime_overlays,
78
+ policy_references=decision.matched_rules,
79
+ final_decision=decision.to_dict(),
80
+ reason_codes=decision.reason_codes,
81
+ risk_score=decision.risk_score,
82
+ escalated_to=policy_evaluation.handoff_target if decision.type.value == "require_approval" else None,
83
+ )
84
+
85
+
86
+ def build_decision_result(
87
+ *,
88
+ agent_id: str,
89
+ pawprint_version: str,
90
+ intent: Intent,
91
+ policy_evaluation: PolicyEvaluation,
92
+ runtime_overlays: dict[str, object],
93
+ decision_id: str,
94
+ decision: Decision,
95
+ budget_result: BudgetResult,
96
+ ) -> RuntimeDecisionResult:
97
+ return RuntimeDecisionResult(
98
+ agent_id=agent_id,
99
+ pawprint_version=pawprint_version,
100
+ intent=intent,
101
+ policy_evaluation=policy_evaluation,
102
+ runtime_overlays=runtime_overlays,
103
+ decision_id=decision_id,
104
+ decision=decision,
105
+ budget_consumed=budget_result.consumed,
106
+ )
107
+
108
+
109
+ def build_runtime_decision_artifacts(
110
+ *,
111
+ event_id: str,
112
+ decision_id: str,
113
+ agent_id: str,
114
+ pawprint_version: str,
115
+ intent: Intent,
116
+ policy_evaluation: PolicyEvaluation,
117
+ runtime_overlays: dict[str, object],
118
+ decision: Decision,
119
+ budget_result: BudgetResult,
120
+ ) -> RuntimeDecisionArtifacts:
121
+ return RuntimeDecisionArtifacts(
122
+ event=build_decision_audit_event(
123
+ event_id=event_id,
124
+ decision_id=decision_id,
125
+ agent_id=agent_id,
126
+ pawprint_version=pawprint_version,
127
+ intent=intent,
128
+ policy_evaluation=policy_evaluation,
129
+ runtime_overlays=runtime_overlays,
130
+ decision=decision,
131
+ ),
132
+ result=build_decision_result(
133
+ agent_id=agent_id,
134
+ pawprint_version=pawprint_version,
135
+ intent=intent,
136
+ policy_evaluation=policy_evaluation,
137
+ runtime_overlays=runtime_overlays,
138
+ decision_id=decision_id,
139
+ decision=decision,
140
+ budget_result=budget_result,
141
+ ),
142
+ )
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping, Sequence
4
+ from typing import Any
5
+
6
+ from pawly.contracts import Action, PolicyScore
7
+ from pawly.policy.base import Policy
8
+
9
+
10
+ def build_scoring_state(
11
+ *,
12
+ state: Mapping[str, Any] | None = None,
13
+ ) -> dict[str, Any]:
14
+ if state is None:
15
+ return {}
16
+ return dict(state)
17
+
18
+
19
+ def score_actions(
20
+ *,
21
+ policy: Policy,
22
+ actions: Sequence[Action],
23
+ state: Mapping[str, Any] | None = None,
24
+ ) -> list[PolicyScore]:
25
+ return policy.evaluate(build_scoring_state(state=state), actions)
@@ -0,0 +1,38 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": true,
5
+ "required": ["type", "reason"],
6
+ "properties": {
7
+ "type": {
8
+ "type": "string",
9
+ "enum": ["allow", "deny", "require_approval", "simulate"]
10
+ },
11
+ "reason": { "type": "string", "minLength": 1 },
12
+ "source": { "type": "string" },
13
+ "reason_codes": {
14
+ "type": "array",
15
+ "items": { "type": "string" }
16
+ },
17
+ "matched_rules": {
18
+ "type": "array",
19
+ "items": { "type": "string" }
20
+ },
21
+ "risk_score": { "type": "number", "minimum": 0.0, "maximum": 1.0 },
22
+ "rewritten_action": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "required": ["name", "arguments"],
26
+ "properties": {
27
+ "name": { "type": "string", "minLength": 1 },
28
+ "arguments": { "type": "object" },
29
+ "target": { "type": "string" }
30
+ }
31
+ },
32
+ "audit_tags": {
33
+ "type": "array",
34
+ "items": { "type": "string" }
35
+ },
36
+ "worker_id": { "type": "string" }
37
+ }
38
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "required": ["intent_id", "source", "action", "context", "metadata"],
6
+ "properties": {
7
+ "intent_id": { "type": "string", "minLength": 1 },
8
+ "source": {
9
+ "type": "string",
10
+ "enum": ["tool_call", "planner_output", "execution_request"]
11
+ },
12
+ "action": {
13
+ "type": "object",
14
+ "additionalProperties": false,
15
+ "required": ["name", "arguments"],
16
+ "properties": {
17
+ "name": { "type": "string", "minLength": 1 },
18
+ "arguments": { "type": "object" },
19
+ "target": { "type": "string" }
20
+ }
21
+ },
22
+ "context": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "required": ["summary", "confidence"],
26
+ "properties": {
27
+ "summary": { "type": "string" },
28
+ "confidence": { "type": "number", "minimum": 0.0, "maximum": 1.0 }
29
+ }
30
+ },
31
+ "metadata": { "type": "object" }
32
+ }
33
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "additionalProperties": false,
5
+ "required": ["worker_id", "generated_at", "summary", "policy_summary", "runtime_overlay_summary"],
6
+ "properties": {
7
+ "worker_id": { "type": "string", "minLength": 1 },
8
+ "generated_at": { "type": "string", "minLength": 1 },
9
+ "summary": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "required": ["status", "notes"],
13
+ "properties": {
14
+ "status": { "type": "string" },
15
+ "notes": { "type": "array", "items": { "type": "string" } }
16
+ }
17
+ },
18
+ "policy_summary": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "required": ["status", "notes"],
22
+ "properties": {
23
+ "status": { "type": "string" },
24
+ "notes": { "type": "array", "items": { "type": "string" } }
25
+ }
26
+ },
27
+ "runtime_overlay_summary": {
28
+ "type": "object",
29
+ "additionalProperties": false,
30
+ "required": ["notes"],
31
+ "properties": {
32
+ "notes": { "type": "array", "items": { "type": "string" } }
33
+ }
34
+ }
35
+ }
36
+ }