veris-ai 1.13.0__py3-none-any.whl → 1.14.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.

Potentially problematic release.


This version of veris-ai might be problematic. Click here for more details.

veris_ai/api_client.py CHANGED
@@ -20,9 +20,15 @@ class SimulatorAPIClient:
20
20
  changes reflected without recreating the singleton.
21
21
  """
22
22
 
23
- def __init__(self) -> None:
23
+ def __init__(self, timeout: float | None = None, base_url: str | None = None) -> None:
24
24
  """Initialize the API client with static timeout configuration."""
25
- self.timeout = float(os.getenv("VERIS_MOCK_TIMEOUT", "90.0"))
25
+ self._timeout = timeout or float(os.getenv("VERIS_MOCK_TIMEOUT", "300.0"))
26
+ self._base_url = base_url
27
+
28
+ @property
29
+ def base_url(self) -> str:
30
+ """Get the resolved base URL."""
31
+ return self._get_base_url()
26
32
 
27
33
  def _get_base_url(self) -> str:
28
34
  """Resolve the base URL from environment.
@@ -33,7 +39,7 @@ class SimulatorAPIClient:
33
39
  (do not fall back). This supports tests expecting connection
34
40
  failures when an invalid endpoint is provided.
35
41
  """
36
- return os.getenv("VERIS_API_URL") or "https://simulator.api.veris.ai"
42
+ return self._base_url or os.getenv("VERIS_API_URL") or "https://simulator.api.veris.ai"
37
43
 
38
44
  def _build_headers(self) -> dict[str, str] | None:
39
45
  """Build headers including OpenTelemetry tracing and API key."""
@@ -55,7 +61,7 @@ class SimulatorAPIClient:
55
61
  if not endpoint.startswith(("http://", "https://")):
56
62
  raise httpx.ConnectError("Invalid endpoint URL (not absolute): {endpoint}")
57
63
 
58
- with httpx.Client(timeout=self.timeout) as client:
64
+ with httpx.Client(timeout=self._timeout) as client:
59
65
  response = client.post(endpoint, json=payload, headers=headers)
60
66
  response.raise_for_status()
61
67
  return response.json() if response.content else None
@@ -73,7 +79,7 @@ class SimulatorAPIClient:
73
79
  error_msg = f"Invalid endpoint URL (not absolute): {endpoint}"
74
80
  raise httpx.ConnectError(error_msg)
75
81
 
76
- async with httpx.AsyncClient(timeout=self.timeout) as client:
82
+ async with httpx.AsyncClient(timeout=self._timeout) as client:
77
83
  response = await client.post(endpoint, json=payload, headers=headers)
78
84
  response.raise_for_status()
79
85
  return response.json() if response.content else None
@@ -81,15 +87,15 @@ class SimulatorAPIClient:
81
87
  @property
82
88
  def tool_mock_endpoint(self) -> str:
83
89
  """Get the tool mock endpoint URL."""
84
- return urljoin(self._get_base_url(), "v3/tool_mock")
90
+ return urljoin(self.base_url, "v3/tool_mock")
85
91
 
86
92
  def get_log_tool_call_endpoint(self, session_id: str) -> str:
87
93
  """Get the log tool call endpoint URL."""
88
- return urljoin(self._get_base_url(), f"v3/log_tool_call?session_id={session_id}")
94
+ return urljoin(self.base_url, f"v3/log_tool_call?session_id={session_id}")
89
95
 
90
96
  def get_log_tool_response_endpoint(self, session_id: str) -> str:
91
97
  """Get the log tool response endpoint URL."""
92
- return urljoin(self._get_base_url(), f"v3/log_tool_response?session_id={session_id}")
98
+ return urljoin(self.base_url, f"v3/log_tool_response?session_id={session_id}")
93
99
 
94
100
 
95
101
  # Global singleton instance
@@ -99,3 +105,9 @@ _api_client = SimulatorAPIClient()
99
105
  def get_api_client() -> SimulatorAPIClient:
100
106
  """Get the global API client instance."""
101
107
  return _api_client
108
+
109
+
110
+ def set_api_client_params(base_url: str | None = None, timeout: float | None = None) -> None:
111
+ """Set the global API client instance for testing purposes."""
112
+ global _api_client # noqa: PLW0603
113
+ _api_client = SimulatorAPIClient(base_url=base_url, timeout=timeout)
veris_ai/tool_mock.py CHANGED
@@ -16,14 +16,16 @@ from typing import (
16
16
 
17
17
 
18
18
  from veris_ai.models import ResponseExpectation, ToolCallOptions
19
- from veris_ai.api_client import get_api_client
19
+ from veris_ai.api_client import get_api_client, set_api_client_params
20
20
  from veris_ai.utils import (
21
21
  convert_to_type,
22
22
  execute_callback,
23
+ execute_combined_callback,
23
24
  extract_json_schema,
24
25
  get_function_parameters,
25
26
  get_input_parameters,
26
27
  launch_callback_task,
28
+ launch_combined_callback_task,
27
29
  )
28
30
 
29
31
  logger = logging.getLogger(__name__)
@@ -90,6 +92,8 @@ class VerisSDK:
90
92
 
91
93
  self._set_session_id(token_data["session_id"])
92
94
  self._set_thread_id(token_data["thread_id"])
95
+ if token_data.get("api_url"):
96
+ set_api_client_params(base_url=token_data["api_url"])
93
97
  logger.info(
94
98
  f"Session ID set to {token_data['session_id']}, "
95
99
  f"Thread ID set to {token_data['thread_id']} - mocking enabled"
@@ -245,13 +249,14 @@ class VerisSDK:
245
249
 
246
250
  return decorator
247
251
 
248
- def mock( # noqa: C901, PLR0915
252
+ def mock( # noqa: C901, PLR0915, PLR0913
249
253
  self,
250
254
  mode: Literal["tool", "function"] = "tool",
251
255
  expects_response: bool | None = None,
252
256
  cache_response: bool | None = None,
253
257
  input_callback: Callable[..., Any] | None = None,
254
258
  output_callback: Callable[[Any], Any] | None = None,
259
+ combined_callback: Callable[..., Any] | None = None,
255
260
  ) -> Callable:
256
261
  """Decorator for mocking tool calls.
257
262
 
@@ -261,6 +266,7 @@ class VerisSDK:
261
266
  cache_response: Whether to cache the response
262
267
  input_callback: Callable that receives input parameters as individual arguments
263
268
  output_callback: Callable that receives the output value
269
+ combined_callback: Callable that receives both input parameters and mock_output
264
270
  """
265
271
  response_expectation = (
266
272
  ResponseExpectation.NONE
@@ -306,6 +312,7 @@ class VerisSDK:
306
312
  input_params = get_input_parameters(func, args, kwargs)
307
313
  launch_callback_task(input_callback, input_params, unpack=True)
308
314
  launch_callback_task(output_callback, result, unpack=False)
315
+ launch_combined_callback_task(combined_callback, input_params, result)
309
316
 
310
317
  return result
311
318
 
@@ -337,6 +344,7 @@ class VerisSDK:
337
344
  input_params = get_input_parameters(func, args, kwargs)
338
345
  execute_callback(input_callback, input_params, unpack=True)
339
346
  execute_callback(output_callback, result, unpack=False)
347
+ execute_combined_callback(combined_callback, input_params, result)
340
348
 
341
349
  return result
342
350
 
@@ -350,6 +358,7 @@ class VerisSDK:
350
358
  return_value: Any, # noqa: ANN401
351
359
  input_callback: Callable[..., Any] | None = None,
352
360
  output_callback: Callable[[Any], Any] | None = None,
361
+ combined_callback: Callable[..., Any] | None = None,
353
362
  ) -> Callable:
354
363
  """Decorator for stubbing tool calls.
355
364
 
@@ -357,6 +366,7 @@ class VerisSDK:
357
366
  return_value: The value to return when the function is stubbed
358
367
  input_callback: Callable that receives input parameters as individual arguments
359
368
  output_callback: Callable that receives the output value
369
+ combined_callback: Callable that receives both input parameters and mock_output
360
370
  """
361
371
 
362
372
  def decorator(func: Callable) -> Callable:
@@ -380,6 +390,7 @@ class VerisSDK:
380
390
  input_params = get_input_parameters(func, args, kwargs)
381
391
  launch_callback_task(input_callback, input_params, unpack=True)
382
392
  launch_callback_task(output_callback, return_value, unpack=False)
393
+ launch_combined_callback_task(combined_callback, input_params, return_value)
383
394
 
384
395
  return return_value
385
396
 
@@ -397,6 +408,7 @@ class VerisSDK:
397
408
  input_params = get_input_parameters(func, args, kwargs)
398
409
  execute_callback(input_callback, input_params, unpack=True)
399
410
  execute_callback(output_callback, return_value, unpack=False)
411
+ execute_combined_callback(combined_callback, input_params, return_value)
400
412
 
401
413
  return return_value
402
414
 
veris_ai/utils.py CHANGED
@@ -489,3 +489,75 @@ def launch_callback_task(
489
489
  except RuntimeError:
490
490
  # If no event loop is running, log a warning
491
491
  logger.warning("Cannot launch callback task: no event loop running")
492
+
493
+
494
+ def execute_combined_callback(
495
+ callback: Callable | None,
496
+ input_params: dict[str, Any],
497
+ mock_output: Any, # noqa: ANN401
498
+ ) -> None:
499
+ """Execute a combined callback synchronously with input parameters and mock output.
500
+
501
+ Args:
502
+ callback: The callback callable to execute
503
+ input_params: Dictionary of input parameters
504
+ mock_output: The output from the mock/stub call
505
+
506
+ Note:
507
+ Exceptions in callbacks are caught and logged to prevent breaking the main flow.
508
+ """
509
+ if callback is None:
510
+ return
511
+
512
+ try:
513
+ # Combine input params with mock_output
514
+ combined_data = {**input_params, "mock_output": mock_output}
515
+ # Filter parameters to match callback signature
516
+ filtered_data = filter_callback_parameters(callback, combined_data)
517
+ callback(**filtered_data)
518
+ except Exception as e:
519
+ logger.warning(f"Combined callback execution failed: {e}", exc_info=True)
520
+
521
+
522
+ def launch_combined_callback_task(
523
+ callback: Callable | None,
524
+ input_params: dict[str, Any],
525
+ mock_output: Any, # noqa: ANN401
526
+ ) -> None:
527
+ """Launch a combined callback as a background task (fire-and-forget).
528
+
529
+ Args:
530
+ callback: The callback callable to execute (can be sync or async)
531
+ input_params: Dictionary of input parameters
532
+ mock_output: The output from the mock/stub call
533
+
534
+ Note:
535
+ This launches the callback without blocking. Errors are logged but won't
536
+ affect the main execution flow.
537
+ """
538
+ if callback is None:
539
+ return
540
+
541
+ async def _run_callback() -> None:
542
+ """Wrapper to run combined callback with error handling."""
543
+ try:
544
+ # Combine input params with mock_output
545
+ combined_data = {**input_params, "mock_output": mock_output}
546
+ # Filter parameters to match callback signature
547
+ filtered_data = filter_callback_parameters(callback, combined_data)
548
+
549
+ if inspect.iscoroutinefunction(callback):
550
+ await callback(**filtered_data)
551
+ else:
552
+ result = callback(**filtered_data)
553
+ if inspect.iscoroutine(result):
554
+ await result
555
+ except Exception as e:
556
+ logger.warning(f"Combined callback execution failed: {e}", exc_info=True)
557
+
558
+ # Create task without awaiting (fire-and-forget)
559
+ try:
560
+ asyncio.create_task(_run_callback())
561
+ except RuntimeError:
562
+ # If no event loop is running, log a warning
563
+ logger.warning("Cannot launch combined callback task: no event loop running")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: veris-ai
3
- Version: 1.13.0
3
+ Version: 1.14.1
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
@@ -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
3
  veris_ai/agents_wrapper.py,sha256=gLUd_0TyCVsqqilQLvsSJIpsU5uu2CdjjWOQ4QJjoJk,12786
4
- veris_ai/api_client.py,sha256=I1XyQ7J0ZU_JK9sZjF3XqFv5gGsrdKF38euOZmW8BG0,4150
4
+ veris_ai/api_client.py,sha256=ZtxskNdAG_ASx_y2VhzV0vdG2kW5Ph5gPDBn-FG44-4,4654
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=olb_ywR88meK_FyoDVHpVnIi0h0B9oWM5IHV7k3hcko,24240
8
- veris_ai/utils.py,sha256=2fzXcsKQGLm1Q1ntjtuC_Z5l6Atj56zQE723m3zXdGg,16357
7
+ veris_ai/tool_mock.py,sha256=A1k_llfjbMsMXP9J1M9pLhYVyNGxaLACaL6vsTc0zoI,25108
8
+ veris_ai/utils.py,sha256=qwPPxS0CrsS36OoN_924hricz9jGRXx9FSDgLok0wgY,18940
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.13.0.dist-info/METADATA,sha256=5yQZuNyfZdG4QiJd30nTHkwm_e2B8WRp4DbCXequnmk,16684
14
- veris_ai-1.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- veris_ai-1.13.0.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
16
- veris_ai-1.13.0.dist-info/RECORD,,
13
+ veris_ai-1.14.1.dist-info/METADATA,sha256=C2JsiZwQNZcdW5uIX45fN2-sU3feqUyZJYMLR--VWKk,16684
14
+ veris_ai-1.14.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ veris_ai-1.14.1.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
16
+ veris_ai-1.14.1.dist-info/RECORD,,