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

Potentially problematic release.


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

veris_ai/README.md CHANGED
@@ -28,15 +28,15 @@ This module contains the core implementation of the Veris AI Python SDK. Each co
28
28
  ### Mock Flow
29
29
  1. **Decoration**: `@veris.mock()` captures function metadata
30
30
  2. **Session Check**: Presence of session ID determines behavior
31
- 3. **API Call**: POST to VERIS API endpoint `/v2/tool_mock` (auto-configured)
31
+ 3. **API Call**: POST to VERIS API endpoint `/v3/tool_mock` (auto-configured)
32
32
  4. **Type Conversion**: Response converted using `extract_json_schema()`
33
33
 
34
34
  **Implementation**: [`tool_mock.py:200-250`](tool_mock.py)
35
35
 
36
36
  ### Spy Flow
37
- 1. **Pre-execution Logging**: Call details sent to `/v2/simulations/{session_id}/log_tool_call`
37
+ 1. **Pre-execution Logging**: Call details sent to `v3/log_tool_call?session_id={session_id}`
38
38
  2. **Function Execution**: Original function runs normally
39
- 3. **Post-execution Logging**: Response sent to `/v2/simulations/{session_id}/log_tool_response`
39
+ 3. **Post-execution Logging**: Response sent to `v3/log_tool_response?session_id={session_id}`
40
40
 
41
41
  **Implementation**: [`tool_mock.py:250-300`](tool_mock.py)
42
42
 
veris_ai/api_client.py CHANGED
@@ -63,15 +63,15 @@ class SimulatorAPIClient:
63
63
  @property
64
64
  def tool_mock_endpoint(self) -> str:
65
65
  """Get the tool mock endpoint URL."""
66
- return urljoin(self._get_base_url(), "v2/tool_mock")
66
+ return urljoin(self._get_base_url(), "v3/tool_mock")
67
67
 
68
68
  def get_log_tool_call_endpoint(self, session_id: str) -> str:
69
69
  """Get the log tool call endpoint URL."""
70
- return urljoin(self._get_base_url(), f"v2/simulations/{session_id}/log_tool_call")
70
+ return urljoin(self._get_base_url(), f"v3/log_tool_call?session_id={session_id}")
71
71
 
72
72
  def get_log_tool_response_endpoint(self, session_id: str) -> str:
73
73
  """Get the log tool response endpoint URL."""
74
- return urljoin(self._get_base_url(), f"v2/simulations/{session_id}/log_tool_response")
74
+ return urljoin(self._get_base_url(), f"v3/log_tool_response?session_id={session_id}")
75
75
 
76
76
 
77
77
  # Global singleton instance
veris_ai/tool_mock.py CHANGED
@@ -1,3 +1,4 @@
1
+ import base64
1
2
  import inspect
2
3
  import json
3
4
  import logging
@@ -22,8 +23,9 @@ logger = logging.getLogger(__name__)
22
23
 
23
24
  T = TypeVar("T")
24
25
 
25
- # Context variable to store session_id for each call
26
+ # Context variables to store session_id and thread_id for each call
26
27
  _session_id_context: ContextVar[str | None] = ContextVar("veris_session_id", default=None)
28
+ _thread_id_context: ContextVar[str | None] = ContextVar("veris_thread_id", default=None)
27
29
 
28
30
 
29
31
  class VerisSDK:
@@ -38,15 +40,111 @@ class VerisSDK:
38
40
  """Get the session_id from context variable."""
39
41
  return _session_id_context.get()
40
42
 
41
- def set_session_id(self, session_id: str) -> None:
42
- """Set the session_id in context variable."""
43
+ @property
44
+ def thread_id(self) -> str | None:
45
+ """Get the thread_id from context variable."""
46
+ return _thread_id_context.get()
47
+
48
+ def _set_session_id(self, session_id: str) -> None:
49
+ """Set the session_id in context variable (private method)."""
43
50
  _session_id_context.set(session_id)
44
- logger.info(f"Session ID set to {session_id}")
45
51
 
46
- def clear_session_id(self) -> None:
47
- """Clear the session_id from context variable."""
52
+ def _set_thread_id(self, thread_id: str) -> None:
53
+ """Set the thread_id in context variable (private method)."""
54
+ _thread_id_context.set(thread_id)
55
+
56
+ def parse_token(self, token: str) -> None:
57
+ """Parse and set session_id and thread_id from a base64-encoded token.
58
+
59
+ The token must be a base64-encoded JSON object containing:
60
+ {"session_id": "...", "thread_id": "..."}
61
+
62
+ Both session_id and thread_id are required fields.
63
+
64
+ Args:
65
+ token: Base64-encoded JSON token
66
+
67
+ Raises:
68
+ ValueError: If token is not valid or missing required fields
69
+ """
70
+ try:
71
+ # Decode base64 JSON token
72
+ decoded = base64.b64decode(token.encode("utf-8")).decode("utf-8")
73
+ token_data = json.loads(decoded)
74
+
75
+ if not isinstance(token_data, dict):
76
+ raise ValueError("Token must decode to a JSON object")
77
+
78
+ if "session_id" not in token_data:
79
+ raise ValueError("Token must contain 'session_id' field")
80
+
81
+ if "thread_id" not in token_data:
82
+ raise ValueError("Token must contain 'thread_id' field")
83
+
84
+ self._set_session_id(token_data["session_id"])
85
+ self._set_thread_id(token_data["thread_id"])
86
+ logger.info(
87
+ f"Session ID set to {token_data['session_id']}, "
88
+ f"Thread ID set to {token_data['thread_id']} - mocking enabled"
89
+ )
90
+
91
+ except (ValueError, json.JSONDecodeError) as e:
92
+ error_msg = f"Invalid token format: {e}"
93
+ raise ValueError(error_msg) from e
94
+
95
+ def set_session_id(self, token: str) -> None:
96
+ """DEPRECATED: Use parse_token() instead.
97
+
98
+ Set the session_id and thread_id from a base64-encoded token.
99
+
100
+ Args:
101
+ token: Base64-encoded JSON token
102
+ """
103
+ logger.warning(
104
+ "set_session_id() is deprecated. Use parse_token() instead. "
105
+ "This method will be removed in a future version."
106
+ )
107
+ # For backwards compatibility, allow tokens without thread_id
108
+ try:
109
+ decoded = base64.b64decode(token.encode("utf-8")).decode("utf-8")
110
+ token_data = json.loads(decoded)
111
+
112
+ if not isinstance(token_data, dict):
113
+ raise ValueError("Token must decode to a JSON object")
114
+
115
+ if "session_id" not in token_data:
116
+ raise ValueError("Token must contain 'session_id' field")
117
+
118
+ self._set_session_id(token_data["session_id"])
119
+ if "thread_id" in token_data:
120
+ self._set_thread_id(token_data["thread_id"])
121
+ logger.info(f"Session ID set to {token_data['session_id']}")
122
+
123
+ except (ValueError, json.JSONDecodeError) as e:
124
+ error_msg = f"Invalid token format: {e}"
125
+ raise ValueError(error_msg) from e
126
+
127
+ def _clear_session_id(self) -> None:
128
+ """Clear the session_id from context variable (private method)."""
48
129
  _session_id_context.set(None)
49
- logger.info("Session ID cleared")
130
+
131
+ def _clear_thread_id(self) -> None:
132
+ """Clear the thread_id from context variable (private method)."""
133
+ _thread_id_context.set(None)
134
+
135
+ def clear_context(self) -> None:
136
+ """Clear the session_id and thread_id from context variables."""
137
+ self._clear_session_id()
138
+ self._clear_thread_id()
139
+ logger.info("Session ID and Thread ID cleared - mocking disabled")
140
+
141
+ def clear_session_id(self) -> None:
142
+ """DEPRECATED: Use clear_context() instead."""
143
+ logger.warning(
144
+ "clear_session_id() is deprecated. Use clear_context() instead. "
145
+ "This method will be removed in a future version."
146
+ )
147
+ self.clear_context()
50
148
 
51
149
  @property
52
150
  def fastapi_mcp(self) -> Any | None: # noqa: ANN401
@@ -69,7 +167,7 @@ class VerisSDK:
69
167
  token: str | None = Depends(oauth2_scheme),
70
168
  ) -> None:
71
169
  if token:
72
- self.set_session_id(token)
170
+ self.parse_token(token)
73
171
 
74
172
  # Create auth config with dependencies
75
173
  auth_config = AuthConfig(
@@ -176,11 +274,13 @@ class VerisSDK:
176
274
  )
177
275
  return await func(*args, **kwargs)
178
276
  parameters = get_function_parameters(func, args, kwargs)
277
+ thread_id = _thread_id_context.get()
179
278
  return mock_tool_call(
180
279
  func,
181
280
  session_id,
182
281
  parameters,
183
282
  options,
283
+ thread_id,
184
284
  )
185
285
 
186
286
  @wraps(func)
@@ -196,11 +296,13 @@ class VerisSDK:
196
296
  )
197
297
  return func(*args, **kwargs)
198
298
  parameters = get_function_parameters(func, args, kwargs)
299
+ thread_id = _thread_id_context.get()
199
300
  return mock_tool_call(
200
301
  func,
201
302
  session_id,
202
303
  parameters,
203
304
  options,
305
+ thread_id,
204
306
  )
205
307
 
206
308
  # Return the appropriate wrapper based on whether the function is async
@@ -251,11 +353,29 @@ class VerisSDK:
251
353
  )
252
354
  def mock_tool_call(
253
355
  func: Callable,
254
- session_id: str,
356
+ session_id: str, # noqa: ARG001
255
357
  parameters: dict[str, dict[str, str]],
256
358
  options: ToolCallOptions | None = None,
359
+ thread_id: str | None = None,
257
360
  ) -> object:
258
- """Mock tool call."""
361
+ """Mock tool call.
362
+
363
+ Args:
364
+ func: Function being mocked
365
+ session_id: Session ID (kept for backwards compatibility, not used)
366
+ parameters: Function parameters
367
+ options: Tool call options
368
+ thread_id: Thread ID to use as session_id in API request (required)
369
+
370
+ Raises:
371
+ ValueError: If thread_id is not provided
372
+ """
373
+ if thread_id is None:
374
+ raise ValueError(
375
+ "thread_id is required for mocking. "
376
+ "Use parse_token() to set both session_id and thread_id."
377
+ )
378
+
259
379
  options = options or ToolCallOptions()
260
380
  api_client = get_api_client()
261
381
  endpoint = api_client.tool_mock_endpoint
@@ -269,6 +389,8 @@ def mock_tool_call(
269
389
  # Get function docstring
270
390
  docstring = inspect.getdoc(func) or ""
271
391
 
392
+ # Use thread_id as session_id in the payload
393
+ payload_session_id = thread_id
272
394
  # Clean up parameters for V3 - just send values, not the nested dict
273
395
  clean_params: dict[str, Any] = {}
274
396
  for key, value in parameters.items():
@@ -281,7 +403,7 @@ def mock_tool_call(
281
403
 
282
404
  # Determine response expectation
283
405
  payload = {
284
- "session_id": session_id,
406
+ "session_id": payload_session_id,
285
407
  "response_expectation": options.response_expectation.value,
286
408
  "cache_response": bool(options.cache_response),
287
409
  "tool_call": {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: veris-ai
3
- Version: 1.11.0
3
+ Version: 1.12.0
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
@@ -135,7 +135,7 @@ What this enables:
135
135
 
136
136
  End-to-end propagation with the simulator:
137
137
  - The simulator injects W3C headers when connecting to your FastAPI MCP endpoints
138
- - The SDK injects W3C headers on `/v2/tool_mock` and logging requests back to the simulator
138
+ - The SDK injects W3C headers on `/v3/tool_mock` and logging requests back to the simulator
139
139
  - Result: customer agent spans and tool mocks appear under the same distributed trace
140
140
 
141
141
  ## Function Mocking
@@ -1,16 +1,16 @@
1
- veris_ai/README.md,sha256=Ht1abGu-2_O0ZHJoJC7eAfG5WhO2CstAuV3hXPq1yAs,3875
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=N-YZ0qvIEJ8rlFZAzVKg6eWKa7I_qIt-khlg_zL-qY8,11931
4
- veris_ai/api_client.py,sha256=385u11QuKq4Qk_WkI4Z5yOxAWJcV57VCGLYU5NIfnmo,3201
4
+ veris_ai/api_client.py,sha256=BQ2Fn5pO7uaWmWNcLOoZO8o-D39OPRmclPROwJvXBUc,3199
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=--t0ZhjplJXzBt1F--XPE57ZyMBjB9SOjO2OzuoWkbk,12861
7
+ veris_ai/tool_mock.py,sha256=h_nS0tTOl8eI_Hb-HNuurjbBPp0ThdMnJwsMXfRyT7I,17489
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.11.0.dist-info/METADATA,sha256=4ktkFw8WMexIqWwCtuRbFriJSVgAJp3_v0uny4R8lic,15259
14
- veris_ai-1.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- veris_ai-1.11.0.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
16
- veris_ai-1.11.0.dist-info/RECORD,,
13
+ veris_ai-1.12.0.dist-info/METADATA,sha256=NvHOxiR8I1gNUBmytOWjB5JvMy_bY9JYhObeoiGmPk8,15259
14
+ veris_ai-1.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ veris_ai-1.12.0.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
16
+ veris_ai-1.12.0.dist-info/RECORD,,