vectorwave 0.1.2__tar.gz → 0.1.4__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.
Files changed (56) hide show
  1. vectorwave-0.1.4/PKG-INFO +417 -0
  2. vectorwave-0.1.4/Readme.md +393 -0
  3. {vectorwave-0.1.2 → vectorwave-0.1.4}/pyproject.toml +7 -6
  4. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/batch/test_batch.py +2 -1
  5. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/database/test_db.py +23 -19
  6. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/models/test_db_config.py +33 -25
  7. vectorwave-0.1.4/src/tests/monitoring/test_async_trace.py +259 -0
  8. vectorwave-0.1.4/src/tests/monitoring/test_tracer.py +256 -0
  9. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/batch/batch.py +11 -8
  10. vectorwave-0.1.4/src/vectorwave/core/decorator.py +156 -0
  11. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/database/db.py +68 -38
  12. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/database/db_search.py +32 -10
  13. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/models/db_config.py +41 -12
  14. vectorwave-0.1.4/src/vectorwave/monitoring/tracer.py +246 -0
  15. vectorwave-0.1.4/src/vectorwave/prediction/predictor.py +0 -0
  16. vectorwave-0.1.4/src/vectorwave/vectorizer/__init__.py +0 -0
  17. vectorwave-0.1.4/src/vectorwave/vectorizer/base.py +12 -0
  18. vectorwave-0.1.4/src/vectorwave/vectorizer/factory.py +49 -0
  19. vectorwave-0.1.4/src/vectorwave/vectorizer/huggingface_vectorizer.py +33 -0
  20. vectorwave-0.1.4/src/vectorwave/vectorizer/openai_vectorizer.py +35 -0
  21. vectorwave-0.1.4/src/vectorwave.egg-info/PKG-INFO +417 -0
  22. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave.egg-info/SOURCES.txt +9 -1
  23. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave.egg-info/requires.txt +1 -0
  24. vectorwave-0.1.2/PKG-INFO +0 -291
  25. vectorwave-0.1.2/Readme.md +0 -268
  26. vectorwave-0.1.2/src/vectorwave/core/decorator.py +0 -108
  27. vectorwave-0.1.2/src/vectorwave/monitoring/tracer.py +0 -128
  28. vectorwave-0.1.2/src/vectorwave.egg-info/PKG-INFO +0 -291
  29. {vectorwave-0.1.2 → vectorwave-0.1.4}/LICENSE +0 -0
  30. {vectorwave-0.1.2 → vectorwave-0.1.4}/MANIFEST.in +0 -0
  31. {vectorwave-0.1.2 → vectorwave-0.1.4}/NOTICE +0 -0
  32. {vectorwave-0.1.2 → vectorwave-0.1.4}/setup.cfg +0 -0
  33. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/__init__.py +0 -0
  34. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/batch/__init__.py +0 -0
  35. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/core/__init__.py +0 -0
  36. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/core/test_decorator.py +0 -0
  37. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/database/__init__.py +0 -0
  38. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/database/test_db_search.py +0 -0
  39. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/exception/__init__.py +0 -0
  40. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/models/__init__.py +0 -0
  41. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/monitoring/__init__.py +0 -0
  42. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/tests/prediction/__init__.py +0 -0
  43. {vectorwave-0.1.2/src/vectorwave/batch → vectorwave-0.1.4/src/tests/vectorizer}/__init__.py +0 -0
  44. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/__init__.py +0 -0
  45. {vectorwave-0.1.2/src/vectorwave/core → vectorwave-0.1.4/src/vectorwave/batch}/__init__.py +0 -0
  46. {vectorwave-0.1.2/src/vectorwave/database → vectorwave-0.1.4/src/vectorwave/core}/__init__.py +0 -0
  47. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/core/core.py +0 -0
  48. {vectorwave-0.1.2/src/vectorwave/exception → vectorwave-0.1.4/src/vectorwave/database}/__init__.py +0 -0
  49. {vectorwave-0.1.2/src/vectorwave/models → vectorwave-0.1.4/src/vectorwave/exception}/__init__.py +0 -0
  50. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/exception/exceptions.py +0 -0
  51. {vectorwave-0.1.2/src/vectorwave/monitoring → vectorwave-0.1.4/src/vectorwave/models}/__init__.py +0 -0
  52. {vectorwave-0.1.2/src/vectorwave/prediction → vectorwave-0.1.4/src/vectorwave/monitoring}/__init__.py +0 -0
  53. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave/monitoring/monitoring.py +0 -0
  54. /vectorwave-0.1.2/src/vectorwave/prediction/predictor.py → /vectorwave-0.1.4/src/vectorwave/prediction/__init__.py +0 -0
  55. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave.egg-info/dependency_links.txt +0 -0
  56. {vectorwave-0.1.2 → vectorwave-0.1.4}/src/vectorwave.egg-info/top_level.txt +0 -0
@@ -0,0 +1,417 @@
1
+ Metadata-Version: 2.4
2
+ Name: vectorwave
3
+ Version: 0.1.4
4
+ Summary: VectorWave: Seamless Auto-Vectorization Framework
5
+ Author-email: junyeonggim <junyeonggim5@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/republicofgamja/vtm
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ License-File: NOTICE
20
+ Requires-Dist: weaviate-client>=4.0.0
21
+ Requires-Dist: pydantic-settings>=2.0.0
22
+ Requires-Dist: sentence-transformers
23
+ Dynamic: license-file
24
+
25
+
26
+
27
+ # VectorWave: Seamless Auto-Vectorization Framework
28
+
29
+ [](https://opensource.org/licenses/MIT)
30
+
31
+ ## 🌟 Overview
32
+
33
+ **VectorWave** is an innovative framework that uses **decorators** to automatically save and manage the output of Python functions/methods in a **Vector Database (Vector DB)**. Developers can convert function outputs into intelligent vector data with just a single line of code (`@vectorize`), without worrying about the complex processes of data collection, embedding generation, and Vector DB storage.
34
+
35
+ -----
36
+
37
+ ## ✨ Features
38
+
39
+ * **`@vectorize` Decorator:**
40
+ 1. **Static Data Collection:** Upon script load, the function's source code, docstring, and metadata are saved once to the `VectorWaveFunctions` collection.
41
+ 2. **Dynamic Data Logging:** Each time the function is called, its execution time, success/failure status, error logs, and "dynamic tags" are recorded in the `VectorWaveExecutions` collection.
42
+ * **Distributed Tracing:** Combines `@vectorize` and `@trace_span` decorators to bundle the execution of complex, multi-step workflows under a single **`trace_id`** for analysis.
43
+ * **Search Interface:** Provides `search_functions` and `search_executions` to query the stored vector data (function definitions) and logs (execution history), facilitating the construction of RAG and monitoring systems.
44
+
45
+ -----
46
+
47
+ ## 🚀 Usage
48
+
49
+ VectorWave consists of "storage" via decorators and "retrieval" via functions, and now includes **execution flow tracing**.
50
+
51
+ ### 1\. (Required) Database Initialization and Setup
52
+
53
+ ```python
54
+ import time
55
+ from vectorwave import (
56
+ vectorize,
57
+ initialize_database,
58
+ search_functions,
59
+ search_executions
60
+ )
61
+ # [New] Import trace_span separately for distributed tracing.
62
+ from vectorwave.monitoring.tracer import trace_span
63
+
64
+ # Needs to be called only once at script startup.
65
+ try:
66
+ client = initialize_database()
67
+ print("VectorWave DB initialization successful.")
68
+ except Exception as e:
69
+ print(f"DB initialization failed: {e}")
70
+ exit()
71
+ ```
72
+
73
+ ### 2\. [Storage] Using `@vectorize` and Distributed Tracing
74
+
75
+ `@vectorize` acts as the **Root** of the trace, and applying `@trace_span` to internal functions bundles the workflow execution under a **single `trace_id`**.
76
+
77
+ ```python
78
+ # --- Child Span Function: Captures arguments ---
79
+ @trace_span(attributes_to_capture=['user_id', 'amount'])
80
+ def step_1_validate_payment(user_id: str, amount: int):
81
+ """(Span) Validates payment. Logs user_id and amount."""
82
+ print(f" [SPAN 1] Validating payment for {user_id}...")
83
+ time.sleep(0.1)
84
+ return True
85
+
86
+ @trace_span(attributes_to_capture=['user_id', 'receipt_id'])
87
+ def step_2_send_receipt(user_id: str, receipt_id: str):
88
+ """(Span) Sends receipt."""
89
+ print(f" [SPAN 2] Sending receipt {receipt_id}...")
90
+ time.sleep(0.2)
91
+
92
+
93
+ # --- Root Function (acts as @trace_root) ---
94
+ @vectorize(
95
+ search_description="Processes a user payment and returns a receipt.",
96
+ sequence_narrative="After payment is complete, a receipt is sent via email.",
97
+ team="billing", # ⬅️ Custom tag (logged on all executions)
98
+ priority=1 # ⬅️ Custom tag (execution importance)
99
+ )
100
+ def process_payment(user_id: str, amount: int):
101
+ """(Root Span) Executes the user payment workflow."""
102
+ print(f" [ROOT EXEC] process_payment: Starting workflow for {user_id}...")
103
+
104
+ # When child functions are called, the same trace_id is automatically inherited via ContextVar.
105
+ step_1_validate_payment(user_id=user_id, amount=amount)
106
+
107
+ receipt_id = f"receipt_{user_id}_{amount}"
108
+ step_2_send_receipt(user_id=user_id, receipt_id=receipt_id)
109
+
110
+ print(f" [ROOT DONE] process_payment")
111
+ return {"status": "success", "receipt_id": receipt_id}
112
+
113
+ # --- Function Execution ---
114
+ print("Now calling 'process_payment'...")
115
+ # This single call will record a total of 3 execution logs (spans) in the DB,
116
+ # and all three logs will be tied to a single 'trace_id'.
117
+ process_payment("user_789", 5000)
118
+ ```
119
+
120
+ ### 3\. [Retrieval ①] Search Function Definitions (for RAG)
121
+
122
+ ```python
123
+ # Search for functions related to 'payment' using natural language (vector).
124
+ print("\n--- Searching for 'payment' related functions ---")
125
+ payment_funcs = search_functions(
126
+ query="User payment processing feature",
127
+ limit=3
128
+ )
129
+ for func in payment_funcs:
130
+ print(f" - Function: {func['properties']['function_name']}")
131
+ print(f" - Description: {func['properties']['search_description']}")
132
+ print(f" - Similarity (Distance): {func['metadata'].distance:.4f}")
133
+ ```
134
+
135
+ ### 4\. [Retrieval ②] Search Execution Logs (for Monitoring & Tracing)
136
+
137
+ `search_executions` can now retrieve all related execution logs (spans) based on a `trace_id`.
138
+
139
+ ```python
140
+ # 1. Find the Trace ID of a specific workflow (process_payment).
141
+ latest_payment_span = search_executions(
142
+ limit=1,
143
+ filters={"function_name": "process_payment"},
144
+ sort_by="timestamp_utc",
145
+ sort_ascending=False
146
+ )
147
+ trace_id = latest_payment_span[0]["trace_id"]
148
+
149
+ # 2. Retrieve all spans belonging to that Trace ID in chronological order.
150
+ print(f"\n--- Full Trace for ID ({trace_id[:8]}...) ---")
151
+ trace_spans = search_executions(
152
+ limit=10,
153
+ filters={"trace_id": trace_id},
154
+ sort_by="timestamp_utc",
155
+ sort_ascending=True # Sort ascending to analyze workflow
156
+ )
157
+
158
+ for i, span in enumerate(trace_spans):
159
+ print(f" - [Span {i+1}] {span['function_name']} ({span['duration_ms']:.2f}ms)")
160
+ # Captured arguments (user_id, amount, etc.) from child spans will also be visible.
161
+
162
+ # Expected Output:
163
+ # - [Span 1] step_1_validate_payment (100.81ms)
164
+ # - [Span 2] step_2_send_receipt (202.06ms)
165
+ # - [Span 3] process_payment (333.18ms)
166
+ ```
167
+
168
+ -----
169
+
170
+ ## ⚙️ Configuration
171
+
172
+ VectorWave automatically reads Weaviate database connection info and **vectorization strategy** from **environment variables** or a `.env` file.
173
+
174
+ Create a `.env` file in your project's root directory (e.g., where `test_ex/example.py` is located) and set the required values.
175
+
176
+ ### Vectorizer Strategy (VECTORIZER)
177
+
178
+ You can select the text vectorization method via the `VECTORIZER` environment variable in your `test_ex/.env` file.
179
+
180
+ | `VECTORIZER` Setting | Description | Required Additional Settings |
181
+ | :--- | :--- | :--- |
182
+ | **`huggingface`** | (Default Recommended) Uses the `sentence-transformers` library to vectorize on your local CPU. No API key is needed. | `HF_MODEL_NAME` (e.g., "sentence-transformers/all-MiniLM-L6-v2") |
183
+ | **`openai_client`** | (High-Performance) Uses the OpenAI Python client to vectorize with models like `text-embedding-3-small`. | `OPENAI_API_KEY` (A valid OpenAI API key) |
184
+ | **`weaviate_module`** | (Docker Delegate) Delegates vectorization to Weaviate's built-in module (e.g., `text2vec-openai`). | `WEAVIATE_VECTORIZER_MODULE`, `OPENAI_API_KEY` |
185
+ | **`none`** | Disables vectorization. Data is stored without vectors. | None |
186
+
187
+ -----
188
+
189
+ ### .env File Examples
190
+
191
+ Configure your `.env` file according to the strategy you want to use.
192
+
193
+ #### Example 1: Using `huggingface` (Local, No API Key)
194
+
195
+ Uses a `sentence-transformers` model on your local machine. Ideal for testing without API keys.
196
+
197
+ ```ini
198
+ # .env (Using HuggingFace)
199
+ # --- Basic Weaviate Connection ---
200
+ WEAVIATE_HOST=localhost
201
+ WEAVIATE_PORT=8080
202
+ WEAVIATE_GRPC_PORT=50051
203
+
204
+ # --- [Strategy 1] HuggingFace Config ---
205
+ VECTORIZER="huggingface"
206
+ HF_MODEL_NAME="sentence-transformers/all-MiniLM-L6-v2"
207
+
208
+ # (OPENAI_API_KEY is not required for this mode)
209
+ OPENAI_API_KEY=sk-...
210
+
211
+ # --- [Advanced] Custom Properties ---
212
+ CUSTOM_PROPERTIES_FILE_PATH=.weaviate_properties
213
+ FAILURE_MAPPING_FILE_PATH=.vectorwave_errors.json
214
+ RUN_ID=test-run-001
215
+ ```
216
+
217
+ #### Example 2: Using `openai_client` (Python Client, High-Performance)
218
+
219
+ Directly calls the OpenAI API via the `openai` Python library.
220
+
221
+ ```ini
222
+ # .env (Using OpenAI Python Client)
223
+ # --- Basic Weaviate Connection ---
224
+ WEAVIATE_HOST=localhost
225
+ WEAVIATE_PORT=8080
226
+ WEAVIATE_GRPC_PORT=50051
227
+
228
+ # --- [Strategy 2] OpenAI Client Config ---
229
+ VECTORIZER="openai_client"
230
+
231
+ # [Required] You must enter a valid OpenAI API key.
232
+ OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
233
+
234
+ # (HF_MODEL_NAME is not used in this mode)
235
+ HF_MODEL_NAME=...
236
+
237
+ # --- [Advanced] Custom Properties ---
238
+ CUSTOM_PROPERTIES_FILE_PATH=.weaviate_properties
239
+ FAILURE_MAPPING_FILE_PATH=.vectorwave_errors.json
240
+ RUN_ID=test-run-001
241
+ ```
242
+
243
+ #### Example 3: Using `weaviate_module` (Docker Delegate)
244
+
245
+ Delegates vectorization to the Weaviate Docker container instead of Python. (See `vw_docker.yml` config).
246
+
247
+ ```ini
248
+ # .env (Delegating to Weaviate Module)
249
+ # --- Basic Weaviate Connection ---
250
+ WEAVIATE_HOST=localhost
251
+ WEAVIATE_PORT=8080
252
+ WEAVIATE_GRPC_PORT=50051
253
+
254
+ # --- [Strategy 3] Weaviate Module Config ---
255
+ VECTORIZER="weaviate_module"
256
+ WEAVIATE_VECTORIZER_MODULE=text2vec-openai
257
+ WEAVIATE_GENERATIVE_MODULE=generative-openai
258
+
259
+ # [Required] The Weaviate container will read this API key.
260
+ OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
261
+
262
+ # --- [Advanced] Custom Properties ---
263
+ CUSTOM_PROPERTIES_FILE_PATH=.weaviate_properties
264
+ FAILURE_MAPPING_FILE_PATH=.vectorwave_errors.json
265
+ RUN_ID=test-run-001
266
+ ```
267
+
268
+ -----
269
+
270
+ ### 🚀 Advanced Failure Tracing (Error Code)
271
+
272
+ This enhances `VectorWaveExecutions` logs beyond a simple `status: "ERROR"`. An `error_code` property is added to the schema for granular failure analysis.
273
+
274
+ When a function wrapped by `@vectorize` or `@trace_span` fails, the `error_code` is automatically determined based on three priorities:
275
+
276
+ 1. **Custom Exception Attribute (Priority 1):**
277
+ The most specific method. If the raised exception object `e` has an `e.error_code` attribute, its value is used.
278
+
279
+ ```python
280
+ class PaymentError(Exception):
281
+ def __init__(self, message, error_code):
282
+ super().__init__(message)
283
+ self.error_code = error_code # ⬅️ This attribute is detected.
284
+
285
+ @vectorize(...)
286
+ def process_payment(amount):
287
+ if amount < 0:
288
+ raise PaymentError("Amount < 0", error_code="PAYMENT_NEGATIVE_AMOUNT")
289
+
290
+ # DB Log on execution: { "status": "ERROR", "error_code": "PAYMENT_NEGATIVE_AMOUNT" }
291
+ ```
292
+
293
+ 2. **Global Mapping File (Priority 2):**
294
+ Centrally manage common exceptions. VectorWave loads a JSON file specified by `FAILURE_MAPPING_FILE_PATH` in your `.env` (default: `.vectorwave_errors.json`) and maps the exception class name to a code.
295
+
296
+ **`.vectorwave_errors.json` Example:**
297
+
298
+ ```json
299
+ {
300
+ "ValueError": "INVALID_INPUT",
301
+ "KeyError": "CONFIG_MISSING",
302
+ "TypeError": "INVALID_INPUT"
303
+ }
304
+ ```
305
+
306
+ ```python
307
+ @vectorize(...)
308
+ def get_config(key):
309
+ return os.environ[key] # ⬅️ Raises KeyError
310
+
311
+ # DB Log on execution: { "status": "ERROR", "error_code": "CONFIG_MISSING" }
312
+ ```
313
+
314
+ 3. **Default (Priority 3):**
315
+ If neither of the above applies, the exception's class name (e.g., `"ZeroDivisionError"`) is stored as the default `error_code`.
316
+
317
+ **[Usage] Searching for Failures:**
318
+ You can now filter for specific failure types using `search_executions`.
319
+
320
+ ```python
321
+ # Find all failure logs categorized as "INVALID_INPUT"
322
+ invalid_logs = search_executions(
323
+ filters={"error_code": "INVALID_INPUT"},
324
+ limit=10
325
+ )
326
+ ```
327
+
328
+ -----
329
+
330
+ ### Custom Properties and Dynamic Execution Tagging
331
+
332
+ VectorWave can store user-defined metadata in addition to static data (function definitions) and dynamic data (execution logs). This works in two steps.
333
+
334
+ #### Step 1: Define Custom Schema (Tag "Allow-list")
335
+
336
+ Create a JSON file at the path specified by `CUSTOM_PROPERTIES_FILE_PATH` in your `.env` file (default: `.weaviate_properties`).
337
+
338
+ This file instructs VectorWave to add **new properties (columns)** to the Weaviate collections. This file acts as an **"allow-list"** for all custom tags.
339
+
340
+ **`.weaviate_properties` Example:**
341
+
342
+ ```json
343
+ {
344
+ "run_id": {
345
+ "data_type": "TEXT",
346
+ "description": "The ID of the specific test run"
347
+ },
348
+ "experiment_id": {
349
+ "data_type": "TEXT",
350
+ "description": "Identifier for the experiment"
351
+ },
352
+ "team": {
353
+ "data_type": "TEXT",
354
+ "description": "The team responsible for this function"
355
+ },
356
+ "priority": {
357
+ "data_type": "INT",
358
+ "description": "Execution priority level"
359
+ }
360
+ }
361
+ ```
362
+
363
+ * This definition will add `run_id`, `experiment_id`, `team`, and `priority` properties to both the `VectorWaveFunctions` and `VectorWaveExecutions` collections.
364
+
365
+ #### Step 2: Dynamic Execution Tagging (Adding Values)
366
+
367
+ When a function is executed, VectorWave adds tags to the `VectorWaveExecutions` log. These tags are collected and merged from two sources.
368
+
369
+ **1. Global Tags (Environment Variables)**
370
+ VectorWave looks for environment variables matching the **UPPERCASE name** of the keys defined in Step 1 (e.g., `RUN_ID`, `EXPERIMENT_ID`). Found values are loaded as `global_custom_values` and added to *all* execution logs. Ideal for run-wide metadata.
371
+
372
+ **2. Function-Specific Tags (Decorator)**
373
+ You can pass tags as keyword arguments (`**execution_tags`) directly to the `@vectorize` decorator. This is ideal for function-specific metadata.
374
+
375
+ ```python
376
+ # --- .env file ---
377
+ # RUN_ID=global-run-abc
378
+ # TEAM=default-team
379
+
380
+ @vectorize(
381
+ search_description="Process payment",
382
+ sequence_narrative="...",
383
+ team="billing", # <-- Function-specific tag
384
+ priority=1 # <-- Function-specific tag
385
+ )
386
+ def process_payment():
387
+ pass
388
+
389
+ @vectorize(
390
+ search_description="Another function",
391
+ sequence_narrative="...",
392
+ run_id="override-run-xyz" # <-- Overrides the global tag
393
+ )
394
+ def other_function():
395
+ pass
396
+ ```
397
+
398
+ **Tag Merging and Validation Rules**
399
+
400
+ 1. **Validation (Important):** Tags (global or function-specific) will **only** be saved to Weaviate if their key (e.g., `run_id`, `team`, `priority`) was first defined in the `.weaviate_properties` file (Step 1). Tags not defined in the schema are **ignored**, and a warning is logged at startup.
401
+
402
+ 2. **Priority (Override):** If a tag key is defined in both places (e.g., global `RUN_ID` in `.env` and `run_id="override-xyz"` in the decorator), the **function-specific tag from the decorator always wins**.
403
+
404
+ **Resulting Logs:**
405
+
406
+ * `process_payment()` execution log: `{"run_id": "global-run-abc", "team": "billing", "priority": 1}`
407
+ * `other_function()` execution log: `{"run_id": "override-run-xyz", "team": "default-team"}`
408
+
409
+ -----
410
+
411
+ ## 🤝 Contributing
412
+
413
+ Bug reports, feature requests, and code contributions are all welcome. For details, please see [CONTRIBUTING.md](https://www.google.com/search?q=httpsS://www.google.com/search%3Fq%3DCONTRIBUTING.md).
414
+
415
+ ## 📜 License
416
+
417
+ This project is distributed under the MIT License. See the [LICENSE](https://www.google.com/search?q=LICENSE) file for details.