agentfense 0.2.1__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.
agentfense/_shared.py ADDED
@@ -0,0 +1,238 @@
1
+ """Shared utility functions for sync and async clients.
2
+
3
+ This module contains conversion functions between protobuf messages and
4
+ Python dataclasses, used by both synchronous and asynchronous clients.
5
+ """
6
+
7
+ from datetime import datetime, timedelta
8
+ from typing import Optional
9
+
10
+ from ._gen import sandbox_pb2
11
+ from ._gen import codebase_pb2
12
+ from ._gen import common_pb2
13
+ from .types import (
14
+ Codebase,
15
+ FileInfo,
16
+ Permission,
17
+ PatternType,
18
+ PermissionRule,
19
+ ResourceLimits,
20
+ RuntimeType,
21
+ Sandbox,
22
+ SandboxStatus,
23
+ Session,
24
+ SessionStatus,
25
+ )
26
+
27
+
28
+ # ============================================
29
+ # Permission Conversions
30
+ # ============================================
31
+
32
+ def permission_to_proto(perm: Permission) -> common_pb2.Permission:
33
+ """Convert Permission enum to protobuf."""
34
+ mapping = {
35
+ Permission.NONE: common_pb2.PERMISSION_NONE,
36
+ Permission.VIEW: common_pb2.PERMISSION_VIEW,
37
+ Permission.READ: common_pb2.PERMISSION_READ,
38
+ Permission.WRITE: common_pb2.PERMISSION_WRITE,
39
+ }
40
+ return mapping.get(perm, common_pb2.PERMISSION_UNSPECIFIED)
41
+
42
+
43
+ def proto_to_permission(perm: common_pb2.Permission) -> Permission:
44
+ """Convert protobuf Permission to enum."""
45
+ mapping = {
46
+ common_pb2.PERMISSION_NONE: Permission.NONE,
47
+ common_pb2.PERMISSION_VIEW: Permission.VIEW,
48
+ common_pb2.PERMISSION_READ: Permission.READ,
49
+ common_pb2.PERMISSION_WRITE: Permission.WRITE,
50
+ }
51
+ return mapping.get(perm, Permission.NONE)
52
+
53
+
54
+ def pattern_type_to_proto(pt: PatternType) -> common_pb2.PatternType:
55
+ """Convert PatternType enum to protobuf."""
56
+ mapping = {
57
+ PatternType.GLOB: common_pb2.PATTERN_TYPE_GLOB,
58
+ PatternType.DIRECTORY: common_pb2.PATTERN_TYPE_DIRECTORY,
59
+ PatternType.FILE: common_pb2.PATTERN_TYPE_FILE,
60
+ }
61
+ return mapping.get(pt, common_pb2.PATTERN_TYPE_UNSPECIFIED)
62
+
63
+
64
+ def proto_to_pattern_type(pt: common_pb2.PatternType) -> PatternType:
65
+ """Convert protobuf PatternType to enum."""
66
+ mapping = {
67
+ common_pb2.PATTERN_TYPE_GLOB: PatternType.GLOB,
68
+ common_pb2.PATTERN_TYPE_DIRECTORY: PatternType.DIRECTORY,
69
+ common_pb2.PATTERN_TYPE_FILE: PatternType.FILE,
70
+ }
71
+ return mapping.get(pt, PatternType.GLOB)
72
+
73
+
74
+ # ============================================
75
+ # Status Conversions
76
+ # ============================================
77
+
78
+ def proto_to_status(status: common_pb2.SandboxStatus) -> SandboxStatus:
79
+ """Convert protobuf SandboxStatus to enum."""
80
+ mapping = {
81
+ common_pb2.SANDBOX_STATUS_PENDING: SandboxStatus.PENDING,
82
+ common_pb2.SANDBOX_STATUS_RUNNING: SandboxStatus.RUNNING,
83
+ common_pb2.SANDBOX_STATUS_STOPPED: SandboxStatus.STOPPED,
84
+ common_pb2.SANDBOX_STATUS_ERROR: SandboxStatus.ERROR,
85
+ }
86
+ return mapping.get(status, SandboxStatus.PENDING)
87
+
88
+
89
+ def proto_to_session_status(status: common_pb2.SessionStatus) -> SessionStatus:
90
+ """Convert protobuf SessionStatus to enum."""
91
+ mapping = {
92
+ common_pb2.SESSION_STATUS_UNSPECIFIED: SessionStatus.UNKNOWN,
93
+ common_pb2.SESSION_STATUS_ACTIVE: SessionStatus.ACTIVE,
94
+ common_pb2.SESSION_STATUS_CLOSED: SessionStatus.CLOSED,
95
+ }
96
+ return mapping.get(status, SessionStatus.UNKNOWN)
97
+
98
+
99
+ # ============================================
100
+ # Runtime Conversions
101
+ # ============================================
102
+
103
+ def runtime_type_to_proto(rt: RuntimeType) -> sandbox_pb2.RuntimeType:
104
+ """Convert RuntimeType enum to protobuf."""
105
+ mapping = {
106
+ RuntimeType.BWRAP: sandbox_pb2.RUNTIME_TYPE_BWRAP,
107
+ RuntimeType.DOCKER: sandbox_pb2.RUNTIME_TYPE_DOCKER,
108
+ }
109
+ return mapping.get(rt, sandbox_pb2.RUNTIME_TYPE_UNSPECIFIED)
110
+
111
+
112
+ def proto_to_runtime_type(rt: sandbox_pb2.RuntimeType) -> RuntimeType:
113
+ """Convert protobuf RuntimeType to enum."""
114
+ mapping = {
115
+ sandbox_pb2.RUNTIME_TYPE_BWRAP: RuntimeType.BWRAP,
116
+ sandbox_pb2.RUNTIME_TYPE_DOCKER: RuntimeType.DOCKER,
117
+ }
118
+ return mapping.get(rt, RuntimeType.BWRAP)
119
+
120
+
121
+ # ============================================
122
+ # Resource Limits Conversions
123
+ # ============================================
124
+
125
+ def resource_limits_to_proto(
126
+ limits: Optional[ResourceLimits],
127
+ ) -> Optional[sandbox_pb2.ResourceLimits]:
128
+ """Convert ResourceLimits to protobuf."""
129
+ if limits is None:
130
+ return None
131
+ return sandbox_pb2.ResourceLimits(
132
+ memory_bytes=limits.memory_bytes or 0,
133
+ cpu_quota=limits.cpu_quota or 0,
134
+ cpu_shares=limits.cpu_shares or 0,
135
+ pids_limit=limits.pids_limit or 0,
136
+ )
137
+
138
+
139
+ def proto_to_resource_limits(
140
+ pb: Optional[sandbox_pb2.ResourceLimits],
141
+ ) -> Optional[ResourceLimits]:
142
+ """Convert protobuf ResourceLimits to dataclass."""
143
+ if pb is None:
144
+ return None
145
+ # Check if any limit is set
146
+ if not any([pb.memory_bytes, pb.cpu_quota, pb.cpu_shares, pb.pids_limit]):
147
+ return None
148
+ return ResourceLimits(
149
+ memory_bytes=pb.memory_bytes if pb.memory_bytes else None,
150
+ cpu_quota=pb.cpu_quota if pb.cpu_quota else None,
151
+ cpu_shares=pb.cpu_shares if pb.cpu_shares else None,
152
+ pids_limit=pb.pids_limit if pb.pids_limit else None,
153
+ )
154
+
155
+
156
+ # ============================================
157
+ # Time Conversions
158
+ # ============================================
159
+
160
+ def timestamp_to_datetime(ts) -> Optional[datetime]:
161
+ """Convert protobuf Timestamp to datetime."""
162
+ if ts is None or ts.seconds == 0:
163
+ return None
164
+ return datetime.fromtimestamp(ts.seconds + ts.nanos / 1e9)
165
+
166
+
167
+ def duration_to_timedelta(d) -> Optional[timedelta]:
168
+ """Convert protobuf Duration to timedelta."""
169
+ if d is None:
170
+ return None
171
+ return timedelta(seconds=d.seconds, microseconds=d.nanos / 1000)
172
+
173
+
174
+ # ============================================
175
+ # Complex Object Conversions
176
+ # ============================================
177
+
178
+ def proto_to_sandbox(pb: sandbox_pb2.Sandbox) -> Sandbox:
179
+ """Convert protobuf Sandbox to Sandbox dataclass."""
180
+ permissions = [
181
+ PermissionRule(
182
+ pattern=p.pattern,
183
+ permission=proto_to_permission(p.permission),
184
+ type=proto_to_pattern_type(p.type),
185
+ priority=p.priority,
186
+ )
187
+ for p in pb.permissions
188
+ ]
189
+ return Sandbox(
190
+ id=pb.id,
191
+ codebase_id=pb.codebase_id,
192
+ status=proto_to_status(pb.status),
193
+ permissions=permissions,
194
+ labels=dict(pb.labels),
195
+ runtime=proto_to_runtime_type(pb.runtime),
196
+ image=pb.image if pb.image else None,
197
+ resources=proto_to_resource_limits(pb.resources) if pb.HasField("resources") else None,
198
+ created_at=timestamp_to_datetime(pb.created_at),
199
+ started_at=timestamp_to_datetime(pb.started_at),
200
+ stopped_at=timestamp_to_datetime(pb.stopped_at),
201
+ expires_at=timestamp_to_datetime(pb.expires_at),
202
+ )
203
+
204
+
205
+ def proto_to_codebase(pb: codebase_pb2.Codebase) -> Codebase:
206
+ """Convert protobuf Codebase to Codebase dataclass."""
207
+ return Codebase(
208
+ id=pb.id,
209
+ name=pb.name,
210
+ owner_id=pb.owner_id,
211
+ size=pb.size,
212
+ file_count=pb.file_count,
213
+ created_at=timestamp_to_datetime(pb.created_at),
214
+ updated_at=timestamp_to_datetime(pb.updated_at),
215
+ )
216
+
217
+
218
+ def proto_to_file_info(pb: codebase_pb2.FileInfo) -> FileInfo:
219
+ """Convert protobuf FileInfo to FileInfo dataclass."""
220
+ return FileInfo(
221
+ path=pb.path,
222
+ name=pb.name,
223
+ is_dir=pb.is_dir,
224
+ size=pb.size,
225
+ modified_at=timestamp_to_datetime(pb.modified_at),
226
+ )
227
+
228
+
229
+ def proto_to_session(pb: sandbox_pb2.Session) -> Session:
230
+ """Convert protobuf Session to Session dataclass."""
231
+ return Session(
232
+ id=pb.id,
233
+ sandbox_id=pb.sandbox_id,
234
+ status=proto_to_session_status(pb.status),
235
+ shell=pb.shell,
236
+ created_at=timestamp_to_datetime(pb.created_at),
237
+ closed_at=timestamp_to_datetime(pb.closed_at),
238
+ )