jvserve 2.0.13__py3-none-any.whl → 2.0.15__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.
Potentially problematic release.
This version of jvserve might be problematic. Click here for more details.
- jvserve/__init__.py +1 -1
- jvserve/lib/agent_interface.py +182 -48
- {jvserve-2.0.13.dist-info → jvserve-2.0.15.dist-info}/METADATA +1 -1
- jvserve-2.0.15.dist-info/RECORD +13 -0
- jvserve-2.0.13.dist-info/RECORD +0 -13
- {jvserve-2.0.13.dist-info → jvserve-2.0.15.dist-info}/WHEEL +0 -0
- {jvserve-2.0.13.dist-info → jvserve-2.0.15.dist-info}/entry_points.txt +0 -0
- {jvserve-2.0.13.dist-info → jvserve-2.0.15.dist-info}/licenses/LICENSE +0 -0
- {jvserve-2.0.13.dist-info → jvserve-2.0.15.dist-info}/top_level.txt +0 -0
jvserve/__init__.py
CHANGED
jvserve/lib/agent_interface.py
CHANGED
|
@@ -159,77 +159,211 @@ class AgentInterface:
|
|
|
159
159
|
|
|
160
160
|
return response
|
|
161
161
|
|
|
162
|
+
@staticmethod
|
|
163
|
+
def get_action_data(agent_id: str, action_label: str) -> dict:
|
|
164
|
+
"""Retrieves the data for a specific action of an agent."""
|
|
165
|
+
|
|
166
|
+
action_data = {}
|
|
167
|
+
ctx = AgentInterface.load_context()
|
|
168
|
+
|
|
169
|
+
if not ctx:
|
|
170
|
+
return {}
|
|
171
|
+
|
|
172
|
+
# TODO : raise error in the event agent id is invalid
|
|
173
|
+
AgentInterface.LOGGER.debug(
|
|
174
|
+
f"attempting to interact with agent {agent_id} with user root {ctx.root}..."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
actions = _Jac.spawn_call(
|
|
179
|
+
ctx.entry_node.architype,
|
|
180
|
+
AgentInterface.spawn_walker(
|
|
181
|
+
walker_name="list_actions",
|
|
182
|
+
attributes={"agent_id": agent_id},
|
|
183
|
+
module_name="agent.action.list_actions",
|
|
184
|
+
),
|
|
185
|
+
).actions
|
|
186
|
+
|
|
187
|
+
if actions:
|
|
188
|
+
for action in actions:
|
|
189
|
+
if action.get("label") == action_label:
|
|
190
|
+
action_data = action
|
|
191
|
+
break
|
|
192
|
+
|
|
193
|
+
except Exception as e:
|
|
194
|
+
AgentInterface.EXPIRATION = None
|
|
195
|
+
AgentInterface.LOGGER.error(
|
|
196
|
+
f"an exception occurred: {e}, {traceback.format_exc()}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
ctx.close()
|
|
200
|
+
return action_data
|
|
201
|
+
|
|
162
202
|
@staticmethod
|
|
163
203
|
async def action_walker_exec(
|
|
164
|
-
agent_id: str = Form(
|
|
165
|
-
|
|
166
|
-
walker: str = Form(
|
|
204
|
+
agent_id: Optional[str] = Form(None), # noqa: B008
|
|
205
|
+
action: Optional[str] = Form(None), # noqa: B008
|
|
206
|
+
walker: Optional[str] = Form(None), # noqa: B008
|
|
167
207
|
args: Optional[str] = Form(None), # noqa: B008
|
|
168
208
|
attachments: List[UploadFile] = File(default_factory=list), # noqa: B008
|
|
169
209
|
) -> JSONResponse:
|
|
170
|
-
"""
|
|
210
|
+
"""
|
|
211
|
+
Execute a named walker exposed by an action within context.
|
|
212
|
+
Capable of handling JSON or file data depending on request.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
agent_id: ID of the agent
|
|
216
|
+
action: Name of the action
|
|
217
|
+
walker: Name of the walker to execute
|
|
218
|
+
args: JSON string of additional arguments
|
|
219
|
+
attachments: List of uploaded files
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
JSONResponse: Response containing walker output or error message
|
|
223
|
+
"""
|
|
224
|
+
ctx = None
|
|
225
|
+
try:
|
|
226
|
+
# Validate required parameters
|
|
227
|
+
if walker is None or agent_id is None or action is None:
|
|
228
|
+
AgentInterface.LOGGER.error("Missing required parameters")
|
|
229
|
+
return JSONResponse(
|
|
230
|
+
status_code=400, # 400 (Bad Request)
|
|
231
|
+
content={"error": "Missing required parameters"},
|
|
232
|
+
)
|
|
171
233
|
|
|
172
|
-
|
|
234
|
+
# Get action data to resolve module
|
|
235
|
+
if agent_id is None or action is None:
|
|
236
|
+
AgentInterface.LOGGER.error("agent_id and action must not be None")
|
|
237
|
+
return JSONResponse(
|
|
238
|
+
status_code=400,
|
|
239
|
+
content={"error": "agent_id and action must not be None"},
|
|
240
|
+
)
|
|
173
241
|
|
|
174
|
-
|
|
242
|
+
action_data = AgentInterface.get_action_data(agent_id, action)
|
|
243
|
+
if not action_data:
|
|
244
|
+
AgentInterface.LOGGER.error(
|
|
245
|
+
f"Action {action} not found for agent {agent_id}"
|
|
246
|
+
)
|
|
247
|
+
return JSONResponse(
|
|
248
|
+
status_code=404,
|
|
249
|
+
content={"error": "Action not found"},
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
module_root = (
|
|
253
|
+
action_data.get("_package", {}).get("config", {}).get("module_root", "")
|
|
254
|
+
)
|
|
255
|
+
if not module_root:
|
|
256
|
+
AgentInterface.LOGGER.error(
|
|
257
|
+
f"Module not found for action {action} of agent {agent_id}"
|
|
258
|
+
)
|
|
259
|
+
return JSONResponse(
|
|
260
|
+
status_code=404,
|
|
261
|
+
content={"error": "Module not found"},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Load execution context
|
|
265
|
+
ctx = await AgentInterface.load_context_async()
|
|
266
|
+
if not ctx:
|
|
267
|
+
AgentInterface.LOGGER.error(f"Unable to execute {walker}")
|
|
268
|
+
return JSONResponse(
|
|
269
|
+
status_code=500,
|
|
270
|
+
content={"error": "Failed to load execution context"},
|
|
271
|
+
)
|
|
175
272
|
|
|
176
|
-
#
|
|
273
|
+
# Prepare attributes
|
|
177
274
|
attributes: Dict[str, Any] = {"agent_id": agent_id}
|
|
178
275
|
|
|
179
|
-
#
|
|
276
|
+
# Parse additional arguments if provided
|
|
180
277
|
if args:
|
|
181
|
-
|
|
278
|
+
try:
|
|
279
|
+
attributes.update(json.loads(args))
|
|
280
|
+
except json.JSONDecodeError as e:
|
|
281
|
+
AgentInterface.LOGGER.error(f"Invalid JSON in args: {e}")
|
|
282
|
+
return JSONResponse(
|
|
283
|
+
status_code=400,
|
|
284
|
+
content={"error": "Invalid JSON in arguments"},
|
|
285
|
+
)
|
|
182
286
|
|
|
183
|
-
#
|
|
287
|
+
# Process uploaded files
|
|
184
288
|
if attachments:
|
|
185
289
|
attributes["files"] = []
|
|
186
290
|
for file in attachments:
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
291
|
+
try:
|
|
292
|
+
attributes["files"].append(
|
|
293
|
+
{
|
|
294
|
+
"name": file.filename,
|
|
295
|
+
"type": file.content_type,
|
|
296
|
+
"content": await file.read(),
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
except Exception as e:
|
|
300
|
+
AgentInterface.LOGGER.error(
|
|
301
|
+
f"Failed to process file {file.filename}: {e}"
|
|
302
|
+
)
|
|
303
|
+
continue # Skip problematic files or return error if critical
|
|
194
304
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
305
|
+
# Execute the walker
|
|
306
|
+
walker_response = _Jac.spawn_call(
|
|
307
|
+
ctx.entry_node.architype,
|
|
308
|
+
AgentInterface.spawn_walker(
|
|
309
|
+
walker_name=walker,
|
|
310
|
+
attributes=attributes,
|
|
311
|
+
module_name=f"{module_root}.{walker}",
|
|
312
|
+
),
|
|
313
|
+
).response
|
|
200
314
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
315
|
+
# Handle different response types appropriately
|
|
316
|
+
try:
|
|
317
|
+
# If it's already a proper Response object, return as-is
|
|
318
|
+
if isinstance(walker_response, requests.Response):
|
|
319
|
+
return walker_response
|
|
206
320
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
module = f"{module_root}.{walker}"
|
|
321
|
+
# If it's a Pydantic model or similar complex object with dict representation
|
|
322
|
+
if hasattr(walker_response, "dict"):
|
|
323
|
+
return JSONResponse(status_code=200, content=walker_response.dict())
|
|
211
324
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
325
|
+
# If it's a list of complex objects
|
|
326
|
+
if (
|
|
327
|
+
isinstance(walker_response, list)
|
|
328
|
+
and len(walker_response) > 0
|
|
329
|
+
and hasattr(walker_response[0], "dict")
|
|
330
|
+
):
|
|
331
|
+
return JSONResponse(
|
|
332
|
+
status_code=200,
|
|
333
|
+
content=[item.dict() for item in walker_response],
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# For other JSON-serializable types
|
|
337
|
+
try:
|
|
338
|
+
return JSONResponse(status_code=200, content=walker_response)
|
|
339
|
+
except TypeError:
|
|
340
|
+
# Fallback to string representation if not directly JSON-serializable
|
|
341
|
+
return JSONResponse(
|
|
342
|
+
status_code=200, content={"result": str(walker_response)}
|
|
343
|
+
)
|
|
221
344
|
|
|
222
345
|
except Exception as e:
|
|
223
|
-
AgentInterface.
|
|
224
|
-
|
|
225
|
-
|
|
346
|
+
AgentInterface.LOGGER.error(f"Failed to format walker response: {e}")
|
|
347
|
+
return JSONResponse(
|
|
348
|
+
status_code=500,
|
|
349
|
+
content={"error": "Failed to format response", "details": str(e)},
|
|
226
350
|
)
|
|
227
|
-
else:
|
|
228
|
-
AgentInterface.LOGGER.error(f"unable to execute {walker}")
|
|
229
351
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
352
|
+
except Exception as e:
|
|
353
|
+
AgentInterface.EXPIRATION = None
|
|
354
|
+
AgentInterface.LOGGER.error(
|
|
355
|
+
f"Exception occurred: {str(e)}\n{traceback.format_exc()}"
|
|
356
|
+
)
|
|
357
|
+
return JSONResponse(
|
|
358
|
+
status_code=500,
|
|
359
|
+
content={"error": "Internal server error", "details": str(e)},
|
|
360
|
+
)
|
|
361
|
+
finally:
|
|
362
|
+
if ctx:
|
|
363
|
+
try:
|
|
364
|
+
ctx.close()
|
|
365
|
+
except Exception as e:
|
|
366
|
+
AgentInterface.LOGGER.error(f"Error closing context: {str(e)}")
|
|
233
367
|
|
|
234
368
|
class InteractPayload(BaseModel):
|
|
235
369
|
"""Payload for interacting with the agent."""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
jvserve/__init__.py,sha256=S9zx3emgI3a17M2NmUFp3sdzrZ9SDFwDKYAUR_TjDxE,191
|
|
2
|
+
jvserve/cli.py,sha256=NJD4ehtKnhOvsz-vrFh9lz3P4bnxqz-uqTr8QItljZc,8897
|
|
3
|
+
jvserve/lib/__init__.py,sha256=cnzfSHLoTWG9Ygut2nOpDys5aPlQz-m0BSkB-nd7OMs,31
|
|
4
|
+
jvserve/lib/agent_interface.py,sha256=d2trRXgLjUzciGSRwYD2Rl-TPnyJVpUKrgG1iU7CGyw,37768
|
|
5
|
+
jvserve/lib/agent_pulse.py,sha256=6hBF6KQYr6Z9Mi_yoWKGfdnW7gg84kK20Slu-bLR_m8,2067
|
|
6
|
+
jvserve/lib/file_interface.py,sha256=sqwTmBnZsVFQUGt7mE1EWA-jHnZlRtBAFeb4Rb_QgQ8,6079
|
|
7
|
+
jvserve/lib/jvlogger.py,sha256=RNiB9PHuBzTvNIQWhxoDgrDlNYA0PYm1SVpvzlqu8mE,4180
|
|
8
|
+
jvserve-2.0.15.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
+
jvserve-2.0.15.dist-info/METADATA,sha256=eXjQb1zag7Si-czz5V4wX60-6wr9E2eyz3yIETUF9i0,4791
|
|
10
|
+
jvserve-2.0.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
jvserve-2.0.15.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
|
|
12
|
+
jvserve-2.0.15.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
|
|
13
|
+
jvserve-2.0.15.dist-info/RECORD,,
|
jvserve-2.0.13.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
jvserve/__init__.py,sha256=AHR-iejuKB2C8u25HZ1ccXlh6tCaB3MuKVTJz-LZzig,191
|
|
2
|
-
jvserve/cli.py,sha256=NJD4ehtKnhOvsz-vrFh9lz3P4bnxqz-uqTr8QItljZc,8897
|
|
3
|
-
jvserve/lib/__init__.py,sha256=cnzfSHLoTWG9Ygut2nOpDys5aPlQz-m0BSkB-nd7OMs,31
|
|
4
|
-
jvserve/lib/agent_interface.py,sha256=4SHqvySxu08dK2cPoe2TjMKlm11VqM0qDalOKp-tma4,32347
|
|
5
|
-
jvserve/lib/agent_pulse.py,sha256=6hBF6KQYr6Z9Mi_yoWKGfdnW7gg84kK20Slu-bLR_m8,2067
|
|
6
|
-
jvserve/lib/file_interface.py,sha256=sqwTmBnZsVFQUGt7mE1EWA-jHnZlRtBAFeb4Rb_QgQ8,6079
|
|
7
|
-
jvserve/lib/jvlogger.py,sha256=RNiB9PHuBzTvNIQWhxoDgrDlNYA0PYm1SVpvzlqu8mE,4180
|
|
8
|
-
jvserve-2.0.13.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
9
|
-
jvserve-2.0.13.dist-info/METADATA,sha256=8gyJ1EnRbjZDZnOU3F-Y4lq9loXHIGLNCXn3YpPiUzg,4791
|
|
10
|
-
jvserve-2.0.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
jvserve-2.0.13.dist-info/entry_points.txt,sha256=HYyg1QXoLs0JRb004L300VeLOZyDLY27ynD1tnTnEN4,35
|
|
12
|
-
jvserve-2.0.13.dist-info/top_level.txt,sha256=afoCXZv-zXNBuhVIvfJGjafXKEiJl_ooy4BtgQwAG4Q,8
|
|
13
|
-
jvserve-2.0.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|