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
pawly/__init__.py ADDED
@@ -0,0 +1,154 @@
1
+ """Aploy Pawly execution-boundary controller package."""
2
+
3
+ from .adapters import (
4
+ ClaudeSkillInvocation,
5
+ ClaudeSkillsPawAdapter,
6
+ OpenAIAgentAction,
7
+ OpenAIAgentsPawAdapter,
8
+ wrap_claude_skill_executor,
9
+ wrap_claude_skills,
10
+ wrap_openai_tool_executor,
11
+ wrap_openai_tools,
12
+ )
13
+ from .api import decide, run, run_actions
14
+ from .approval import (
15
+ ApprovalHandler,
16
+ ApprovalRecord,
17
+ ApprovalRequest,
18
+ ApprovalResponse,
19
+ ApprovalRouter,
20
+ ApprovalStatus,
21
+ CallbackApprovalNotifier,
22
+ FileApprovalQueue,
23
+ InMemoryApprovalQueue,
24
+ StaticApprovalHandler,
25
+ )
26
+ from .backends import (
27
+ AdvancedRiskProviderStub,
28
+ ApprovalBackend,
29
+ AuditSink,
30
+ CloudApprovalBackendStub,
31
+ CloudReviewer,
32
+ CloudAuditSinkStub,
33
+ CloudReviewerStub,
34
+ CompositeAuditSink,
35
+ HostedActionSyncAuditSink,
36
+ LocalApprovalBackend,
37
+ LocalAuditSink,
38
+ LocalRiskProvider,
39
+ ReviewerPolicy,
40
+ ReviewerBackend,
41
+ RiskContext,
42
+ RiskProvider,
43
+ RulePolicy,
44
+ RuleReviewer,
45
+ build_default_audit_sink,
46
+ resolve_policy,
47
+ resolve_reviewer_backend,
48
+ )
49
+ from .decision_engine import ActionCandidate, ActionDecision, DecisionEngine
50
+ from .gateway import ExecutionGateway, GatewayProtocol, wrap_execute_fn, wrap_executor, wrap_framework_adapter
51
+ from .loader.yaml_loader import load_yaml_file
52
+ from .pawprint_loader import (
53
+ PROTECTED_SKILL_WARNING,
54
+ PawprintConfig,
55
+ SkillLicense,
56
+ SkillMetadata,
57
+ SkillProtection,
58
+ build_model_visible_skill_context,
59
+ load_pawprint_file,
60
+ parse_pawprint_document,
61
+ )
62
+ from .policy import DefaultOssPolicy, HeuristicPolicy, Policy
63
+ from .policy.base import ScoringPolicyUnavailableError, score_source, tag_scores
64
+ from .policy.resolve import resolve_scoring_policy
65
+ from .policy_engine.engine import evaluate_pawprint
66
+ from .protected_oss import ProtectedAuditRedactingSink, detect_extraction_attempt, is_protected_skill, redact_audit_event
67
+ from .runtime import PawlyRuntime
68
+ from .runtime_result import RuntimeDecisionResult
69
+ from .skill_registry import MissingSkillRegistryError, SkillRegistry
70
+ from .contracts import Action, Decision, DecisionState, Intent, IntentSource, PolicyScore
71
+
72
+ __all__ = [
73
+ "AdvancedRiskProviderStub",
74
+ "Action",
75
+ "ApprovalBackend",
76
+ "ApprovalHandler",
77
+ "ApprovalRecord",
78
+ "ApprovalRequest",
79
+ "ApprovalResponse",
80
+ "ApprovalRouter",
81
+ "ApprovalStatus",
82
+ "ActionCandidate",
83
+ "ActionDecision",
84
+ "AuditSink",
85
+ "CloudReviewer",
86
+ "CallbackApprovalNotifier",
87
+ "ClaudeSkillInvocation",
88
+ "ClaudeSkillsPawAdapter",
89
+ "CloudApprovalBackendStub",
90
+ "CloudAuditSinkStub",
91
+ "CloudReviewerStub",
92
+ "CompositeAuditSink",
93
+ "Decision",
94
+ "DecisionState",
95
+ "ExecutionGateway",
96
+ "GatewayProtocol",
97
+ "FileApprovalQueue",
98
+ "InMemoryApprovalQueue",
99
+ "LocalApprovalBackend",
100
+ "LocalAuditSink",
101
+ "LocalRiskProvider",
102
+ "MissingSkillRegistryError",
103
+ "OpenAIAgentAction",
104
+ "OpenAIAgentsPawAdapter",
105
+ "PawprintConfig",
106
+ "DecisionEngine",
107
+ "DefaultOssPolicy",
108
+ "Intent",
109
+ "IntentSource",
110
+ "Policy",
111
+ "PolicyScore",
112
+ "PawlyRuntime",
113
+ "ProtectedAuditRedactingSink",
114
+ "ReviewerPolicy",
115
+ "ReviewerBackend",
116
+ "RiskContext",
117
+ "RiskProvider",
118
+ "RuntimeDecisionResult",
119
+ "HeuristicPolicy",
120
+ "HostedActionSyncAuditSink",
121
+ "RulePolicy",
122
+ "RuleReviewer",
123
+ "SkillLicense",
124
+ "SkillMetadata",
125
+ "SkillProtection",
126
+ "ScoringPolicyUnavailableError",
127
+ "StaticApprovalHandler",
128
+ "SkillRegistry",
129
+ "PROTECTED_SKILL_WARNING",
130
+ "build_model_visible_skill_context",
131
+ "build_default_audit_sink",
132
+ "decide",
133
+ "load_yaml_file",
134
+ "evaluate_pawprint",
135
+ "detect_extraction_attempt",
136
+ "is_protected_skill",
137
+ "load_pawprint_file",
138
+ "parse_pawprint_document",
139
+ "resolve_policy",
140
+ "resolve_reviewer_backend",
141
+ "run",
142
+ "run_actions",
143
+ "redact_audit_event",
144
+ "score_source",
145
+ "tag_scores",
146
+ "resolve_scoring_policy",
147
+ "wrap_execute_fn",
148
+ "wrap_executor",
149
+ "wrap_framework_adapter",
150
+ "wrap_claude_skill_executor",
151
+ "wrap_claude_skills",
152
+ "wrap_openai_tool_executor",
153
+ "wrap_openai_tools",
154
+ ]
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,64 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Literal
5
+
6
+ from pawly.contracts import Action, PolicyScore
7
+
8
+
9
+ BoundaryType = Literal["allow", "review", "blocked"]
10
+ DecisionSourceName = Literal["heuristic", "custom", "cloud", "fallback"]
11
+
12
+
13
+ @dataclass(slots=True)
14
+ class ActionCandidate:
15
+ action: Action
16
+ boundary_type: BoundaryType
17
+ requires_review: bool
18
+ decision_source: DecisionSourceName
19
+ score: PolicyScore
20
+ reason: str
21
+ uncertainty: float | None
22
+
23
+ def to_dict(self) -> dict[str, object]:
24
+ return {
25
+ "action": self.action.to_dict(),
26
+ "boundary_type": self.boundary_type,
27
+ "requires_review": self.requires_review,
28
+ "decision_source": self.decision_source,
29
+ "source": self.decision_source,
30
+ "reason": self.reason,
31
+ "uncertainty": self.uncertainty,
32
+ "score": self.score.to_dict(),
33
+ }
34
+
35
+
36
+ @dataclass(slots=True)
37
+ class ActionDecision:
38
+ trace_id: str | None
39
+ selected_action: Action | None
40
+ requires_review: bool
41
+ decision_source: DecisionSourceName | None
42
+ boundary_type: Literal["allow", "review"] | None
43
+ reason: str | None = None
44
+ uncertainty: float | None = None
45
+ protection: dict[str, object] | None = None
46
+ allowed_actions: list[ActionCandidate] = field(default_factory=list)
47
+ review_required_actions: list[ActionCandidate] = field(default_factory=list)
48
+ blocked_actions: list[Action] = field(default_factory=list)
49
+
50
+ def to_dict(self) -> dict[str, object]:
51
+ return {
52
+ "trace_id": self.trace_id,
53
+ "selected_action": None if self.selected_action is None else self.selected_action.to_dict(),
54
+ "requires_review": self.requires_review,
55
+ "decision_source": self.decision_source,
56
+ "source": self.decision_source,
57
+ "boundary_type": self.boundary_type,
58
+ "reason": self.reason,
59
+ "uncertainty": self.uncertainty,
60
+ "protection": None if self.protection is None else dict(self.protection),
61
+ "allowed_actions": [candidate.to_dict() for candidate in self.allowed_actions],
62
+ "review_required_actions": [candidate.to_dict() for candidate in self.review_required_actions],
63
+ "blocked_actions": [action.to_dict() for action in self.blocked_actions],
64
+ }
@@ -0,0 +1,25 @@
1
+ """Public adapter helpers for rapid framework integration."""
2
+
3
+ from .claude_skills import (
4
+ ClaudeSkillInvocation,
5
+ ClaudeSkillsPawAdapter,
6
+ wrap_claude_skill_executor,
7
+ wrap_claude_skills,
8
+ )
9
+ from .openai_agents import (
10
+ OpenAIAgentAction,
11
+ OpenAIAgentsPawAdapter,
12
+ wrap_openai_tool_executor,
13
+ wrap_openai_tools,
14
+ )
15
+
16
+ __all__ = [
17
+ "ClaudeSkillInvocation",
18
+ "ClaudeSkillsPawAdapter",
19
+ "OpenAIAgentAction",
20
+ "OpenAIAgentsPawAdapter",
21
+ "wrap_claude_skill_executor",
22
+ "wrap_claude_skills",
23
+ "wrap_openai_tool_executor",
24
+ "wrap_openai_tools",
25
+ ]
@@ -0,0 +1,210 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field, replace
4
+ from typing import Any, Callable, Iterable, Mapping
5
+
6
+ from pawly.gateway import GatewayProtocol
7
+ from pawly.gateway.adapter_support import build_gateway, execute_adapter_action, metadata_from_intent
8
+ from pawly.runtime import PawlyRuntime
9
+
10
+
11
+ @dataclass(slots=True)
12
+ class ClaudeSkillInvocation:
13
+ skill_name: str
14
+ task: str
15
+ confidence: float
16
+ metadata: dict[str, Any] = field(default_factory=dict)
17
+ approved_action_name: str | None = None
18
+ raw_item: Any = None
19
+
20
+ @classmethod
21
+ def from_value(
22
+ cls,
23
+ value: Any,
24
+ *,
25
+ task: str | None = None,
26
+ confidence: float | None = None,
27
+ metadata: Mapping[str, Any] | None = None,
28
+ skill_name_field: str = "skill_name",
29
+ task_field: str = "task",
30
+ confidence_field: str = "confidence",
31
+ metadata_field: str = "metadata",
32
+ ) -> "ClaudeSkillInvocation":
33
+ skill_name = _extract_value(value, skill_name_field)
34
+ resolved_task = task if task is not None else _extract_value(value, task_field, required=False, default="")
35
+ resolved_confidence = confidence if confidence is not None else _extract_value(
36
+ value,
37
+ confidence_field,
38
+ required=False,
39
+ default=1.0,
40
+ )
41
+ resolved_metadata = dict(metadata) if metadata is not None else dict(
42
+ _extract_value(value, metadata_field, required=False, default={}) or {}
43
+ )
44
+ return cls(
45
+ skill_name=str(skill_name),
46
+ task=str(resolved_task),
47
+ confidence=float(resolved_confidence),
48
+ metadata=resolved_metadata,
49
+ raw_item=value,
50
+ )
51
+
52
+
53
+ SkillExecutor = Callable[[ClaudeSkillInvocation], Any]
54
+ AuditHook = Callable[[dict[str, Any]], None]
55
+
56
+
57
+ class ClaudeSkillsPawAdapter:
58
+ """Gateway-backed adapter for Claude-style skill invocations."""
59
+
60
+ def __init__(
61
+ self,
62
+ runtime: PawlyRuntime,
63
+ audit_hook: AuditHook | None = None,
64
+ approval_handler=None,
65
+ gateway: GatewayProtocol | None = None,
66
+ ) -> None:
67
+ self.gateway = build_gateway(runtime, approval_handler=approval_handler, gateway=gateway)
68
+ self.audit_hook = audit_hook
69
+
70
+ def execute_skill(self, invocation: ClaudeSkillInvocation, executor: SkillExecutor) -> dict[str, Any]:
71
+ return execute_adapter_action(
72
+ gateway=self.gateway,
73
+ item=invocation,
74
+ task=invocation.task,
75
+ action=invocation.skill_name,
76
+ confidence=invocation.confidence,
77
+ metadata=invocation.metadata,
78
+ executor=executor,
79
+ remap=lambda current, intent: replace(
80
+ current,
81
+ task=intent.summary,
82
+ skill_name=intent.action.name,
83
+ confidence=intent.confidence,
84
+ metadata=metadata_from_intent(intent),
85
+ approved_action_name=intent.action.name,
86
+ ),
87
+ audit_hook=self.audit_hook,
88
+ audit_payload=lambda outcome: {
89
+ "framework": "claude-skills",
90
+ "event": "skill-execution",
91
+ "skill_name": invocation.skill_name,
92
+ "decision_type": outcome["type"],
93
+ "executed": outcome["execution"]["executed"],
94
+ },
95
+ )
96
+
97
+ def execute_native_skill(
98
+ self,
99
+ value: Any,
100
+ executor: SkillExecutor,
101
+ *,
102
+ task: str | None = None,
103
+ confidence: float | None = None,
104
+ metadata: Mapping[str, Any] | None = None,
105
+ skill_name_field: str = "skill_name",
106
+ task_field: str = "task",
107
+ confidence_field: str = "confidence",
108
+ metadata_field: str = "metadata",
109
+ ) -> dict[str, Any]:
110
+ return self.execute_skill(
111
+ ClaudeSkillInvocation.from_value(
112
+ value,
113
+ task=task,
114
+ confidence=confidence,
115
+ metadata=metadata,
116
+ skill_name_field=skill_name_field,
117
+ task_field=task_field,
118
+ confidence_field=confidence_field,
119
+ metadata_field=metadata_field,
120
+ ),
121
+ executor,
122
+ )
123
+
124
+
125
+ def wrap_claude_skill_executor(
126
+ runtime: PawlyRuntime,
127
+ executor: SkillExecutor,
128
+ *,
129
+ audit_hook: AuditHook | None = None,
130
+ approval_handler=None,
131
+ gateway: GatewayProtocol | None = None,
132
+ task: str | None = None,
133
+ confidence: float | None = None,
134
+ metadata: Mapping[str, Any] | None = None,
135
+ skill_name_field: str = "skill_name",
136
+ task_field: str = "task",
137
+ confidence_field: str = "confidence",
138
+ metadata_field: str = "metadata",
139
+ ) -> Callable[[Any], dict[str, Any]]:
140
+ adapter = ClaudeSkillsPawAdapter(
141
+ runtime,
142
+ audit_hook=audit_hook,
143
+ approval_handler=approval_handler,
144
+ gateway=gateway,
145
+ )
146
+
147
+ def wrapped(value: Any) -> dict[str, Any]:
148
+ return adapter.execute_native_skill(
149
+ value,
150
+ executor,
151
+ task=task,
152
+ confidence=confidence,
153
+ metadata=metadata,
154
+ skill_name_field=skill_name_field,
155
+ task_field=task_field,
156
+ confidence_field=confidence_field,
157
+ metadata_field=metadata_field,
158
+ )
159
+
160
+ return wrapped
161
+
162
+
163
+ def wrap_claude_skills(
164
+ runtime: PawlyRuntime,
165
+ skills: Iterable[Any],
166
+ *,
167
+ audit_hook: AuditHook | None = None,
168
+ approval_handler=None,
169
+ gateway: GatewayProtocol | None = None,
170
+ executor_field: str = "executor",
171
+ skill_name_field: str = "skill_name",
172
+ task: str | None = None,
173
+ confidence: float | None = None,
174
+ metadata: Mapping[str, Any] | None = None,
175
+ task_field: str = "task",
176
+ confidence_field: str = "confidence",
177
+ metadata_field: str = "metadata",
178
+ ) -> dict[str, Callable[[Any], dict[str, Any]]]:
179
+ wrapped_skills: dict[str, Callable[[Any], dict[str, Any]]] = {}
180
+ for skill in skills:
181
+ skill_name = str(_extract_value(skill, skill_name_field))
182
+ executor = _extract_value(skill, executor_field)
183
+ if not callable(executor):
184
+ raise TypeError(f"executor for skill '{skill_name}' must be callable")
185
+ wrapped_skills[skill_name] = wrap_claude_skill_executor(
186
+ runtime,
187
+ executor,
188
+ audit_hook=audit_hook,
189
+ approval_handler=approval_handler,
190
+ gateway=gateway,
191
+ task=task,
192
+ confidence=confidence,
193
+ metadata=metadata,
194
+ skill_name_field=skill_name_field,
195
+ task_field=task_field,
196
+ confidence_field=confidence_field,
197
+ metadata_field=metadata_field,
198
+ )
199
+ return wrapped_skills
200
+
201
+
202
+ def _extract_value(value: Any, field: str, *, required: bool = True, default: Any = None) -> Any:
203
+ if isinstance(value, Mapping):
204
+ if field in value:
205
+ return value[field]
206
+ elif hasattr(value, field):
207
+ return getattr(value, field)
208
+ if required:
209
+ raise ValueError(f"unable to extract required field '{field}'")
210
+ return default