langwatch 0.7.2__py3-none-any.whl → 0.8.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.
- langwatch/__init__.py +3 -1
- langwatch/__version__.py +1 -1
- langwatch/batch_evaluation.py +5 -4
- langwatch/dspy/__init__.py +3 -2
- langwatch/evaluation/evaluation.py +3 -2
- langwatch/evaluations.py +3 -2
- langwatch/login.py +2 -1
- langwatch/prompts/__init__.py +31 -0
- langwatch/prompts/errors.py +2 -1
- langwatch/prompts/local_loader.py +7 -2
- langwatch/prompts/prompt_facade.py +95 -5
- langwatch/prompts/types/__init__.py +4 -0
- langwatch/prompts/types/fetch_policy.py +26 -0
- langwatch/telemetry/tracing.py +3 -2
- langwatch/utils/exceptions.py +22 -1
- {langwatch-0.7.2.dist-info → langwatch-0.8.1.dist-info}/METADATA +1 -1
- {langwatch-0.7.2.dist-info → langwatch-0.8.1.dist-info}/RECORD +18 -18
- langwatch/prompts/types.py +0 -16
- {langwatch-0.7.2.dist-info → langwatch-0.8.1.dist-info}/WHEEL +0 -0
langwatch/__init__.py
CHANGED
|
@@ -8,6 +8,8 @@ from .login import login
|
|
|
8
8
|
from .state import get_api_key, get_endpoint
|
|
9
9
|
from .__version__ import __version__
|
|
10
10
|
from .utils.initialization import ensure_setup, setup
|
|
11
|
+
from .prompts.types import FetchPolicy
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
# Type hints for IntelliSense (only imported for typing)
|
|
13
15
|
from typing import TYPE_CHECKING
|
|
@@ -153,5 +155,5 @@ __all__ = [
|
|
|
153
155
|
"evaluations",
|
|
154
156
|
"langchain",
|
|
155
157
|
"dspy",
|
|
156
|
-
"
|
|
158
|
+
"FetchPolicy",
|
|
157
159
|
]
|
langwatch/__version__.py
CHANGED
langwatch/batch_evaluation.py
CHANGED
|
@@ -24,6 +24,7 @@ from tqdm import tqdm
|
|
|
24
24
|
import pandas as pd
|
|
25
25
|
|
|
26
26
|
from langwatch.types import Money
|
|
27
|
+
from langwatch.utils.exceptions import better_raise_for_status
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class EvaluationResult(BaseModel):
|
|
@@ -150,7 +151,7 @@ class BatchEvaluation:
|
|
|
150
151
|
raise ValueError(
|
|
151
152
|
"API key is not valid, please try to login again with langwatch.login()"
|
|
152
153
|
)
|
|
153
|
-
response
|
|
154
|
+
better_raise_for_status(response)
|
|
154
155
|
experiment_path = response.json()["path"]
|
|
155
156
|
self.experiment_slug = response.json()["slug"]
|
|
156
157
|
|
|
@@ -368,7 +369,7 @@ class BatchEvaluation:
|
|
|
368
369
|
json=body,
|
|
369
370
|
timeout=60,
|
|
370
371
|
)
|
|
371
|
-
response
|
|
372
|
+
better_raise_for_status(response)
|
|
372
373
|
|
|
373
374
|
def wait_for_completion(self):
|
|
374
375
|
async def wait_for_completion(self):
|
|
@@ -414,7 +415,7 @@ async def run_evaluation(
|
|
|
414
415
|
|
|
415
416
|
async with httpx.AsyncClient(timeout=900) as client:
|
|
416
417
|
response = await client.post(**request_params)
|
|
417
|
-
response
|
|
418
|
+
better_raise_for_status(response)
|
|
418
419
|
|
|
419
420
|
result = response.json()
|
|
420
421
|
|
|
@@ -462,7 +463,7 @@ def get_dataset(
|
|
|
462
463
|
|
|
463
464
|
with httpx.Client(timeout=300) as client:
|
|
464
465
|
response = client.get(**request_params)
|
|
465
|
-
response
|
|
466
|
+
better_raise_for_status(response)
|
|
466
467
|
|
|
467
468
|
result = response.json()
|
|
468
469
|
|
langwatch/dspy/__init__.py
CHANGED
|
@@ -5,6 +5,7 @@ import time
|
|
|
5
5
|
import warnings
|
|
6
6
|
import dspy
|
|
7
7
|
from typing import Callable, List, Optional, Any, Type, Union
|
|
8
|
+
from langwatch.utils.exceptions import better_raise_for_status
|
|
8
9
|
from langwatch.utils.transformation import truncate_object_recursively
|
|
9
10
|
from langwatch.telemetry.tracing import LangWatchTrace
|
|
10
11
|
from typing_extensions import TypedDict
|
|
@@ -193,7 +194,7 @@ class LangWatchDSPy:
|
|
|
193
194
|
raise ValueError(
|
|
194
195
|
"API key is not valid, please try to login again with langwatch.login()"
|
|
195
196
|
)
|
|
196
|
-
response
|
|
197
|
+
better_raise_for_status(response)
|
|
197
198
|
|
|
198
199
|
if optimizer and evaluator:
|
|
199
200
|
raise ValueError("You can only provide an optimizer or an evaluator, not both.")
|
|
@@ -386,7 +387,7 @@ class LangWatchDSPy:
|
|
|
386
387
|
data=json.dumps(data), # type: ignore
|
|
387
388
|
timeout=60,
|
|
388
389
|
)
|
|
389
|
-
response
|
|
390
|
+
better_raise_for_status(response)
|
|
390
391
|
self.steps_buffer = []
|
|
391
392
|
|
|
392
393
|
def tracer(self, trace: LangWatchTrace):
|
|
@@ -34,6 +34,7 @@ import langwatch
|
|
|
34
34
|
from langwatch.attributes import AttributeKey
|
|
35
35
|
from langwatch.domain import Money, TypedValueJson
|
|
36
36
|
from langwatch.telemetry.tracing import LangWatchTrace
|
|
37
|
+
from langwatch.utils.exceptions import better_raise_for_status
|
|
37
38
|
from langwatch.utils.transformation import SerializableWithStringFallback
|
|
38
39
|
|
|
39
40
|
from coolname import generate_slug # type: ignore
|
|
@@ -132,7 +133,7 @@ class Evaluation:
|
|
|
132
133
|
raise ValueError(
|
|
133
134
|
"API key is not valid, please try to login again with langwatch.login()"
|
|
134
135
|
)
|
|
135
|
-
response
|
|
136
|
+
better_raise_for_status(response)
|
|
136
137
|
response_json = response.json()
|
|
137
138
|
experiment_path = response_json["path"]
|
|
138
139
|
self.experiment_slug = response_json["slug"]
|
|
@@ -388,7 +389,7 @@ class Evaluation:
|
|
|
388
389
|
data=json.dumps(body, cls=SerializableWithStringFallback), # type: ignore
|
|
389
390
|
timeout=60,
|
|
390
391
|
)
|
|
391
|
-
response
|
|
392
|
+
better_raise_for_status(response)
|
|
392
393
|
|
|
393
394
|
def _wait_for_completion(self):
|
|
394
395
|
async def wait_for_completion(self: Evaluation):
|
langwatch/evaluations.py
CHANGED
|
@@ -12,6 +12,7 @@ from langwatch.telemetry.span import LangWatchSpan
|
|
|
12
12
|
from langwatch.telemetry.context import get_current_span
|
|
13
13
|
from langwatch.state import get_api_key, get_endpoint, get_instance
|
|
14
14
|
from langwatch.attributes import AttributeKey
|
|
15
|
+
from langwatch.utils.exceptions import EvaluatorException, better_raise_for_status
|
|
15
16
|
from pydantic import BaseModel
|
|
16
17
|
|
|
17
18
|
from langwatch.types import (
|
|
@@ -101,7 +102,7 @@ def evaluate(
|
|
|
101
102
|
try:
|
|
102
103
|
with httpx.Client(timeout=900) as client:
|
|
103
104
|
response = client.post(**request_params)
|
|
104
|
-
response
|
|
105
|
+
better_raise_for_status(response, cls=EvaluatorException)
|
|
105
106
|
except Exception as e:
|
|
106
107
|
return _handle_exception(e, span, as_guardrail)
|
|
107
108
|
|
|
@@ -156,7 +157,7 @@ async def async_evaluate(
|
|
|
156
157
|
try:
|
|
157
158
|
async with httpx.AsyncClient(timeout=900) as client:
|
|
158
159
|
response = await client.post(**request_params)
|
|
159
|
-
response
|
|
160
|
+
better_raise_for_status(response)
|
|
160
161
|
except Exception as e:
|
|
161
162
|
return _handle_exception(e, span, as_guardrail)
|
|
162
163
|
|
langwatch/login.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import httpx
|
|
2
2
|
|
|
3
3
|
import langwatch
|
|
4
|
+
from langwatch.utils.exceptions import better_raise_for_status
|
|
4
5
|
from .state import get_api_key, get_endpoint
|
|
5
6
|
from getpass import getpass
|
|
6
7
|
|
|
@@ -25,7 +26,7 @@ def login(relogin=False):
|
|
|
25
26
|
)
|
|
26
27
|
if response.status_code == 401:
|
|
27
28
|
raise ValueError("API key is not valid, please try to login again")
|
|
28
|
-
response
|
|
29
|
+
better_raise_for_status(response)
|
|
29
30
|
|
|
30
31
|
langwatch.setup(api_key=api_key)
|
|
31
32
|
print("LangWatch API key set")
|
langwatch/prompts/__init__.py
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
from .prompt_facade import PromptsFacade
|
|
2
|
+
from .types import FetchPolicy
|
|
2
3
|
|
|
3
4
|
__all__ = [
|
|
4
5
|
"PromptsFacade",
|
|
6
|
+
"FetchPolicy",
|
|
5
7
|
]
|
|
8
|
+
|
|
9
|
+
# Cached PromptsFacade instance for module-level method delegation
|
|
10
|
+
_facade_instance: PromptsFacade | None = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _get_facade() -> PromptsFacade:
|
|
14
|
+
"""Get or create the cached PromptsFacade instance."""
|
|
15
|
+
global _facade_instance
|
|
16
|
+
if _facade_instance is None:
|
|
17
|
+
_facade_instance = PromptsFacade.from_global()
|
|
18
|
+
return _facade_instance
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def __getattr__(name: str):
|
|
22
|
+
"""
|
|
23
|
+
Delegate attribute access to PromptsFacade instance.
|
|
24
|
+
|
|
25
|
+
This allows langwatch.prompts to work both as:
|
|
26
|
+
- A module (for submodule access like `from langwatch.prompts.types import FetchPolicy`)
|
|
27
|
+
- A facade (for method access like `langwatch.prompts.get(...)`)
|
|
28
|
+
|
|
29
|
+
When Python imports `langwatch.prompts.types`, it stores `langwatch.prompts` as a module
|
|
30
|
+
in sys.modules, which shadows the lazy-loaded PromptsFacade instance from langwatch.__getattr__.
|
|
31
|
+
This __getattr__ ensures method calls still work by delegating to a PromptsFacade instance.
|
|
32
|
+
"""
|
|
33
|
+
facade = _get_facade()
|
|
34
|
+
if hasattr(facade, name):
|
|
35
|
+
return getattr(facade, name)
|
|
36
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
langwatch/prompts/errors.py
CHANGED
|
@@ -139,7 +139,8 @@ def unwrap_response(
|
|
|
139
139
|
error_detail = f": {msg}" if msg else ""
|
|
140
140
|
raise ValueError(f"Invalid prompt request{error_detail}")
|
|
141
141
|
if status == 401:
|
|
142
|
-
|
|
142
|
+
error_detail = f": {msg}" if msg else ""
|
|
143
|
+
raise RuntimeError(f"Authentication error{error_detail}")
|
|
143
144
|
if status >= 500:
|
|
144
145
|
error_detail = f" - {msg}" if msg else ""
|
|
145
146
|
raise RuntimeError(
|
|
@@ -25,8 +25,13 @@ class LocalPromptLoader:
|
|
|
25
25
|
"""Loads prompts from local files in CLI format."""
|
|
26
26
|
|
|
27
27
|
def __init__(self, base_path: Optional[Path] = None):
|
|
28
|
-
"""Initialize with base path (defaults to current working directory)."""
|
|
29
|
-
self.
|
|
28
|
+
"""Initialize with base path (defaults to current working directory at load time)."""
|
|
29
|
+
self._base_path = base_path
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def base_path(self) -> Path:
|
|
33
|
+
"""Get the base path, defaulting to current working directory if not set."""
|
|
34
|
+
return self._base_path or Path.cwd()
|
|
30
35
|
|
|
31
36
|
def load_prompt(self, prompt_id: str) -> Optional[PromptData]:
|
|
32
37
|
"""
|
|
@@ -8,7 +8,8 @@ or when API is unavailable.
|
|
|
8
8
|
|
|
9
9
|
Follows the facade pattern to coordinate between LocalPromptLoader and PromptApiService.
|
|
10
10
|
"""
|
|
11
|
-
from typing import Dict, List, Literal, Optional
|
|
11
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
12
|
+
import time
|
|
12
13
|
from langwatch.generated.langwatch_rest_api_client.client import (
|
|
13
14
|
Client as LangWatchRestApiClient,
|
|
14
15
|
)
|
|
@@ -16,9 +17,13 @@ from langwatch.generated.langwatch_rest_api_client.client import (
|
|
|
16
17
|
from langwatch.utils.initialization import ensure_setup
|
|
17
18
|
from langwatch.state import get_instance
|
|
18
19
|
from .prompt import Prompt
|
|
20
|
+
from .types import FetchPolicy
|
|
19
21
|
from .prompt_api_service import PromptApiService
|
|
20
22
|
from .local_loader import LocalPromptLoader
|
|
21
23
|
from .types import MessageDict, InputDict, OutputDict
|
|
24
|
+
from logging import getLogger
|
|
25
|
+
|
|
26
|
+
logger = getLogger(__name__)
|
|
22
27
|
|
|
23
28
|
|
|
24
29
|
class PromptsFacade:
|
|
@@ -34,6 +39,7 @@ class PromptsFacade:
|
|
|
34
39
|
"""Initialize the prompt service facade with dependencies."""
|
|
35
40
|
self._api_service = PromptApiService(rest_api_client)
|
|
36
41
|
self._local_loader = LocalPromptLoader()
|
|
42
|
+
self._cache: Dict[str, Dict[str, Any]] = {}
|
|
37
43
|
|
|
38
44
|
@classmethod
|
|
39
45
|
def from_global(cls) -> "PromptsFacade":
|
|
@@ -46,17 +52,43 @@ class PromptsFacade:
|
|
|
46
52
|
)
|
|
47
53
|
return cls(instance.rest_api_client)
|
|
48
54
|
|
|
49
|
-
def get(
|
|
55
|
+
def get(
|
|
56
|
+
self,
|
|
57
|
+
prompt_id: str,
|
|
58
|
+
version_number: Optional[int] = None,
|
|
59
|
+
fetch_policy: Optional[FetchPolicy] = None,
|
|
60
|
+
cache_ttl_minutes: Optional[int] = None,
|
|
61
|
+
) -> Prompt:
|
|
50
62
|
"""
|
|
51
|
-
Retrieve a prompt by its ID with
|
|
63
|
+
Retrieve a prompt by its ID with configurable fetch policy.
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
Args:
|
|
66
|
+
prompt_id: The prompt ID to retrieve
|
|
67
|
+
version_number: Optional specific version number to retrieve
|
|
68
|
+
fetch_policy: How to fetch the prompt. Defaults to MATERIALIZED_FIRST.
|
|
69
|
+
cache_ttl_minutes: Cache TTL in minutes (only used with CACHE_TTL policy). Defaults to 5.
|
|
55
70
|
|
|
56
71
|
Raises:
|
|
57
72
|
ValueError: If the prompt is not found (404 error).
|
|
58
73
|
RuntimeError: If the API call fails for other reasons (auth, server errors, etc.).
|
|
59
74
|
"""
|
|
75
|
+
fetch_policy = fetch_policy or FetchPolicy.MATERIALIZED_FIRST
|
|
76
|
+
|
|
77
|
+
if fetch_policy == FetchPolicy.MATERIALIZED_ONLY:
|
|
78
|
+
return self._get_materialized_only(prompt_id)
|
|
79
|
+
elif fetch_policy == FetchPolicy.ALWAYS_FETCH:
|
|
80
|
+
return self._get_always_fetch(prompt_id, version_number)
|
|
81
|
+
elif fetch_policy == FetchPolicy.CACHE_TTL:
|
|
82
|
+
return self._get_cache_ttl(
|
|
83
|
+
prompt_id, version_number, cache_ttl_minutes or 5
|
|
84
|
+
)
|
|
85
|
+
else: # MATERIALIZED_FIRST (default)
|
|
86
|
+
return self._get_materialized_first(prompt_id, version_number)
|
|
87
|
+
|
|
88
|
+
def _get_materialized_first(
|
|
89
|
+
self, prompt_id: str, version_number: Optional[int] = None
|
|
90
|
+
) -> Prompt:
|
|
91
|
+
"""Get prompt using MATERIALIZED_FIRST policy (local first, API fallback)."""
|
|
60
92
|
# Try to load from local files first
|
|
61
93
|
local_data = self._local_loader.load_prompt(prompt_id)
|
|
62
94
|
if local_data is not None:
|
|
@@ -66,6 +98,64 @@ class PromptsFacade:
|
|
|
66
98
|
api_data = self._api_service.get(prompt_id, version_number)
|
|
67
99
|
return Prompt(api_data)
|
|
68
100
|
|
|
101
|
+
def _get_materialized_only(self, prompt_id: str) -> Prompt:
|
|
102
|
+
"""Get prompt using MATERIALIZED_ONLY policy (local only, no API calls)."""
|
|
103
|
+
local_data = self._local_loader.load_prompt(prompt_id)
|
|
104
|
+
if local_data is not None:
|
|
105
|
+
return Prompt(local_data)
|
|
106
|
+
|
|
107
|
+
raise ValueError(f"Prompt '{prompt_id}' not found in materialized files")
|
|
108
|
+
|
|
109
|
+
def _get_always_fetch(
|
|
110
|
+
self, prompt_id: str, version_number: Optional[int] = None
|
|
111
|
+
) -> Prompt:
|
|
112
|
+
"""Get prompt using ALWAYS_FETCH policy (API first, local fallback)."""
|
|
113
|
+
try:
|
|
114
|
+
api_data = self._api_service.get(prompt_id, version_number)
|
|
115
|
+
return Prompt(api_data)
|
|
116
|
+
except Exception:
|
|
117
|
+
# Fall back to local if API fails
|
|
118
|
+
local_data = self._local_loader.load_prompt(prompt_id)
|
|
119
|
+
if local_data is not None:
|
|
120
|
+
return Prompt(local_data)
|
|
121
|
+
raise ValueError(f"Prompt '{prompt_id}' not found locally or on server")
|
|
122
|
+
|
|
123
|
+
def _get_cache_ttl(
|
|
124
|
+
self,
|
|
125
|
+
prompt_id: str,
|
|
126
|
+
version_number: Optional[int] = None,
|
|
127
|
+
cache_ttl_minutes: int = 5,
|
|
128
|
+
) -> Prompt:
|
|
129
|
+
"""Get prompt using CACHE_TTL policy (cache with TTL, fallback to local)."""
|
|
130
|
+
cache_key = f"{prompt_id}::version:{version_number or ''}"
|
|
131
|
+
ttl_ms = cache_ttl_minutes * 60 * 1000
|
|
132
|
+
now = time.time() * 1000 # Convert to milliseconds
|
|
133
|
+
|
|
134
|
+
cached = self._cache.get(cache_key)
|
|
135
|
+
if cached and now - cached["timestamp"] < ttl_ms:
|
|
136
|
+
return Prompt(cached["data"])
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
api_data = self._api_service.get(prompt_id, version_number)
|
|
140
|
+
self._cache[cache_key] = {"data": api_data, "timestamp": now}
|
|
141
|
+
return Prompt(api_data)
|
|
142
|
+
except Exception:
|
|
143
|
+
logger.warning(
|
|
144
|
+
f"Failed to fetch prompt '{prompt_id}' from API, falling back to local",
|
|
145
|
+
exc_info=True,
|
|
146
|
+
stack_info=True,
|
|
147
|
+
extra={
|
|
148
|
+
"prompt_id": prompt_id,
|
|
149
|
+
"version_number": version_number,
|
|
150
|
+
"cache_ttl_minutes": cache_ttl_minutes,
|
|
151
|
+
},
|
|
152
|
+
)
|
|
153
|
+
# Fall back to local if API fails
|
|
154
|
+
local_data = self._local_loader.load_prompt(prompt_id)
|
|
155
|
+
if local_data is not None:
|
|
156
|
+
return Prompt(local_data)
|
|
157
|
+
raise ValueError(f"Prompt '{prompt_id}' not found locally or on server")
|
|
158
|
+
|
|
69
159
|
def create(
|
|
70
160
|
self,
|
|
71
161
|
handle: str,
|
|
@@ -8,6 +8,9 @@ organized by their purpose and scope.
|
|
|
8
8
|
# Core prompt data structure
|
|
9
9
|
from .prompt_data import PromptData
|
|
10
10
|
|
|
11
|
+
# Fetch policy
|
|
12
|
+
from .fetch_policy import FetchPolicy
|
|
13
|
+
|
|
11
14
|
# Standardized data structures
|
|
12
15
|
from .structures import (
|
|
13
16
|
MessageDict,
|
|
@@ -24,4 +27,5 @@ __all__ = [
|
|
|
24
27
|
"InputDict",
|
|
25
28
|
"OutputDict",
|
|
26
29
|
"ResponseFormatDict",
|
|
30
|
+
"FetchPolicy",
|
|
27
31
|
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FetchPolicy(Enum):
|
|
5
|
+
"""
|
|
6
|
+
Fetch policy for prompt retrieval.
|
|
7
|
+
|
|
8
|
+
Controls how prompts are fetched and cached.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Use local file if available, otherwise fetch from API (default)
|
|
12
|
+
MATERIALIZED_FIRST = "MATERIALIZED_FIRST"
|
|
13
|
+
|
|
14
|
+
# Always try API first, fall back to materialized
|
|
15
|
+
ALWAYS_FETCH = "ALWAYS_FETCH"
|
|
16
|
+
|
|
17
|
+
# Fetch every X minutes, use materialized between fetches
|
|
18
|
+
CACHE_TTL = "CACHE_TTL"
|
|
19
|
+
|
|
20
|
+
# Never fetch, use materialized files only
|
|
21
|
+
MATERIALIZED_ONLY = "MATERIALIZED_ONLY"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"FetchPolicy",
|
|
26
|
+
]
|
langwatch/telemetry/tracing.py
CHANGED
|
@@ -6,6 +6,7 @@ import httpx
|
|
|
6
6
|
import threading
|
|
7
7
|
from deprecated import deprecated
|
|
8
8
|
from langwatch.attributes import AttributeKey
|
|
9
|
+
from langwatch.utils.exceptions import better_raise_for_status
|
|
9
10
|
from langwatch.utils.transformation import (
|
|
10
11
|
SerializableWithStringFallback,
|
|
11
12
|
convert_typed_values,
|
|
@@ -300,7 +301,7 @@ class LangWatchTrace:
|
|
|
300
301
|
headers={"X-Auth-Token": get_api_key()},
|
|
301
302
|
timeout=15,
|
|
302
303
|
)
|
|
303
|
-
response
|
|
304
|
+
better_raise_for_status(response)
|
|
304
305
|
path = response.json()["path"]
|
|
305
306
|
return f"{endpoint}{path}"
|
|
306
307
|
|
|
@@ -317,7 +318,7 @@ class LangWatchTrace:
|
|
|
317
318
|
headers={"X-Auth-Token": get_api_key()},
|
|
318
319
|
timeout=15,
|
|
319
320
|
)
|
|
320
|
-
response
|
|
321
|
+
better_raise_for_status(response)
|
|
321
322
|
|
|
322
323
|
def update(
|
|
323
324
|
self,
|
langwatch/utils/exceptions.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import traceback
|
|
2
|
-
from typing import List, cast
|
|
2
|
+
from typing import List, cast, Type
|
|
3
3
|
|
|
4
4
|
from langwatch.domain import ErrorCapture
|
|
5
|
+
import httpx
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def capture_exception(err: BaseException):
|
|
@@ -12,3 +13,23 @@ def capture_exception(err: BaseException):
|
|
|
12
13
|
except: # python 3.10+
|
|
13
14
|
string_stacktrace = traceback.format_exception(err) # type: ignore
|
|
14
15
|
return ErrorCapture(message=repr(err), stacktrace=string_stacktrace)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EvaluatorException(Exception):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def better_raise_for_status(response: httpx.Response, cls: Type[BaseException] = httpx.HTTPStatusError) -> None:
|
|
23
|
+
try:
|
|
24
|
+
response.raise_for_status()
|
|
25
|
+
except httpx.HTTPStatusError as http_err:
|
|
26
|
+
try:
|
|
27
|
+
json = response.json()
|
|
28
|
+
except Exception:
|
|
29
|
+
raise http_err
|
|
30
|
+
|
|
31
|
+
if "error" in json:
|
|
32
|
+
error = json["error"]
|
|
33
|
+
raise cls(f"{response.status_code} {error}") from http_err
|
|
34
|
+
else:
|
|
35
|
+
raise http_err
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
langwatch/__init__.py,sha256=
|
|
2
|
-
langwatch/__version__.py,sha256=
|
|
1
|
+
langwatch/__init__.py,sha256=GMq4SV2Tz2i0JD05shqnw2lBW5cgMx4Zzo141hp106k,4266
|
|
2
|
+
langwatch/__version__.py,sha256=l2r_v6gqH58S38dAeIr-BCiWrh25Ql4biGJMjTpZZ1o,91
|
|
3
3
|
langwatch/attributes.py,sha256=nXdI_G85wQQCAdAcwjCiLYdEYj3wATmfgCmhlf6dVIk,3910
|
|
4
|
-
langwatch/batch_evaluation.py,sha256=
|
|
4
|
+
langwatch/batch_evaluation.py,sha256=Y_S3teXpHV07U-vvJYyV1PB6d0CgyFM_rTzPp6GnEBo,16165
|
|
5
5
|
langwatch/client.py,sha256=WTNcYSik7kZ2kH-qGDnhbMTosc8e_Xhab_lZlfh5TC8,25559
|
|
6
|
-
langwatch/evaluations.py,sha256=
|
|
6
|
+
langwatch/evaluations.py,sha256=W-nxhcbQ4Niyx949LjHjTehw74pj31dUVs5rjkQUBLo,16951
|
|
7
7
|
langwatch/guardrails.py,sha256=4d320HyklXPUVszF34aWsDKGzuvPggcDM_f45_eJTnc,1352
|
|
8
8
|
langwatch/langchain.py,sha256=HjbBBIDwwt688g0W4K0EsZGuGBbo1Mv5LQ-7Mkn56iQ,18726
|
|
9
9
|
langwatch/litellm.py,sha256=mPcw5cLykt0SQf9bTNSoT7elMx4gj-wZ_K2PC14Bw50,11998
|
|
10
|
-
langwatch/login.py,sha256=
|
|
10
|
+
langwatch/login.py,sha256=o0DxYVMhMCRHeopyF0qlj_U4o6yD1rL8QjfKvKnHv0s,965
|
|
11
11
|
langwatch/openai.py,sha256=h_NCIwJ0qs57PS-R7gQZsnf2_EBAahlYQMuqS9-Cj3Q,25139
|
|
12
12
|
langwatch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
langwatch/state.py,sha256=qXvPAjO90jdokCU6tPSwjHIac4QU_5N0pSd9dfmc9kY,1204
|
|
@@ -15,9 +15,9 @@ langwatch/tracer.py,sha256=t5FOdP1es9H_pPGqGUBLXCyEln0tTi4m4M9b6WxCrPU,975
|
|
|
15
15
|
langwatch/types.py,sha256=h6r3tNTzWqENx-9j_JPmOMZfFoKq9SNpEtxpAACk2G0,3114
|
|
16
16
|
langwatch/dataset/__init__.py,sha256=hZBcbjXuBO2qE5osJtd9wIE9f45F6-jpNTrne5nk4eE,2606
|
|
17
17
|
langwatch/domain/__init__.py,sha256=gSCOV3WkRhp_--9D1vxw7BYpnMRbpGh-2NbsXd4KZC0,6074
|
|
18
|
-
langwatch/dspy/__init__.py,sha256=
|
|
18
|
+
langwatch/dspy/__init__.py,sha256=F35iLwiznMJPgXLVYOvybjDWxdYlSN4vn3EzxC27Awc,34054
|
|
19
19
|
langwatch/evaluation/__init__.py,sha256=Jy7PW5VQbMoDGdOLRlQmDEvo_9TDkBLmrLrfocxddLM,281
|
|
20
|
-
langwatch/evaluation/evaluation.py,sha256=
|
|
20
|
+
langwatch/evaluation/evaluation.py,sha256=hmtY7rfgJm4TbTEMUP_x89B2L_Jyi7aNGhjNUxw1N4A,16112
|
|
21
21
|
langwatch/exporters/filterable_batch_span_exporter.py,sha256=MlhZjui56XD6p2sa8kEGyr-Hb3wqudknngmemnB4Twg,2142
|
|
22
22
|
langwatch/generated/langwatch_rest_api_client/__init__.py,sha256=8r-9pAj7fK7vnVX3mT0y_zS4B9ZRqD6RZiBo5fPra60,156
|
|
23
23
|
langwatch/generated/langwatch_rest_api_client/client.py,sha256=o_mdLqyBCQstu5tS1WZFwqIEbGwkvWQ7eQjuCJw_5VY,12419
|
|
@@ -390,31 +390,31 @@ langwatch/generated/langwatch_rest_api_client/models/search_request_filters.py,s
|
|
|
390
390
|
langwatch/generated/langwatch_rest_api_client/models/search_response.py,sha256=zDYmJ8bFBSJyF9D3cEn_ffrey-ITIfwr-_7eu72zLyk,2832
|
|
391
391
|
langwatch/generated/langwatch_rest_api_client/models/timestamps.py,sha256=-nRKUPZTAJQNxiKz128xF7DKgZNbFo4G3mr5xNXrkaw,2173
|
|
392
392
|
langwatch/generated/langwatch_rest_api_client/models/trace.py,sha256=K9Lc_EQOrJ2dqMXx9EpiUXReT1_uYF7WRfYyhlfbi3I,7537
|
|
393
|
-
langwatch/prompts/__init__.py,sha256=
|
|
394
|
-
langwatch/prompts/errors.py,sha256=
|
|
395
|
-
langwatch/prompts/local_loader.py,sha256=
|
|
393
|
+
langwatch/prompts/__init__.py,sha256=OGf3BrzVsTZnSPYSqSqe_eWmGIBRiOUlovOduYzKCx4,1259
|
|
394
|
+
langwatch/prompts/errors.py,sha256=kmaGeA1QPot9Ii5lgooxmAFlvUPOGjAnzzPBuw4h6Bw,5124
|
|
395
|
+
langwatch/prompts/local_loader.py,sha256=luvk39Kc4S-x4lBSms-AoWqg0Im_Uu-Lcpt3cRJFmdY,6774
|
|
396
396
|
langwatch/prompts/prompt.py,sha256=SgLDo9hO-CuRE-AZ8zx9v7-KqjiabiW8GzD9jdx1IoA,6914
|
|
397
397
|
langwatch/prompts/prompt_api_service.py,sha256=tHhwIRjUBSM43_jwDAoGCHJjvvqVeSCrUPwcwMvUHho,9823
|
|
398
|
-
langwatch/prompts/prompt_facade.py,sha256=
|
|
399
|
-
langwatch/prompts/types.py,sha256=p1bRMvfCCpGGiVwzFtQijVtWl5GWugL_vBOFc4B2348,269
|
|
398
|
+
langwatch/prompts/prompt_facade.py,sha256=fc16TB4ZBhKpwXVx9SNTJxLvQVms4eu4w0ZOH4Kk55w,8950
|
|
400
399
|
langwatch/prompts/decorators/prompt_service_tracing.py,sha256=uSYw0vExo7AuxbcCRnxbYl6UOfOQSC0IsisSqYy153Y,2395
|
|
401
400
|
langwatch/prompts/decorators/prompt_tracing.py,sha256=x_PQvJlGbGF1h2HtGNiqaZ8K1qNd1jRf5pTOBTQx-7M,3963
|
|
402
|
-
langwatch/prompts/types/__init__.py,sha256=
|
|
401
|
+
langwatch/prompts/types/__init__.py,sha256=jwaFV4VJHrOE6dm6yyLtWk6_7dqZpR5uZjN1cswtga4,579
|
|
402
|
+
langwatch/prompts/types/fetch_policy.py,sha256=AyS4J2x4IYjlcFo-6hSJY16awhll6hK2c3jncLUgZxc,578
|
|
403
403
|
langwatch/prompts/types/prompt_data.py,sha256=g_EQ94-PGfa4Ptwd3e2rMqoIZiX052MEEZKyF77m9D0,3137
|
|
404
404
|
langwatch/prompts/types/structures.py,sha256=cB94bn-qhFgHHYXcrmJV6Bk9idk5ZmyfXhFNQAaXw-M,951
|
|
405
405
|
langwatch/telemetry/context.py,sha256=q0hUG9PM3aifIr6ZRuuNNbsGtcAImu9Pv2XTKUp3CGc,4029
|
|
406
406
|
langwatch/telemetry/sampling.py,sha256=XDf6ZoXiwpHaHDYd_dDszSqH8_9-CHFNsGAZWOW1VYk,1327
|
|
407
407
|
langwatch/telemetry/span.py,sha256=g-RGWfQk4Q3b2TpipiHqjEV7rwmidaUHp54q51UxQ6s,32801
|
|
408
|
-
langwatch/telemetry/tracing.py,sha256=
|
|
408
|
+
langwatch/telemetry/tracing.py,sha256=R5e0F5Gea72Otusxj5ceafs_-KuFFylNRjcGNkLAhTQ,27697
|
|
409
409
|
langwatch/telemetry/types.py,sha256=Q9H7nT3GMK1aluRB7CCX8BR7VFKrQY_vdFdyF4Yc98U,501
|
|
410
410
|
langwatch/telemetry/__tests__/test_tracing.py,sha256=Px2vcpbRWBgwwaXzw3MgRfkcL-If2LmPAwaFN1sLyvY,3350
|
|
411
411
|
langwatch/utils/__init__.py,sha256=3rqQTgzEtmICJW_KSPuLa5q8p5udxt5SRi28Z2vZB10,138
|
|
412
412
|
langwatch/utils/capture.py,sha256=uVKPqHCm-o8CpabsUfhqbNFr5sgUHzcKnBadvL2oIwI,1172
|
|
413
|
-
langwatch/utils/exceptions.py,sha256=
|
|
413
|
+
langwatch/utils/exceptions.py,sha256=b-dorrnQ9XBJcijLLNJP9LRQzdOZGEiyQ3f8GcA1kgk,1046
|
|
414
414
|
langwatch/utils/initialization.py,sha256=1KoZmkHOvGEVF0j-4t4xRQdA_2C_SPiF7qFXqEG4Nkw,4553
|
|
415
415
|
langwatch/utils/module.py,sha256=KLBNOK3mA9gCSifCcQX_lOtU48BJQDWvFKtF6NMvwVA,688
|
|
416
416
|
langwatch/utils/transformation.py,sha256=76MGXyrYTxM0Yri36NJqLK-XxL4BBYdmKWAXXlw3D4Q,7690
|
|
417
417
|
langwatch/utils/utils.py,sha256=ZCOSie4o9LdJ7odshNfCNjmgwgQ27ojc5ENqt1rXuSs,596
|
|
418
|
-
langwatch-0.
|
|
419
|
-
langwatch-0.
|
|
420
|
-
langwatch-0.
|
|
418
|
+
langwatch-0.8.1.dist-info/METADATA,sha256=osaR4n3f3-Uo3PhYP_Dox70Dgs5fiCBnOEpu4LAhTVQ,13192
|
|
419
|
+
langwatch-0.8.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
420
|
+
langwatch-0.8.1.dist-info/RECORD,,
|
langwatch/prompts/types.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Re-export types for backward compatibility
|
|
2
|
-
from .types import (
|
|
3
|
-
PromptData,
|
|
4
|
-
MessageDict,
|
|
5
|
-
InputDict,
|
|
6
|
-
OutputDict,
|
|
7
|
-
ResponseFormatDict,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
__all__ = [
|
|
11
|
-
"PromptData",
|
|
12
|
-
"MessageDict",
|
|
13
|
-
"InputDict",
|
|
14
|
-
"OutputDict",
|
|
15
|
-
"ResponseFormatDict",
|
|
16
|
-
]
|
|
File without changes
|