veris-ai 1.2.0__py3-none-any.whl → 1.4.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/tool_mock.py CHANGED
@@ -15,6 +15,12 @@ from typing import (
15
15
 
16
16
  import httpx
17
17
 
18
+ from veris_ai.logging import (
19
+ log_tool_call_async,
20
+ log_tool_call_sync,
21
+ log_tool_response_async,
22
+ log_tool_response_sync,
23
+ )
18
24
  from veris_ai.models import ResponseExpectation
19
25
  from veris_ai.utils import convert_to_type, extract_json_schema
20
26
 
@@ -92,23 +98,16 @@ class VerisSDK:
92
98
  **params_dict,
93
99
  )
94
100
 
95
- def mock(
101
+ def mock( # noqa: C901, PLR0915
96
102
  self,
97
- mode: Literal["tool", "function"] = "tool",
103
+ mode: Literal["tool", "function", "spy"] = "tool",
98
104
  expects_response: bool | None = None,
99
105
  cache_response: bool | None = None,
100
106
  ) -> Callable:
101
107
  """Decorator for mocking tool calls."""
102
108
 
103
- def decorator(func: Callable) -> Callable:
109
+ def decorator(func: Callable) -> Callable: # noqa: C901, PLR0915
104
110
  """Decorator for mocking tool calls."""
105
- endpoint = os.getenv("VERIS_MOCK_ENDPOINT_URL")
106
- if not endpoint:
107
- error_msg = "VERIS_MOCK_ENDPOINT_URL environment variable is not set"
108
- raise ValueError(error_msg)
109
- # Default timeout of 30 seconds
110
- timeout = float(os.getenv("VERIS_MOCK_TIMEOUT", "90.0"))
111
-
112
111
  # Check if the original function is async
113
112
  is_async = inspect.iscoroutinefunction(func)
114
113
 
@@ -148,7 +147,7 @@ class VerisSDK:
148
147
  response_expectation = ResponseExpectation.REQUIRED
149
148
  else:
150
149
  response_expectation = ResponseExpectation.AUTO
151
-
150
+
152
151
  payload = {
153
152
  "session_id": self.session_id,
154
153
  "response_expectation": response_expectation.value,
@@ -169,11 +168,46 @@ class VerisSDK:
169
168
  **kwargs: dict[str, object],
170
169
  ) -> object:
171
170
  # Check if we're in simulation mode
172
- env_mode = os.getenv("ENV", "").lower()
173
- if env_mode != "simulation":
171
+ if not self.session_id:
174
172
  # If not in simulation mode, execute the original function
175
173
  return await func(*args, **kwargs)
176
-
174
+
175
+ # Handle spy mode - execute original function and log
176
+ if mode == "spy":
177
+ logger.info(f"Spying on function: {func.__name__}")
178
+
179
+ # Log the tool call
180
+ sig = inspect.signature(func)
181
+ bound_args = sig.bind(*args, **kwargs)
182
+ bound_args.apply_defaults()
183
+ _ = bound_args.arguments.pop("ctx", None)
184
+ _ = bound_args.arguments.pop("self", None)
185
+ _ = bound_args.arguments.pop("cls", None)
186
+
187
+ await log_tool_call_async(
188
+ session_id=self.session_id,
189
+ function_name=func.__name__,
190
+ parameters=bound_args.arguments,
191
+ docstring=inspect.getdoc(func) or "",
192
+ )
193
+
194
+ # Execute the original function
195
+ result = await func(*args, **kwargs)
196
+
197
+ # Log the response
198
+ await log_tool_response_async(session_id=self.session_id, response=result)
199
+
200
+ return result
201
+
202
+ # Regular mock mode
203
+ base_url = os.getenv("VERIS_ENDPOINT_URL")
204
+ if not base_url:
205
+ error_msg = "VERIS_ENDPOINT_URL environment variable is not set"
206
+ raise ValueError(error_msg)
207
+ endpoint = f"{base_url.rstrip('/')}/api/v2/tool_mock"
208
+ # Default timeout of 30 seconds
209
+ timeout = float(os.getenv("VERIS_MOCK_TIMEOUT", "90.0"))
210
+
177
211
  logger.info(f"Simulating function: {func.__name__}")
178
212
  payload, return_type_obj = create_mock_payload(*args, **kwargs)
179
213
 
@@ -196,11 +230,46 @@ class VerisSDK:
196
230
  **kwargs: dict[str, object],
197
231
  ) -> object:
198
232
  # Check if we're in simulation mode
199
- env_mode = os.getenv("ENV", "").lower()
200
- if env_mode != "simulation":
233
+ if not self.session_id:
201
234
  # If not in simulation mode, execute the original function
202
235
  return func(*args, **kwargs)
203
-
236
+
237
+ # Handle spy mode - execute original function and log
238
+ if mode == "spy":
239
+ logger.info(f"Spying on function: {func.__name__}")
240
+
241
+ # Log the tool call
242
+ sig = inspect.signature(func)
243
+ bound_args = sig.bind(*args, **kwargs)
244
+ bound_args.apply_defaults()
245
+ _ = bound_args.arguments.pop("ctx", None)
246
+ _ = bound_args.arguments.pop("self", None)
247
+ _ = bound_args.arguments.pop("cls", None)
248
+
249
+ log_tool_call_sync(
250
+ session_id=self.session_id,
251
+ function_name=func.__name__,
252
+ parameters=bound_args.arguments,
253
+ docstring=inspect.getdoc(func) or "",
254
+ )
255
+
256
+ # Execute the original function
257
+ result = func(*args, **kwargs)
258
+
259
+ # Log the response
260
+ log_tool_response_sync(session_id=self.session_id, response=result)
261
+
262
+ return result
263
+
264
+ # Regular mock mode
265
+ base_url = os.getenv("VERIS_ENDPOINT_URL")
266
+ if not base_url:
267
+ error_msg = "VERIS_ENDPOINT_URL environment variable is not set"
268
+ raise ValueError(error_msg)
269
+ endpoint = f"{base_url.rstrip('/')}/api/v2/tool_mock"
270
+ # Default timeout of 30 seconds
271
+ timeout = float(os.getenv("VERIS_MOCK_TIMEOUT", "90.0"))
272
+
204
273
  logger.info(f"Simulating function: {func.__name__}")
205
274
  payload, return_type_obj = create_mock_payload(*args, **kwargs)
206
275
 
@@ -228,26 +297,24 @@ class VerisSDK:
228
297
  def decorator(func: Callable) -> Callable:
229
298
  # Check if the original function is async
230
299
  is_async = inspect.iscoroutinefunction(func)
231
-
300
+
232
301
  @wraps(func)
233
302
  async def async_wrapper(
234
303
  *args: tuple[object, ...],
235
304
  **kwargs: dict[str, object],
236
305
  ) -> object:
237
- env_mode = os.getenv("ENV", "").lower()
238
- if env_mode != "simulation":
306
+ if not self.session_id:
239
307
  # If not in simulation mode, execute the original function
240
- return func(*args, **kwargs)
241
- logger.info(f"Simulating function: {func.__name__}")
308
+ return await func(*args, **kwargs)
309
+ logger.info(f"Stubbing function: {func.__name__}")
242
310
  return return_value
243
-
311
+
244
312
  @wraps(func)
245
313
  def sync_wrapper(*args: tuple[object, ...], **kwargs: dict[str, object]) -> object:
246
- env_mode = os.getenv("ENV", "").lower()
247
- if env_mode != "simulation":
314
+ if not self.session_id:
248
315
  # If not in simulation mode, execute the original function
249
316
  return func(*args, **kwargs)
250
- logger.info(f"Simulating function: {func.__name__}")
317
+ logger.info(f"Stubbing function: {func.__name__}")
251
318
  return return_value
252
319
 
253
320
  # Return the appropriate wrapper based on whether the function is async
veris_ai/utils.py CHANGED
@@ -74,6 +74,9 @@ def _convert_simple_type(value: object, target_type: type) -> object:
74
74
  with suppress(TypeError):
75
75
  return target_type(**value)
76
76
 
77
+ if target_type is types.NoneType:
78
+ return None
79
+
77
80
  return target_type(value)
78
81
 
79
82
 
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.4
2
+ Name: veris-ai
3
+ Version: 1.4.0
4
+ Summary: A Python package for Veris AI tools
5
+ Project-URL: Homepage, https://github.com/veris-ai/veris-python-sdk
6
+ Project-URL: Bug Tracker, https://github.com/veris-ai/veris-python-sdk/issues
7
+ Author-email: Mehdi Jamei <mehdi@veris.ai>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: httpx>=0.24.0
12
+ Requires-Dist: pydantic>=2.0.0
13
+ Requires-Dist: requests>=2.31.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: black>=23.7.0; extra == 'dev'
16
+ Requires-Dist: mypy>=1.5.1; extra == 'dev'
17
+ Requires-Dist: openai-agents>=0.0.1; extra == 'dev'
18
+ Requires-Dist: pre-commit>=3.3.3; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=0.21.1; extra == 'dev'
20
+ Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
21
+ Requires-Dist: pytest>=7.4.0; extra == 'dev'
22
+ Requires-Dist: ruff>=0.11.4; extra == 'dev'
23
+ Provides-Extra: fastapi
24
+ Requires-Dist: fastapi; extra == 'fastapi'
25
+ Requires-Dist: fastapi-mcp; extra == 'fastapi'
26
+ Provides-Extra: instrument
27
+ Requires-Dist: braintrust; extra == 'instrument'
28
+ Requires-Dist: opentelemetry-api; extra == 'instrument'
29
+ Requires-Dist: opentelemetry-exporter-otlp; extra == 'instrument'
30
+ Requires-Dist: opentelemetry-exporter-otlp-proto-common; extra == 'instrument'
31
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc; extra == 'instrument'
32
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http; extra == 'instrument'
33
+ Requires-Dist: opentelemetry-sdk; extra == 'instrument'
34
+ Requires-Dist: wrapt; extra == 'instrument'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Veris AI Python SDK
38
+
39
+ A Python package for Veris AI tools with simulation capabilities and FastAPI MCP (Model Context Protocol) integration.
40
+
41
+ ## Quick Reference
42
+
43
+ **Purpose**: Tool mocking, tracing, and FastAPI MCP integration for AI agent development
44
+ **Core Components**: [`tool_mock`](#function-mocking) • [`jaeger_interface`](#jaeger-trace-interface) • [`braintrust_tracing`](#tracing-integration) • [`fastapi_mcp`](#fastapi-mcp-integration)
45
+ **Deep Dive**: [`Module Architecture`](src/veris_ai/README.md) • [`Testing Guide`](tests/README.md) • [`Usage Examples`](examples/README.md)
46
+ **Source of Truth**: Implementation details in [`src/veris_ai/`](src/veris_ai/) source code
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ # Base package
52
+ uv add veris-ai
53
+
54
+ # With optional extras
55
+ uv add "veris-ai[dev,fastapi,instrument]"
56
+ ```
57
+
58
+ **Installation Profiles**:
59
+ - `dev`: Development tools (ruff, pytest, mypy)
60
+ - `fastapi`: FastAPI MCP integration
61
+ - `instrument`: Braintrust/OpenTelemetry tracing
62
+
63
+ ## Import Patterns
64
+
65
+ **Semantic Tag**: `import-patterns`
66
+
67
+ ```python
68
+ # Core imports (base dependencies only)
69
+ from veris_ai import veris, JaegerClient
70
+
71
+ # Optional features (require extras)
72
+ from veris_ai import braintrust_tracing # Requires [instrument]
73
+ ```
74
+
75
+ **Complete Import Strategies**: See [`examples/README.md`](examples/README.md) for five different import approaches, conditional features, and integration patterns.
76
+
77
+ ## Configuration
78
+
79
+ **Semantic Tag**: `environment-config`
80
+
81
+ | Variable | Purpose | Default |
82
+ |----------|---------|---------|
83
+ | `VERIS_ENDPOINT_URL` | Mock server endpoint | *Required* |
84
+ | `VERIS_MOCK_TIMEOUT` | Request timeout (seconds) | `90.0` |
85
+ | `ENV` | Set to `"simulation"` for mock mode | Production |
86
+ | `VERIS_SERVICE_NAME` | Tracing service name | Auto-detected |
87
+ | `VERIS_OTLP_ENDPOINT` | OpenTelemetry collector | *Required for tracing* |
88
+
89
+ **Configuration Details**: See [`src/veris_ai/tool_mock.py`](src/veris_ai/tool_mock.py) for environment handling logic.
90
+
91
+ ## Tracing Integration
92
+
93
+ **Semantic Tag**: `distributed-tracing`
94
+
95
+ Parallel tracing to Braintrust and Jaeger/OpenTelemetry for monitoring and evaluation.
96
+
97
+ ```python
98
+ from veris_ai import braintrust_tracing
99
+
100
+ # Enable dual tracing
101
+ braintrust_tracing.instrument(service_name="my-service", otlp_endpoint="http://localhost:4317")
102
+ ```
103
+
104
+ **Session Management**: Automatic session ID extraction from bearer tokens. Manual session control via `veris.set_session_id()` and `veris.clear_session_id()`.
105
+
106
+ **Implementation Details**: See [`src/veris_ai/braintrust_tracing.py`](src/veris_ai/braintrust_tracing.py) for instrumentation logic.
107
+
108
+ ## Function Mocking
109
+
110
+ **Semantic Tag**: `tool-mocking`
111
+
112
+ ### Core Decorators
113
+
114
+ ```python
115
+ from veris_ai import veris
116
+
117
+ # Mock mode: Returns simulated responses in ENV=simulation
118
+ @veris.mock()
119
+ async def your_function(param1: str, param2: int) -> dict:
120
+ """Function documentation for LLM context."""
121
+ return {"result": "actual implementation"}
122
+
123
+ # Spy mode: Executes function but logs calls/responses
124
+ @veris.mock(mode="spy")
125
+ async def monitored_function(data: str) -> dict:
126
+ return process_data(data)
127
+
128
+ # Stub mode: Returns fixed value in simulation
129
+ @veris.stub(return_value={"status": "success"})
130
+ async def get_data() -> dict:
131
+ return await fetch_from_api()
132
+ ```
133
+
134
+ **Behavior**: In simulation mode, decorators intercept calls to mock endpoints. In production, functions execute normally.
135
+
136
+ **Implementation**: See [`src/veris_ai/tool_mock.py`](src/veris_ai/tool_mock.py) for decorator logic and API integration.
137
+
138
+ ## FastAPI MCP Integration
139
+
140
+ **Semantic Tag**: `fastapi-mcp`
141
+
142
+ Expose FastAPI endpoints as MCP tools for AI agent consumption.
143
+
144
+ ```python
145
+ from fastapi import FastAPI
146
+ from veris_ai import veris
147
+
148
+ app = FastAPI()
149
+
150
+ # Enable MCP integration
151
+ veris.set_fastapi_mcp(
152
+ fastapi=app,
153
+ name="My API Server",
154
+ include_operations=["get_users", "create_user"],
155
+ exclude_tags=["internal"]
156
+ )
157
+ ```
158
+
159
+ **Key Features**:
160
+ - **Automatic schema conversion**: FastAPI OpenAPI → MCP tool definitions
161
+ - **Session management**: Bearer token → session ID mapping
162
+ - **Filtering**: Include/exclude operations and tags
163
+ - **Authentication**: OAuth2 integration
164
+
165
+ **Configuration Reference**: See function signature in [`src/veris_ai/tool_mock.py`](src/veris_ai/tool_mock.py) for all `set_fastapi_mcp()` parameters.
166
+
167
+ ## Utility Functions
168
+
169
+ **Semantic Tag**: `json-schema-utils`
170
+
171
+ ```python
172
+ from veris_ai.utils import extract_json_schema
173
+
174
+ # Schema extraction from types
175
+ user_schema = extract_json_schema(User) # Pydantic models
176
+ list_schema = extract_json_schema(List[str]) # Generics
177
+ ```
178
+
179
+ **Supported Types**: Built-in types, generics (List, Dict, Union), Pydantic models, TypedDict, forward references.
180
+
181
+ **Implementation**: See [`src/veris_ai/utils.py`](src/veris_ai/utils.py) for type conversion logic.
182
+
183
+ ## Development
184
+
185
+ **Semantic Tag**: `development-setup`
186
+
187
+ **Requirements**: Python 3.11+, `uv` package manager
188
+
189
+ ```bash
190
+ # Install with dev dependencies
191
+ uv add "veris-ai[dev]"
192
+
193
+ # Quality checks
194
+ ruff check --fix . # Lint and format
195
+ pytest --cov=veris_ai # Test with coverage
196
+ ```
197
+
198
+ **Testing & Architecture**: See [`tests/README.md`](tests/README.md) for test structure, fixtures, and coverage strategies. See [`src/veris_ai/README.md`](src/veris_ai/README.md) for module architecture and implementation flows.
199
+
200
+ ## Module Architecture
201
+
202
+ **Semantic Tag**: `module-architecture`
203
+
204
+ **Core Modules**: `tool_mock` (mocking), `jaeger_interface` (trace queries), `braintrust_tracing` (dual tracing), `utils` (schema conversion)
205
+
206
+ **Complete Architecture**: See [`src/veris_ai/README.md`](src/veris_ai/README.md) for module overview, implementation flows, and configuration details.
207
+
208
+ ## Jaeger Trace Interface
209
+
210
+ **Semantic Tag**: `jaeger-query-api`
211
+
212
+ ```python
213
+ from veris_ai.jaeger_interface import JaegerClient
214
+
215
+ client = JaegerClient("http://localhost:16686")
216
+ traces = client.search(service="veris-agent", tags={"error": "true"})
217
+ ```
218
+
219
+ **Complete Guide**: See [`src/veris_ai/jaeger_interface/README.md`](src/veris_ai/jaeger_interface/README.md) for API reference, filtering strategies, and architecture details.
220
+
221
+ ---
222
+
223
+ **License**: MIT License - see [LICENSE](LICENSE) file for details.
@@ -0,0 +1,15 @@
1
+ veris_ai/README.md,sha256=q0Qn6gu85HWU189SmyOygY_mkNj0l10wlAVy9kj4udo,3120
2
+ veris_ai/__init__.py,sha256=Vp5yf9ZRchw0mmPwrRuNebI5cb2NGwpJGfr41l86q1U,1177
3
+ veris_ai/braintrust_tracing.py,sha256=0i-HR6IuK3-Q5ujMjT1FojxESRZLgqEvJ44bfJfDHaw,11938
4
+ veris_ai/logging.py,sha256=2855E8s_k6yTnzFK10EQR4WQngQk3VuWFPJW-MYiw3k,3837
5
+ veris_ai/models.py,sha256=6HINPxNFCakCVPcyEbUswWkXwb2K4lF0A8g8EvTMal4,213
6
+ veris_ai/tool_mock.py,sha256=9rb4c8OZEg6hGmyJlmgFSmbBDa7L6_XzadvtVrGy9xs,13198
7
+ veris_ai/utils.py,sha256=aqFFNuNiBehil6874nOHtU7G_bWHbFpVuubcz2AIx6I,9267
8
+ veris_ai/jaeger_interface/README.md,sha256=kd9rKcE5xf3EyNaiHu0tjn-0oES9sfaK6Ih-OhhTyCM,2821
9
+ veris_ai/jaeger_interface/__init__.py,sha256=d873a0zq3eUYU2Y77MtdjCwIARjAsAP7WDqGXDMWpYs,1158
10
+ veris_ai/jaeger_interface/client.py,sha256=yJrh86wRR0Dk3Gq12DId99WogcMIVbL0QQFqVSevvlE,8772
11
+ veris_ai/jaeger_interface/models.py,sha256=e64VV6IvOEFuzRUgvDAMQFyOZMRb56I-PUPZLBZ3rX0,1864
12
+ veris_ai-1.4.0.dist-info/METADATA,sha256=yq1IbvlQ7qME6BdFz3tQ9-b0x9Oblcu2OJNUGS3iNVE,7702
13
+ veris_ai-1.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ veris_ai-1.4.0.dist-info/licenses/LICENSE,sha256=2g4i20atAgtD5einaKzhQrIB-JrPhyQgD3bC0wkHcCI,1065
15
+ veris_ai-1.4.0.dist-info/RECORD,,