vectorwave 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {vectorwave-0.2.2/src/vectorwave.egg-info → vectorwave-0.2.3}/PKG-INFO +1 -1
- {vectorwave-0.2.2 → vectorwave-0.2.3}/pyproject.toml +1 -1
- vectorwave-0.2.3/src/tests/utils/test_replay_source.py +140 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/decorator.py +7 -4
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/database/db.py +5 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/tracer.py +3 -1
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/search/execution_search.py +31 -0
- vectorwave-0.2.3/src/vectorwave/utils/context.py +4 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/replayer.py +8 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/replayer_semantic.py +6 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3/src/vectorwave.egg-info}/PKG-INFO +1 -1
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave.egg-info/SOURCES.txt +2 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/LICENSE +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/MANIFEST.in +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/NOTICE +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/Readme.md +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/setup.cfg +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/batch/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/batch/test_batch.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/conftest.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/core/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/core/llm/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/core/llm/test_token_usage.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/core/test_decorator.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/core/test_semantic_caching.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/database/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/database/test_archiver.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/database/test_dataset.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/database/test_db.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/database/test_db_search.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/exception/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/models/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/models/test_db_config.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/monitoring/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/monitoring/alert/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/monitoring/alert/test_alerter.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/monitoring/test_async_trace.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/monitoring/test_tracer.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/prediction/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/search/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/search/test_execution_search.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/utils/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/utils/test_function_cahe.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/utils/test_replayer.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/utils/test_return_caching.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/utils/test_status.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/tests/vectorizer/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/batch/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/batch/batch.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/core.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/generator.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/llm/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/llm/base.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/llm/factory.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/core/llm/openai_client.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/database/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/database/archiver.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/database/dataset.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/database/db_search.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/exception/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/exception/exceptions.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/models/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/models/db_config.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/alert/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/alert/base.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/alert/factory.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/alert/null_alerter.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/alert/webhook_alerter.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/monitoring/monitoring.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/prediction/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/prediction/predictor.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/search/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/search/extended_search.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/search/rag_search.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/function_cache.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/healer.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/return_caching_utils.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/utils/status.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/vectorizer/__init__.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/vectorizer/base.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/vectorizer/factory.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/vectorizer/huggingface_vectorizer.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave/vectorizer/openai_vectorizer.py +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave.egg-info/dependency_links.txt +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave.egg-info/requires.txt +0 -0
- {vectorwave-0.2.2 → vectorwave-0.2.3}/src/vectorwave.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import sys
|
|
3
|
+
from unittest.mock import MagicMock, patch
|
|
4
|
+
from vectorwave import vectorize, search_executions
|
|
5
|
+
from vectorwave.utils.replayer import VectorWaveReplayer
|
|
6
|
+
from vectorwave.models.db_config import WeaviateSettings
|
|
7
|
+
|
|
8
|
+
# 1. Dummy function for testing
|
|
9
|
+
@vectorize(unique_id="test_replay_tagging")
|
|
10
|
+
def calc_add(a: int, b: int):
|
|
11
|
+
"""Simple addition function for testing replay tags."""
|
|
12
|
+
return a + b
|
|
13
|
+
|
|
14
|
+
@pytest.fixture
|
|
15
|
+
def mock_replay_deps(monkeypatch):
|
|
16
|
+
"""Mocks dependencies for Replay Source testing."""
|
|
17
|
+
# Mock Settings
|
|
18
|
+
mock_settings = WeaviateSettings(
|
|
19
|
+
EXECUTION_COLLECTION_NAME="VectorWaveExecutions",
|
|
20
|
+
GOLDEN_COLLECTION_NAME="VectorWaveGoldenDataset"
|
|
21
|
+
)
|
|
22
|
+
mock_get_settings = MagicMock(return_value=mock_settings)
|
|
23
|
+
|
|
24
|
+
# Mock Batch Manager (to verify logs)
|
|
25
|
+
mock_batch = MagicMock()
|
|
26
|
+
mock_batch.add_object = MagicMock()
|
|
27
|
+
mock_get_batch = MagicMock(return_value=mock_batch)
|
|
28
|
+
|
|
29
|
+
# Mock DB Client (for Replayer initialization)
|
|
30
|
+
mock_client = MagicMock()
|
|
31
|
+
mock_collection = MagicMock()
|
|
32
|
+
mock_client.collections.get.return_value = mock_collection
|
|
33
|
+
mock_get_client = MagicMock(return_value=mock_client)
|
|
34
|
+
|
|
35
|
+
# --- [수정] Patch dependencies where they are USED, not just defined ---
|
|
36
|
+
|
|
37
|
+
# 1. Patch for Replayer (vectorwave/utils/replayer.py)
|
|
38
|
+
monkeypatch.setattr("vectorwave.utils.replayer.get_cached_client", mock_get_client)
|
|
39
|
+
monkeypatch.setattr("vectorwave.utils.replayer.get_weaviate_settings", mock_get_settings)
|
|
40
|
+
|
|
41
|
+
# 2. Patch for Database (vectorwave/database/db.py) - 안전장치
|
|
42
|
+
monkeypatch.setattr("vectorwave.database.db.get_cached_client", mock_get_client)
|
|
43
|
+
|
|
44
|
+
# 3. Patch for Config (vectorwave/models/db_config.py) - 안전장치
|
|
45
|
+
monkeypatch.setattr("vectorwave.models.db_config.get_weaviate_settings", mock_get_settings)
|
|
46
|
+
|
|
47
|
+
# 4. Patch batch manager for Decorator & Tracer
|
|
48
|
+
monkeypatch.setattr("vectorwave.core.decorator.get_batch_manager", mock_get_batch)
|
|
49
|
+
monkeypatch.setattr("vectorwave.monitoring.tracer.get_batch_manager", mock_get_batch)
|
|
50
|
+
|
|
51
|
+
# 5. Patch search_executions in THIS test file
|
|
52
|
+
mock_search = MagicMock()
|
|
53
|
+
monkeypatch.setattr(sys.modules[__name__], "search_executions", mock_search)
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
"batch": mock_batch,
|
|
57
|
+
"search": mock_search,
|
|
58
|
+
"client": mock_client
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def test_execution_source_tagging(mock_replay_deps):
|
|
62
|
+
"""
|
|
63
|
+
Verification Scenario:
|
|
64
|
+
1. Realtime Execution -> Check if saved to DB as 'REALTIME'
|
|
65
|
+
2. Replay Execution -> Check if saved to DB as 'REPLAY'
|
|
66
|
+
"""
|
|
67
|
+
mock_batch = mock_replay_deps["batch"]
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------
|
|
70
|
+
# Case 1: Realtime Execution
|
|
71
|
+
# ---------------------------------------------------------
|
|
72
|
+
print("\n🚀 1. Running Realtime Execution...")
|
|
73
|
+
calc_add(10, 20)
|
|
74
|
+
|
|
75
|
+
# Check if log was sent to BatchManager
|
|
76
|
+
assert mock_batch.add_object.called
|
|
77
|
+
|
|
78
|
+
# Get the latest call args
|
|
79
|
+
args, kwargs = mock_batch.add_object.call_args
|
|
80
|
+
props = kwargs['properties']
|
|
81
|
+
|
|
82
|
+
print(f" [Log Check] Source: {props.get('exec_source')}")
|
|
83
|
+
|
|
84
|
+
# Verify exec_source is 'REALTIME'
|
|
85
|
+
assert props.get("exec_source") == "REALTIME"
|
|
86
|
+
assert props.get("status") == "SUCCESS"
|
|
87
|
+
|
|
88
|
+
# ---------------------------------------------------------
|
|
89
|
+
# Case 2: Replay Execution
|
|
90
|
+
# ---------------------------------------------------------
|
|
91
|
+
print("\n🔄 2. Running Replay...")
|
|
92
|
+
|
|
93
|
+
# Prepare dummy log for Replayer to fetch
|
|
94
|
+
dummy_log_obj = MagicMock()
|
|
95
|
+
dummy_log_obj.uuid = "old-uuid-123"
|
|
96
|
+
dummy_log_obj.properties = {
|
|
97
|
+
"function_name": "calc_add",
|
|
98
|
+
"a": 10,
|
|
99
|
+
"b": 20,
|
|
100
|
+
"return_value": "30",
|
|
101
|
+
"exec_source": "REALTIME"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Replayer uses client.collections.get().query.fetch_objects()
|
|
105
|
+
mock_collection = mock_replay_deps["client"].collections.get.return_value
|
|
106
|
+
mock_collection.query.fetch_objects.return_value.objects = [dummy_log_obj]
|
|
107
|
+
|
|
108
|
+
# Also need to mock import_module since Replayer imports the function dynamically
|
|
109
|
+
with patch("vectorwave.utils.replayer.importlib.import_module") as mock_import:
|
|
110
|
+
mock_module = MagicMock()
|
|
111
|
+
# Set the function on the mock module
|
|
112
|
+
setattr(mock_module, "calc_add", calc_add)
|
|
113
|
+
mock_import.return_value = mock_module
|
|
114
|
+
|
|
115
|
+
replayer = VectorWaveReplayer()
|
|
116
|
+
|
|
117
|
+
# Reset batch mock to capture only replay log
|
|
118
|
+
mock_batch.add_object.reset_mock()
|
|
119
|
+
|
|
120
|
+
# Execute Replay
|
|
121
|
+
result = replayer.replay(
|
|
122
|
+
function_full_name="src.tests.utils.test_replay_source.calc_add",
|
|
123
|
+
limit=1
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
assert result['total'] > 0, "Replay should have executed at least 1 test."
|
|
127
|
+
|
|
128
|
+
# Check if new log was sent to BatchManager
|
|
129
|
+
assert mock_batch.add_object.called
|
|
130
|
+
|
|
131
|
+
# Get the latest call args (from Replay execution)
|
|
132
|
+
args, kwargs = mock_batch.add_object.call_args
|
|
133
|
+
replay_props = kwargs['properties']
|
|
134
|
+
|
|
135
|
+
print(f" [Log Check] Source: {replay_props.get('exec_source')}")
|
|
136
|
+
|
|
137
|
+
# Verify exec_source is 'REPLAY'
|
|
138
|
+
assert replay_props.get("exec_source") == "REPLAY"
|
|
139
|
+
|
|
140
|
+
print("\n✅ All tests passed! Execution Source tagging is working.")
|
|
@@ -11,6 +11,7 @@ from ..monitoring.tracer import trace_root, trace_span
|
|
|
11
11
|
from ..utils.function_cache import function_cache_manager
|
|
12
12
|
from ..utils.return_caching_utils import _check_and_return_cached_result
|
|
13
13
|
from ..vectorizer.factory import get_vectorizer
|
|
14
|
+
from ..utils.context import execution_source_context
|
|
14
15
|
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
@@ -53,7 +54,7 @@ def vectorize(search_description: Optional[str] = None,
|
|
|
53
54
|
func_uuid = generate_uuid5(func_identifier)
|
|
54
55
|
|
|
55
56
|
# Prepare attributes to capture
|
|
56
|
-
final_attributes = ['function_uuid', 'team', 'priority', 'run_id']
|
|
57
|
+
final_attributes = ['function_uuid', 'team', 'priority', 'run_id', 'exec_source']
|
|
57
58
|
if attributes_to_capture:
|
|
58
59
|
for attr in attributes_to_capture:
|
|
59
60
|
if attr not in final_attributes:
|
|
@@ -145,7 +146,7 @@ def vectorize(search_description: Optional[str] = None,
|
|
|
145
146
|
async def inner_wrapper(*args, **kwargs):
|
|
146
147
|
# Remove injected tags from kwargs before calling original func
|
|
147
148
|
clean_kwargs = {k: v for k, v in kwargs.items() if
|
|
148
|
-
k not in valid_execution_tags and k != 'function_uuid'}
|
|
149
|
+
k not in valid_execution_tags and k != 'function_uuid' and k != 'exec_source'}
|
|
149
150
|
return await func(*args, **clean_kwargs)
|
|
150
151
|
|
|
151
152
|
@wraps(func)
|
|
@@ -157,6 +158,7 @@ def vectorize(search_description: Optional[str] = None,
|
|
|
157
158
|
full_kwargs = kwargs.copy()
|
|
158
159
|
full_kwargs.update(valid_execution_tags)
|
|
159
160
|
full_kwargs['function_uuid'] = func_uuid
|
|
161
|
+
full_kwargs['exec_source'] = execution_source_context.get()
|
|
160
162
|
return await inner_wrapper(*args, **full_kwargs)
|
|
161
163
|
|
|
162
164
|
return outer_wrapper
|
|
@@ -167,7 +169,7 @@ def vectorize(search_description: Optional[str] = None,
|
|
|
167
169
|
@wraps(func)
|
|
168
170
|
def inner_wrapper(*args, **kwargs):
|
|
169
171
|
clean_kwargs = {k: v for k, v in kwargs.items() if
|
|
170
|
-
k not in valid_execution_tags and k != 'function_uuid'}
|
|
172
|
+
k not in valid_execution_tags and k != 'function_uuid' and k != 'exec_source'}
|
|
171
173
|
return func(*args, **clean_kwargs)
|
|
172
174
|
|
|
173
175
|
@wraps(func)
|
|
@@ -179,8 +181,9 @@ def vectorize(search_description: Optional[str] = None,
|
|
|
179
181
|
full_kwargs = kwargs.copy()
|
|
180
182
|
full_kwargs.update(valid_execution_tags)
|
|
181
183
|
full_kwargs['function_uuid'] = func_uuid
|
|
184
|
+
full_kwargs['exec_source'] = execution_source_context.get()
|
|
182
185
|
return inner_wrapper(*args, **full_kwargs)
|
|
183
186
|
|
|
184
187
|
return outer_wrapper
|
|
185
188
|
|
|
186
|
-
return decorator
|
|
189
|
+
return decorator
|
|
@@ -282,6 +282,11 @@ def create_execution_schema(client: weaviate.WeaviateClient, settings: WeaviateS
|
|
|
282
282
|
name="return_value",
|
|
283
283
|
data_type=wvc.DataType.TEXT,
|
|
284
284
|
description="The JSON-serialized or str() representation of the function's return value"
|
|
285
|
+
),
|
|
286
|
+
wvc.Property(
|
|
287
|
+
name="exec_source",
|
|
288
|
+
data_type=wvc.DataType.TEXT,
|
|
289
|
+
description="Source of execution: 'REALTIME' (User traffic) or 'REPLAY' (Regression Test)"
|
|
285
290
|
)
|
|
286
291
|
]
|
|
287
292
|
|
|
@@ -15,6 +15,7 @@ from ..models.db_config import get_weaviate_settings, WeaviateSettings
|
|
|
15
15
|
from .alert.factory import get_alerter
|
|
16
16
|
from ..vectorizer.factory import get_vectorizer
|
|
17
17
|
from ..database.db_search import check_semantic_drift
|
|
18
|
+
from ..utils.context import execution_source_context
|
|
18
19
|
|
|
19
20
|
# Create module-level logger
|
|
20
21
|
logger = logging.getLogger(__name__)
|
|
@@ -137,7 +138,8 @@ def _create_span_properties(
|
|
|
137
138
|
"status": status,
|
|
138
139
|
"error_message": error_msg,
|
|
139
140
|
"error_code": error_code,
|
|
140
|
-
"return_value": return_value_to_log
|
|
141
|
+
"return_value": return_value_to_log,
|
|
142
|
+
"exec_source": execution_source_context.get()
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
if tracer.settings.global_custom_values:
|
|
@@ -121,3 +121,34 @@ def find_by_trace_id(trace_id: str, limit: int = 100) -> List[Dict[str, Any]]:
|
|
|
121
121
|
sort_ascending=True, # Sort chronologically
|
|
122
122
|
limit=limit
|
|
123
123
|
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def find_replay_executions(
|
|
127
|
+
limit: int = 20,
|
|
128
|
+
status: Optional[str] = None,
|
|
129
|
+
function_name: Optional[str] = None
|
|
130
|
+
) -> List[Dict[str, Any]]:
|
|
131
|
+
"""
|
|
132
|
+
Searches specifically for logs generated during a Replay session.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
limit: Max number of logs to retrieve.
|
|
136
|
+
status: Optional filter for 'SUCCESS' or 'ERROR'.
|
|
137
|
+
function_name: Optional filter for specific function name.
|
|
138
|
+
"""
|
|
139
|
+
logger.info(f"\n--- Searching for REPLAY Executions (Status: {status}, Func: {function_name}) ---")
|
|
140
|
+
|
|
141
|
+
filters = {"exec_source": "REPLAY"}
|
|
142
|
+
|
|
143
|
+
if status:
|
|
144
|
+
filters["status"] = status
|
|
145
|
+
|
|
146
|
+
if function_name:
|
|
147
|
+
filters["function_name"] = function_name
|
|
148
|
+
|
|
149
|
+
return find_executions(
|
|
150
|
+
filters=filters,
|
|
151
|
+
sort_by="timestamp_utc",
|
|
152
|
+
sort_ascending=False,
|
|
153
|
+
limit=limit
|
|
154
|
+
)
|
|
@@ -13,6 +13,7 @@ import weaviate.classes.query as wvc_query
|
|
|
13
13
|
from ..database.db import get_cached_client
|
|
14
14
|
from ..models.db_config import get_weaviate_settings
|
|
15
15
|
from ..monitoring.tracer import _mask_and_serialize
|
|
16
|
+
from .context import execution_source_context
|
|
16
17
|
|
|
17
18
|
logger = logging.getLogger(__name__)
|
|
18
19
|
|
|
@@ -78,7 +79,10 @@ class VectorWaveReplayer:
|
|
|
78
79
|
# [FIX] Extract only valid arguments for the target function
|
|
79
80
|
inputs = self._extract_inputs(raw_inputs, target_func)
|
|
80
81
|
|
|
82
|
+
token = None
|
|
81
83
|
try:
|
|
84
|
+
token = execution_source_context.set("REPLAY")
|
|
85
|
+
|
|
82
86
|
# 3. Function Re-execution
|
|
83
87
|
if is_async_func:
|
|
84
88
|
actual_output = asyncio.run(target_func(**inputs))
|
|
@@ -127,6 +131,10 @@ class VectorWaveReplayer:
|
|
|
127
131
|
"traceback": traceback.format_exc()
|
|
128
132
|
})
|
|
129
133
|
|
|
134
|
+
finally:
|
|
135
|
+
if token:
|
|
136
|
+
execution_source_context.reset(token)
|
|
137
|
+
|
|
130
138
|
logger.info(f"Replay Finished. Passed: {results['passed']}, Failed: {results['failed']}")
|
|
131
139
|
return results
|
|
132
140
|
|
|
@@ -6,6 +6,8 @@ import math
|
|
|
6
6
|
import asyncio
|
|
7
7
|
import inspect
|
|
8
8
|
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from .context import execution_source_context
|
|
9
11
|
from ..core.llm.factory import get_llm_client
|
|
10
12
|
|
|
11
13
|
import weaviate.classes.query as wvc_query
|
|
@@ -88,12 +90,16 @@ class SemanticReplayer(VectorWaveReplayer):
|
|
|
88
90
|
inputs = self._extract_inputs(raw_inputs, target_func)
|
|
89
91
|
|
|
90
92
|
try:
|
|
93
|
+
token = execution_source_context.set("REPLAY")
|
|
91
94
|
# 3. Function Re-execution
|
|
92
95
|
if is_async_func:
|
|
93
96
|
actual_output = asyncio.run(target_func(**inputs))
|
|
94
97
|
else:
|
|
95
98
|
actual_output = target_func(**inputs)
|
|
96
99
|
|
|
100
|
+
if token:
|
|
101
|
+
execution_source_context.reset(token)
|
|
102
|
+
|
|
97
103
|
# 4. Result Validation (Semantic Comparison)
|
|
98
104
|
is_match, match_reason = self._compare_results_semantic(
|
|
99
105
|
expected_output,
|
|
@@ -30,6 +30,7 @@ src/tests/search/__init__.py
|
|
|
30
30
|
src/tests/search/test_execution_search.py
|
|
31
31
|
src/tests/utils/__init__.py
|
|
32
32
|
src/tests/utils/test_function_cahe.py
|
|
33
|
+
src/tests/utils/test_replay_source.py
|
|
33
34
|
src/tests/utils/test_replayer.py
|
|
34
35
|
src/tests/utils/test_return_caching.py
|
|
35
36
|
src/tests/utils/test_status.py
|
|
@@ -74,6 +75,7 @@ src/vectorwave/search/execution_search.py
|
|
|
74
75
|
src/vectorwave/search/extended_search.py
|
|
75
76
|
src/vectorwave/search/rag_search.py
|
|
76
77
|
src/vectorwave/utils/__init__.py
|
|
78
|
+
src/vectorwave/utils/context.py
|
|
77
79
|
src/vectorwave/utils/function_cache.py
|
|
78
80
|
src/vectorwave/utils/healer.py
|
|
79
81
|
src/vectorwave/utils/replayer.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|