veris-ai 1.12.1__py3-none-any.whl → 1.12.3__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 veris-ai might be problematic. Click here for more details.
- veris_ai/agents_wrapper.py +15 -4
- veris_ai/api_client.py +18 -0
- veris_ai/tool_mock.py +130 -4
- {veris_ai-1.12.1.dist-info → veris_ai-1.12.3.dist-info}/METADATA +8 -1
- {veris_ai-1.12.1.dist-info → veris_ai-1.12.3.dist-info}/RECORD +7 -7
- {veris_ai-1.12.1.dist-info → veris_ai-1.12.3.dist-info}/WHEEL +0 -0
- {veris_ai-1.12.1.dist-info → veris_ai-1.12.3.dist-info}/licenses/LICENSE +0 -0
veris_ai/agents_wrapper.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""OpenAI Agents wrapper for automatic tool mocking via Veris SDK."""
|
|
2
2
|
|
|
3
|
+
import inspect
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
5
6
|
from collections.abc import Callable
|
|
@@ -9,7 +10,7 @@ from agents import RunContextWrapper, RunResult, Runner as OpenAIRunner
|
|
|
9
10
|
from pydantic import BaseModel
|
|
10
11
|
|
|
11
12
|
from veris_ai import veris
|
|
12
|
-
from veris_ai.tool_mock import mock_tool_call
|
|
13
|
+
from veris_ai.tool_mock import mock_tool_call, mock_tool_call_async
|
|
13
14
|
from veris_ai.models import ToolCallOptions
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
@@ -83,14 +84,26 @@ def _wrap(
|
|
|
83
84
|
) -> Any: # noqa: ANN401
|
|
84
85
|
"""Wrapped on_invoke_tool that intercepts the tool function."""
|
|
85
86
|
session_id = veris.session_id
|
|
87
|
+
thread_id = veris.thread_id
|
|
86
88
|
the_func = tool_functions.get(tool_id)
|
|
87
89
|
if the_func and session_id:
|
|
88
|
-
#
|
|
90
|
+
# Check if async or sync, call appropriate version
|
|
91
|
+
if inspect.iscoroutinefunction(the_func):
|
|
92
|
+
# Use async version (non-blocking)
|
|
93
|
+
return await mock_tool_call_async(
|
|
94
|
+
the_func,
|
|
95
|
+
session_id,
|
|
96
|
+
json.loads(parameters),
|
|
97
|
+
tool_options.get(tool_name_inner),
|
|
98
|
+
thread_id=thread_id,
|
|
99
|
+
)
|
|
100
|
+
# Use sync version for sync functions
|
|
89
101
|
return mock_tool_call(
|
|
90
102
|
the_func,
|
|
91
103
|
session_id,
|
|
92
104
|
json.loads(parameters),
|
|
93
105
|
tool_options.get(tool_name_inner),
|
|
106
|
+
thread_id=thread_id,
|
|
94
107
|
)
|
|
95
108
|
# Fall back to original if we couldn't extract the function
|
|
96
109
|
return await orig_invoke(ctx, parameters)
|
|
@@ -189,8 +202,6 @@ def _find_user_function_in_closure(closure: tuple) -> Callable | None:
|
|
|
189
202
|
Returns:
|
|
190
203
|
The user function if found, None otherwise
|
|
191
204
|
"""
|
|
192
|
-
import inspect
|
|
193
|
-
|
|
194
205
|
# List of module prefixes that indicate library/framework code
|
|
195
206
|
library_modules = ("json", "inspect", "agents", "pydantic", "openai", "typing")
|
|
196
207
|
|
veris_ai/api_client.py
CHANGED
|
@@ -60,6 +60,24 @@ class SimulatorAPIClient:
|
|
|
60
60
|
response.raise_for_status()
|
|
61
61
|
return response.json() if response.content else None
|
|
62
62
|
|
|
63
|
+
async def post_async(self, endpoint: str, payload: dict[str, Any]) -> Any: # noqa: ANN401
|
|
64
|
+
"""Make an asynchronous POST request to the specified endpoint.
|
|
65
|
+
|
|
66
|
+
This method uses httpx.AsyncClient and is safe to call from async functions
|
|
67
|
+
without blocking the event loop.
|
|
68
|
+
"""
|
|
69
|
+
headers = self._build_headers()
|
|
70
|
+
# Validate endpoint URL; raise ConnectError for non-absolute URLs to
|
|
71
|
+
# mirror connection failures in tests when base URL is intentionally invalid.
|
|
72
|
+
if not endpoint.startswith(("http://", "https://")):
|
|
73
|
+
error_msg = f"Invalid endpoint URL (not absolute): {endpoint}"
|
|
74
|
+
raise httpx.ConnectError(error_msg)
|
|
75
|
+
|
|
76
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
77
|
+
response = await client.post(endpoint, json=payload, headers=headers)
|
|
78
|
+
response.raise_for_status()
|
|
79
|
+
return response.json() if response.content else None
|
|
80
|
+
|
|
63
81
|
@property
|
|
64
82
|
def tool_mock_endpoint(self) -> str:
|
|
65
83
|
"""Get the tool mock endpoint URL."""
|
veris_ai/tool_mock.py
CHANGED
|
@@ -206,14 +206,14 @@ class VerisSDK:
|
|
|
206
206
|
return await func(*args, **kwargs)
|
|
207
207
|
parameters = get_function_parameters(func, args, kwargs)
|
|
208
208
|
logger.info(f"Spying on function: {func.__name__}")
|
|
209
|
-
|
|
209
|
+
await log_tool_call_async(
|
|
210
210
|
session_id=session_id,
|
|
211
211
|
function_name=func.__name__,
|
|
212
212
|
parameters=parameters,
|
|
213
213
|
docstring=inspect.getdoc(func) or "",
|
|
214
214
|
)
|
|
215
215
|
result = await func(*args, **kwargs)
|
|
216
|
-
|
|
216
|
+
await log_tool_response_async(session_id=session_id, response=result)
|
|
217
217
|
return result
|
|
218
218
|
|
|
219
219
|
@wraps(func)
|
|
@@ -275,7 +275,7 @@ class VerisSDK:
|
|
|
275
275
|
return await func(*args, **kwargs)
|
|
276
276
|
parameters = get_function_parameters(func, args, kwargs)
|
|
277
277
|
thread_id = _thread_id_context.get()
|
|
278
|
-
return
|
|
278
|
+
return await mock_tool_call_async(
|
|
279
279
|
func,
|
|
280
280
|
session_id,
|
|
281
281
|
parameters,
|
|
@@ -358,7 +358,7 @@ def mock_tool_call(
|
|
|
358
358
|
options: ToolCallOptions | None = None,
|
|
359
359
|
thread_id: str | None = None,
|
|
360
360
|
) -> object:
|
|
361
|
-
"""Mock tool call.
|
|
361
|
+
"""Mock tool call (synchronous).
|
|
362
362
|
|
|
363
363
|
Args:
|
|
364
364
|
func: Function being mocked
|
|
@@ -424,6 +424,84 @@ def mock_tool_call(
|
|
|
424
424
|
return convert_to_type(mock_result, return_type_obj)
|
|
425
425
|
|
|
426
426
|
|
|
427
|
+
@tenacity.retry(
|
|
428
|
+
stop=tenacity.stop_after_attempt(3),
|
|
429
|
+
wait=tenacity.wait_exponential(multiplier=1, min=4, max=10),
|
|
430
|
+
reraise=True,
|
|
431
|
+
)
|
|
432
|
+
async def mock_tool_call_async(
|
|
433
|
+
func: Callable,
|
|
434
|
+
session_id: str, # noqa: ARG001
|
|
435
|
+
parameters: dict[str, dict[str, str]],
|
|
436
|
+
options: ToolCallOptions | None = None,
|
|
437
|
+
thread_id: str | None = None,
|
|
438
|
+
) -> object:
|
|
439
|
+
"""Mock tool call (asynchronous).
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
func: Function being mocked
|
|
443
|
+
session_id: Session ID (kept for backwards compatibility, not used)
|
|
444
|
+
parameters: Function parameters
|
|
445
|
+
options: Tool call options
|
|
446
|
+
thread_id: Thread ID to use as session_id in API request (required)
|
|
447
|
+
|
|
448
|
+
Raises:
|
|
449
|
+
ValueError: If thread_id is not provided
|
|
450
|
+
"""
|
|
451
|
+
if thread_id is None:
|
|
452
|
+
raise ValueError(
|
|
453
|
+
"thread_id is required for mocking. "
|
|
454
|
+
"Use parse_token() to set both session_id and thread_id."
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
options = options or ToolCallOptions()
|
|
458
|
+
api_client = get_api_client()
|
|
459
|
+
endpoint = api_client.tool_mock_endpoint
|
|
460
|
+
|
|
461
|
+
logger.info(f"Simulating function: {func.__name__}")
|
|
462
|
+
|
|
463
|
+
type_hints = get_type_hints(func)
|
|
464
|
+
|
|
465
|
+
# Extract return type object (not just the name)
|
|
466
|
+
return_type_obj = type_hints.pop("return", Any)
|
|
467
|
+
# Get function docstring
|
|
468
|
+
docstring = inspect.getdoc(func) or ""
|
|
469
|
+
|
|
470
|
+
# Use thread_id as session_id in the payload
|
|
471
|
+
payload_session_id = thread_id
|
|
472
|
+
# Clean up parameters for V3 - just send values, not the nested dict
|
|
473
|
+
clean_params: dict[str, Any] = {}
|
|
474
|
+
for key, value in parameters.items():
|
|
475
|
+
if isinstance(value, dict) and "value" in value:
|
|
476
|
+
# Extract just the value from the nested structure
|
|
477
|
+
clean_params[key] = value["value"]
|
|
478
|
+
else:
|
|
479
|
+
# Already clean or unexpected format
|
|
480
|
+
clean_params[key] = value
|
|
481
|
+
|
|
482
|
+
# Determine response expectation
|
|
483
|
+
payload = {
|
|
484
|
+
"session_id": payload_session_id,
|
|
485
|
+
"response_expectation": options.response_expectation.value,
|
|
486
|
+
"cache_response": bool(options.cache_response),
|
|
487
|
+
"tool_call": {
|
|
488
|
+
"function_name": func.__name__,
|
|
489
|
+
"parameters": clean_params,
|
|
490
|
+
"return_type": json.dumps(extract_json_schema(return_type_obj)),
|
|
491
|
+
"docstring": docstring,
|
|
492
|
+
},
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
mock_result = await api_client.post_async(endpoint, payload)
|
|
496
|
+
logger.info(f"Mock response: {mock_result}")
|
|
497
|
+
|
|
498
|
+
if isinstance(mock_result, str):
|
|
499
|
+
with suppress(json.JSONDecodeError):
|
|
500
|
+
mock_result = json.loads(mock_result)
|
|
501
|
+
return convert_to_type(mock_result, return_type_obj)
|
|
502
|
+
return convert_to_type(mock_result, return_type_obj)
|
|
503
|
+
|
|
504
|
+
|
|
427
505
|
def log_tool_call(
|
|
428
506
|
session_id: str,
|
|
429
507
|
function_name: str,
|
|
@@ -456,6 +534,38 @@ def log_tool_call(
|
|
|
456
534
|
logger.warning(f"Failed to log tool call for {function_name}: {e}")
|
|
457
535
|
|
|
458
536
|
|
|
537
|
+
async def log_tool_call_async(
|
|
538
|
+
session_id: str,
|
|
539
|
+
function_name: str,
|
|
540
|
+
parameters: dict[str, dict[str, str]],
|
|
541
|
+
docstring: str,
|
|
542
|
+
) -> None:
|
|
543
|
+
"""Log tool call asynchronously to the VERIS logging endpoint."""
|
|
544
|
+
api_client = get_api_client()
|
|
545
|
+
endpoint = api_client.get_log_tool_call_endpoint(session_id)
|
|
546
|
+
|
|
547
|
+
# Clean up parameters for V3 - just send values, not the nested dict
|
|
548
|
+
clean_params: dict[str, Any] = {}
|
|
549
|
+
for key, value in parameters.items():
|
|
550
|
+
if isinstance(value, dict) and "value" in value:
|
|
551
|
+
# Extract just the value from the nested structure
|
|
552
|
+
clean_params[key] = value["value"]
|
|
553
|
+
else:
|
|
554
|
+
# Already clean or unexpected format
|
|
555
|
+
clean_params[key] = value
|
|
556
|
+
|
|
557
|
+
payload = {
|
|
558
|
+
"function_name": function_name,
|
|
559
|
+
"parameters": clean_params,
|
|
560
|
+
"docstring": docstring,
|
|
561
|
+
}
|
|
562
|
+
try:
|
|
563
|
+
await api_client.post_async(endpoint, payload)
|
|
564
|
+
logger.debug(f"Tool call logged for {function_name}")
|
|
565
|
+
except Exception as e:
|
|
566
|
+
logger.warning(f"Failed to log tool call for {function_name}: {e}")
|
|
567
|
+
|
|
568
|
+
|
|
459
569
|
def log_tool_response(session_id: str, response: Any) -> None: # noqa: ANN401
|
|
460
570
|
"""Log tool response synchronously to the VERIS logging endpoint."""
|
|
461
571
|
api_client = get_api_client()
|
|
@@ -472,4 +582,20 @@ def log_tool_response(session_id: str, response: Any) -> None: # noqa: ANN401
|
|
|
472
582
|
logger.warning(f"Failed to log tool response: {e}")
|
|
473
583
|
|
|
474
584
|
|
|
585
|
+
async def log_tool_response_async(session_id: str, response: Any) -> None: # noqa: ANN401
|
|
586
|
+
"""Log tool response asynchronously to the VERIS logging endpoint."""
|
|
587
|
+
api_client = get_api_client()
|
|
588
|
+
endpoint = api_client.get_log_tool_response_endpoint(session_id)
|
|
589
|
+
|
|
590
|
+
payload = {
|
|
591
|
+
"response": json.dumps(response, default=str),
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
try:
|
|
595
|
+
await api_client.post_async(endpoint, payload)
|
|
596
|
+
logger.debug("Tool response logged")
|
|
597
|
+
except Exception as e:
|
|
598
|
+
logger.warning(f"Failed to log tool response: {e}")
|
|
599
|
+
|
|
600
|
+
|
|
475
601
|
veris = VerisSDK()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: veris-ai
|
|
3
|
-
Version: 1.12.
|
|
3
|
+
Version: 1.12.3
|
|
4
4
|
Summary: A Python package for Veris AI tools
|
|
5
5
|
Project-URL: Homepage, https://github.com/veris-ai/veris-python-sdk
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/veris-ai/veris-python-sdk/issues
|
|
@@ -41,6 +41,13 @@ Description-Content-Type: text/markdown
|
|
|
41
41
|
|
|
42
42
|
# Veris AI Python SDK
|
|
43
43
|
|
|
44
|
+
[](https://badge.fury.io/py/veris-ai)
|
|
45
|
+
[](https://pypi.org/project/veris-ai/)
|
|
46
|
+
[](https://pepy.tech/project/veris-ai)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
[](https://github.com/veris-ai/veris-python-sdk/actions/workflows/test.yml)
|
|
49
|
+
[](https://github.com/astral-sh/ruff)
|
|
50
|
+
|
|
44
51
|
For more information visit us at https://veris.ai
|
|
45
52
|
|
|
46
53
|
A Python package for Veris AI tools with simulation capabilities and FastAPI MCP (Model Context Protocol) integration.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
veris_ai/README.md,sha256=Mxg9fyNt6hFkQaFBYZq85Kw9akw4cN2uu6j_mXZtNCs,3871
|
|
2
2
|
veris_ai/__init__.py,sha256=enl_gEa6BQAjWvzCtsn_hFVJVVlJZ_dMsLL--E5W3nU,1907
|
|
3
|
-
veris_ai/agents_wrapper.py,sha256=
|
|
4
|
-
veris_ai/api_client.py,sha256=
|
|
3
|
+
veris_ai/agents_wrapper.py,sha256=gLUd_0TyCVsqqilQLvsSJIpsU5uu2CdjjWOQ4QJjoJk,12786
|
|
4
|
+
veris_ai/api_client.py,sha256=I1XyQ7J0ZU_JK9sZjF3XqFv5gGsrdKF38euOZmW8BG0,4150
|
|
5
5
|
veris_ai/models.py,sha256=xKeheSJQle2tBeJG1DsGJzMDwv24p5jECjX6RAa39n4,495
|
|
6
6
|
veris_ai/observability.py,sha256=eSIXmk6fpOAoWM-sDbsvzyUASh1ZwU6tRIPduy09RxY,4206
|
|
7
|
-
veris_ai/tool_mock.py,sha256=
|
|
7
|
+
veris_ai/tool_mock.py,sha256=wqklgub07C9zon25P9XMAXTXUsRVKAnZo6nv4lJROCo,21850
|
|
8
8
|
veris_ai/utils.py,sha256=hJetCiN8Bubhy0nqSoS1C2awN9cdkKuHM1v7YhtwtTs,10066
|
|
9
9
|
veris_ai/jaeger_interface/README.md,sha256=kd9rKcE5xf3EyNaiHu0tjn-0oES9sfaK6Ih-OhhTyCM,2821
|
|
10
10
|
veris_ai/jaeger_interface/__init__.py,sha256=KD7NSiMYRG_2uF6dOLKkGG5lNQe4K9ptEwucwMT4_aw,1128
|
|
11
11
|
veris_ai/jaeger_interface/client.py,sha256=yJrh86wRR0Dk3Gq12DId99WogcMIVbL0QQFqVSevvlE,8772
|
|
12
12
|
veris_ai/jaeger_interface/models.py,sha256=e64VV6IvOEFuzRUgvDAMQFyOZMRb56I-PUPZLBZ3rX0,1864
|
|
13
|
-
veris_ai-1.12.
|
|
14
|
-
veris_ai-1.12.
|
|
15
|
-
veris_ai-1.12.
|
|
16
|
-
veris_ai-1.12.
|
|
13
|
+
veris_ai-1.12.3.dist-info/METADATA,sha256=P6ZtsocGvpf7cifFzmvQLUZnFaYb5bVGiaYggn9KkC8,16684
|
|
14
|
+
veris_ai-1.12.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
15
|
+
veris_ai-1.12.3.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
|
|
16
|
+
veris_ai-1.12.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|