prefactor-langchain 0.2.4__tar.gz → 0.2.7__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.
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/.gitignore +1 -1
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/PKG-INFO +16 -9
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/README.md +14 -7
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/examples/README.md +1 -1
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/examples/simple_agent.py +11 -5
- prefactor_langchain-0.2.7/examples/termination_demo.py +203 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/pyproject.toml +5 -2
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/src/prefactor_langchain/__init__.py +2 -2
- prefactor_langchain-0.2.7/src/prefactor_langchain/_version.py +5 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/src/prefactor_langchain/middleware.py +170 -19
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/tests/test_middleware.py +435 -8
- prefactor_langchain-0.2.7/tests/test_termination_demo.py +73 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/examples/.env.example +0 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/src/prefactor_langchain/metadata_extractor.py +0 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/src/prefactor_langchain/schemas.py +0 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/src/prefactor_langchain/spans.py +0 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/tests/test_metadata_extractor.py +0 -0
- {prefactor_langchain-0.2.4 → prefactor_langchain-0.2.7}/tests/test_schemas.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: prefactor-langchain
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: LangChain integration for Prefactor observability
|
|
5
5
|
Author-email: Prefactor Pty Ltd <josh@prefactor.tech>
|
|
6
6
|
License: MIT
|
|
7
7
|
Requires-Python: <4.0.0,>=3.11.0
|
|
8
8
|
Requires-Dist: langchain-core>=1.0.0
|
|
9
|
-
Requires-Dist: prefactor-core>=0.
|
|
9
|
+
Requires-Dist: prefactor-core>=0.5.1
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
|
|
12
12
|
# prefactor-langchain
|
|
@@ -27,9 +27,9 @@ pip install prefactor-langchain
|
|
|
27
27
|
from prefactor_langchain import LangChainToolSchemaConfig, PrefactorMiddleware
|
|
28
28
|
|
|
29
29
|
middleware = PrefactorMiddleware.from_config(
|
|
30
|
-
api_url="https://
|
|
30
|
+
api_url="https://app.prefactorai.com",
|
|
31
31
|
api_token="your-api-token",
|
|
32
|
-
agent_id="my-agent",
|
|
32
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
33
33
|
agent_name="My Agent", # optional
|
|
34
34
|
tool_schemas={
|
|
35
35
|
"send_email": LangChainToolSchemaConfig(
|
|
@@ -59,6 +59,9 @@ result = agent.invoke({"messages": [...]})
|
|
|
59
59
|
await middleware.close()
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
With a deployment-scoped token you can omit `agent_id`; the backend derives the
|
|
63
|
+
agent and environment from the token during registration.
|
|
64
|
+
|
|
62
65
|
### Pre-configured client
|
|
63
66
|
|
|
64
67
|
Pass a client you created yourself when you need full control over its
|
|
@@ -69,14 +72,16 @@ from prefactor_core import PrefactorCoreClient, PrefactorCoreConfig
|
|
|
69
72
|
from prefactor_http.config import HttpClientConfig
|
|
70
73
|
from prefactor_langchain import PrefactorMiddleware
|
|
71
74
|
|
|
72
|
-
http_config = HttpClientConfig(
|
|
75
|
+
http_config = HttpClientConfig(
|
|
76
|
+
api_url="https://app.prefactorai.com", api_token="your-api-token"
|
|
77
|
+
)
|
|
73
78
|
config = PrefactorCoreConfig(http_config=http_config)
|
|
74
79
|
client = PrefactorCoreClient(config)
|
|
75
80
|
await client.initialize()
|
|
76
81
|
|
|
77
82
|
middleware = PrefactorMiddleware(
|
|
78
83
|
client=client,
|
|
79
|
-
agent_id="my-agent",
|
|
84
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
80
85
|
agent_name="My Agent",
|
|
81
86
|
)
|
|
82
87
|
|
|
@@ -121,9 +126,9 @@ register_langchain_schemas(
|
|
|
121
126
|
)
|
|
122
127
|
|
|
123
128
|
middleware = PrefactorMiddleware.from_config(
|
|
124
|
-
api_url="https://
|
|
129
|
+
api_url="https://app.prefactorai.com",
|
|
125
130
|
api_token="your-api-token",
|
|
126
|
-
agent_id="my-agent",
|
|
131
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
127
132
|
schema_registry=registry,
|
|
128
133
|
)
|
|
129
134
|
```
|
|
@@ -140,7 +145,9 @@ from prefactor_core import PrefactorCoreClient, PrefactorCoreConfig
|
|
|
140
145
|
from prefactor_http.config import HttpClientConfig
|
|
141
146
|
from prefactor_langchain import PrefactorMiddleware
|
|
142
147
|
|
|
143
|
-
http_config = HttpClientConfig(
|
|
148
|
+
http_config = HttpClientConfig(
|
|
149
|
+
api_url="https://app.prefactorai.com", api_token="your-api-token"
|
|
150
|
+
)
|
|
144
151
|
config = PrefactorCoreConfig(http_config=http_config)
|
|
145
152
|
client = PrefactorCoreClient(config)
|
|
146
153
|
await client.initialize()
|
|
@@ -16,9 +16,9 @@ pip install prefactor-langchain
|
|
|
16
16
|
from prefactor_langchain import LangChainToolSchemaConfig, PrefactorMiddleware
|
|
17
17
|
|
|
18
18
|
middleware = PrefactorMiddleware.from_config(
|
|
19
|
-
api_url="https://
|
|
19
|
+
api_url="https://app.prefactorai.com",
|
|
20
20
|
api_token="your-api-token",
|
|
21
|
-
agent_id="my-agent",
|
|
21
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
22
22
|
agent_name="My Agent", # optional
|
|
23
23
|
tool_schemas={
|
|
24
24
|
"send_email": LangChainToolSchemaConfig(
|
|
@@ -48,6 +48,9 @@ result = agent.invoke({"messages": [...]})
|
|
|
48
48
|
await middleware.close()
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
With a deployment-scoped token you can omit `agent_id`; the backend derives the
|
|
52
|
+
agent and environment from the token during registration.
|
|
53
|
+
|
|
51
54
|
### Pre-configured client
|
|
52
55
|
|
|
53
56
|
Pass a client you created yourself when you need full control over its
|
|
@@ -58,14 +61,16 @@ from prefactor_core import PrefactorCoreClient, PrefactorCoreConfig
|
|
|
58
61
|
from prefactor_http.config import HttpClientConfig
|
|
59
62
|
from prefactor_langchain import PrefactorMiddleware
|
|
60
63
|
|
|
61
|
-
http_config = HttpClientConfig(
|
|
64
|
+
http_config = HttpClientConfig(
|
|
65
|
+
api_url="https://app.prefactorai.com", api_token="your-api-token"
|
|
66
|
+
)
|
|
62
67
|
config = PrefactorCoreConfig(http_config=http_config)
|
|
63
68
|
client = PrefactorCoreClient(config)
|
|
64
69
|
await client.initialize()
|
|
65
70
|
|
|
66
71
|
middleware = PrefactorMiddleware(
|
|
67
72
|
client=client,
|
|
68
|
-
agent_id="my-agent",
|
|
73
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
69
74
|
agent_name="My Agent",
|
|
70
75
|
)
|
|
71
76
|
|
|
@@ -110,9 +115,9 @@ register_langchain_schemas(
|
|
|
110
115
|
)
|
|
111
116
|
|
|
112
117
|
middleware = PrefactorMiddleware.from_config(
|
|
113
|
-
api_url="https://
|
|
118
|
+
api_url="https://app.prefactorai.com",
|
|
114
119
|
api_token="your-api-token",
|
|
115
|
-
agent_id="my-agent",
|
|
120
|
+
agent_id="my-agent", # Optional for deployment-scoped tokens
|
|
116
121
|
schema_registry=registry,
|
|
117
122
|
)
|
|
118
123
|
```
|
|
@@ -129,7 +134,9 @@ from prefactor_core import PrefactorCoreClient, PrefactorCoreConfig
|
|
|
129
134
|
from prefactor_http.config import HttpClientConfig
|
|
130
135
|
from prefactor_langchain import PrefactorMiddleware
|
|
131
136
|
|
|
132
|
-
http_config = HttpClientConfig(
|
|
137
|
+
http_config = HttpClientConfig(
|
|
138
|
+
api_url="https://app.prefactorai.com", api_token="your-api-token"
|
|
139
|
+
)
|
|
133
140
|
config = PrefactorCoreConfig(http_config=http_config)
|
|
134
141
|
client = PrefactorCoreClient(config)
|
|
135
142
|
await client.initialize()
|
|
@@ -36,7 +36,7 @@ pip install prefactor-langchain langchain
|
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
export ANTHROPIC_API_KEY=your_api_key_here
|
|
39
|
-
export PREFACTOR_API_URL=https://
|
|
39
|
+
export PREFACTOR_API_URL=https://app.prefactorai.com
|
|
40
40
|
export PREFACTOR_API_TOKEN=your_token_here
|
|
41
41
|
```
|
|
42
42
|
|
|
@@ -17,7 +17,7 @@ Prerequisites:
|
|
|
17
17
|
|
|
18
18
|
Example:
|
|
19
19
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
20
|
-
export PREFACTOR_API_URL=https://
|
|
20
|
+
export PREFACTOR_API_URL=https://app.prefactorai.com
|
|
21
21
|
export PREFACTOR_API_TOKEN=your_token
|
|
22
22
|
python simple_agent.py
|
|
23
23
|
"""
|
|
@@ -27,6 +27,7 @@ import asyncio
|
|
|
27
27
|
import operator
|
|
28
28
|
import os
|
|
29
29
|
from datetime import datetime
|
|
30
|
+
from typing import Callable
|
|
30
31
|
|
|
31
32
|
from langchain.agents import create_agent
|
|
32
33
|
from langchain_core.tools import tool
|
|
@@ -38,7 +39,7 @@ from prefactor_langchain import PrefactorMiddleware
|
|
|
38
39
|
# ---------------------------------------------------------------------------
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
_OPS = {
|
|
42
|
+
_OPS: dict[type[ast.operator], Callable[[float, float], float]] = {
|
|
42
43
|
ast.Add: operator.add,
|
|
43
44
|
ast.Sub: operator.sub,
|
|
44
45
|
ast.Mult: operator.mul,
|
|
@@ -48,9 +49,14 @@ _OPS = {
|
|
|
48
49
|
|
|
49
50
|
def _safe_eval(node: ast.expr) -> float:
|
|
50
51
|
if isinstance(node, ast.Constant):
|
|
51
|
-
|
|
52
|
+
if isinstance(node.value, (int, float)) and not isinstance(node.value, bool):
|
|
53
|
+
return float(node.value)
|
|
54
|
+
raise ValueError(f"Unsupported constant: {node.value!r}")
|
|
52
55
|
if isinstance(node, ast.BinOp):
|
|
53
|
-
|
|
56
|
+
op_type = type(node.op)
|
|
57
|
+
if op_type in _OPS:
|
|
58
|
+
return _OPS[op_type](_safe_eval(node.left), _safe_eval(node.right))
|
|
59
|
+
raise ValueError(f"Unsupported operator: {ast.dump(node.op)}")
|
|
54
60
|
if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
|
|
55
61
|
return -_safe_eval(node.operand)
|
|
56
62
|
raise ValueError(f"Unsupported expression: {ast.dump(node)}")
|
|
@@ -190,7 +196,7 @@ async def main_async():
|
|
|
190
196
|
"Get your API key from: https://console.anthropic.com/"
|
|
191
197
|
)
|
|
192
198
|
|
|
193
|
-
api_url = os.getenv("PREFACTOR_API_URL", "https://
|
|
199
|
+
api_url = os.getenv("PREFACTOR_API_URL", "https://app.prefactorai.com")
|
|
194
200
|
api_token = os.getenv("PREFACTOR_API_TOKEN")
|
|
195
201
|
if not api_token:
|
|
196
202
|
raise ValueError(
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""Termination demo — runs a LangChain agent in a service loop and demonstrates
|
|
2
|
+
automatic detection of p2-initiated termination.
|
|
3
|
+
|
|
4
|
+
Required env vars:
|
|
5
|
+
PREFACTOR_API_URL e.g. http://localhost:4000
|
|
6
|
+
PREFACTOR_AGENT_ID agent ID on the target p2 instance
|
|
7
|
+
PREFACTOR_API_TOKEN deployment/BA token for SDK (span creation etc.)
|
|
8
|
+
PREFACTOR_BA_TOKEN BA token for terminate API (falls back to
|
|
9
|
+
PREFACTOR_API_TOKEN)
|
|
10
|
+
|
|
11
|
+
Optional env vars:
|
|
12
|
+
PREFACTOR_AUTO_TERMINATE_DELAY seconds before demo calls terminate API (default: 6)
|
|
13
|
+
PREFACTOR_RESTART_DELAY seconds to wait between runs (default: 75)
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
PREFACTOR_API_URL=http://localhost:4000 \\
|
|
17
|
+
PREFACTOR_AGENT_ID=<agent-id> \\
|
|
18
|
+
PREFACTOR_API_TOKEN=<token> \\
|
|
19
|
+
PREFACTOR_AUTO_TERMINATE_DELAY=6 \\
|
|
20
|
+
PREFACTOR_RESTART_DELAY=75 \\
|
|
21
|
+
python packages/langchain/examples/termination_demo.py
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import asyncio
|
|
27
|
+
import logging
|
|
28
|
+
import os
|
|
29
|
+
|
|
30
|
+
import aiohttp
|
|
31
|
+
from langchain.agents import create_agent
|
|
32
|
+
from langchain_anthropic import ChatAnthropic
|
|
33
|
+
from langchain_core.tools import tool
|
|
34
|
+
from prefactor_core import PrefactorTerminatedError
|
|
35
|
+
from prefactor_langchain.middleware import PrefactorMiddleware
|
|
36
|
+
|
|
37
|
+
logging.basicConfig(
|
|
38
|
+
level=logging.INFO, format="%(asctime)s %(name)s %(levelname)s %(message)s"
|
|
39
|
+
)
|
|
40
|
+
logger = logging.getLogger("termination-demo")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@tool
|
|
44
|
+
def get_current_time() -> str:
|
|
45
|
+
"""Return the current UTC time as a string."""
|
|
46
|
+
from datetime import datetime, timezone
|
|
47
|
+
|
|
48
|
+
return datetime.now(timezone.utc).isoformat()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def terminate_after_delay(
|
|
52
|
+
api_url: str,
|
|
53
|
+
ba_token: str,
|
|
54
|
+
instance_id: str,
|
|
55
|
+
delay: float,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Call the terminate endpoint after a configured delay.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
api_url: Base Prefactor API URL.
|
|
61
|
+
ba_token: Bearer token for terminate API authorization.
|
|
62
|
+
instance_id: Agent instance identifier to terminate.
|
|
63
|
+
delay: Seconds to wait before posting the terminate request.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
None.
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
aiohttp.ClientResponseError: If the terminate API returns a non-2xx
|
|
70
|
+
response.
|
|
71
|
+
aiohttp.ClientError: If the terminate request fails before a response.
|
|
72
|
+
"""
|
|
73
|
+
await asyncio.sleep(delay)
|
|
74
|
+
url = f"{api_url.rstrip('/')}/api/v1/agent_instance/{instance_id}/terminate"
|
|
75
|
+
logger.info("Calling terminate API: POST %s", url)
|
|
76
|
+
timeout = aiohttp.ClientTimeout(total=10)
|
|
77
|
+
async with aiohttp.ClientSession(timeout=timeout) as session:
|
|
78
|
+
async with session.post(
|
|
79
|
+
url,
|
|
80
|
+
headers={
|
|
81
|
+
"Authorization": f"Bearer {ba_token}",
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
},
|
|
84
|
+
json={"reason": "demo termination"},
|
|
85
|
+
) as resp:
|
|
86
|
+
body = await resp.text()
|
|
87
|
+
logger.info("Terminate API: status=%s body=%s", resp.status, body)
|
|
88
|
+
resp.raise_for_status()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def _cancel_and_await_terminate_task(task: asyncio.Task[None]) -> None:
|
|
92
|
+
if not task.done():
|
|
93
|
+
task.cancel()
|
|
94
|
+
try:
|
|
95
|
+
await task
|
|
96
|
+
except asyncio.CancelledError:
|
|
97
|
+
pass
|
|
98
|
+
except Exception:
|
|
99
|
+
logger.exception("Auto-terminate task failed")
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
async def run_once(
|
|
104
|
+
run_number: int,
|
|
105
|
+
api_url: str,
|
|
106
|
+
api_token: str,
|
|
107
|
+
agent_id: str,
|
|
108
|
+
auto_terminate_delay: float,
|
|
109
|
+
) -> None:
|
|
110
|
+
"""Run one termination-demo agent session.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
run_number: Sequential run counter used in log messages.
|
|
114
|
+
api_url: Base Prefactor API URL.
|
|
115
|
+
api_token: SDK API token for Prefactor telemetry.
|
|
116
|
+
agent_id: Agent identifier used to initialize the middleware.
|
|
117
|
+
auto_terminate_delay: Seconds before the demo calls the terminate API.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
None.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
PrefactorTerminatedError: If Prefactor signals agent termination.
|
|
124
|
+
Exception: If agent invocation, termination cleanup, or middleware
|
|
125
|
+
cleanup fails.
|
|
126
|
+
"""
|
|
127
|
+
environment_id = os.environ.get("PREFACTOR_ENVIRONMENT_ID")
|
|
128
|
+
middleware = PrefactorMiddleware.from_config(
|
|
129
|
+
api_url=api_url,
|
|
130
|
+
api_token=api_token,
|
|
131
|
+
agent_id=agent_id,
|
|
132
|
+
agent_name="termination-demo-agent",
|
|
133
|
+
environment_id=environment_id,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
model = ChatAnthropic(model_name="claude-haiku-4-5-20251001")
|
|
137
|
+
agent = create_agent(
|
|
138
|
+
model, tools=[get_current_time], middleware=[middleware], checkpointer=None
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
instance = await middleware.ensure_initialized()
|
|
142
|
+
logger.info("Run #%d — Agent instance: %s", run_number, instance.id)
|
|
143
|
+
logger.info("Auto-terminate in %.0fs...", auto_terminate_delay)
|
|
144
|
+
|
|
145
|
+
ba_token = os.environ.get("PREFACTOR_BA_TOKEN", api_token)
|
|
146
|
+
terminate_task = asyncio.create_task(
|
|
147
|
+
terminate_after_delay(api_url, ba_token, instance.id, auto_terminate_delay)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
result = await agent.ainvoke(
|
|
152
|
+
{
|
|
153
|
+
"messages": [
|
|
154
|
+
{
|
|
155
|
+
"role": "user",
|
|
156
|
+
"content": "What time is it? Then keep asking every 2 seconds.",
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
)
|
|
161
|
+
logger.info("Run #%d completed normally: %s", run_number, result)
|
|
162
|
+
except PrefactorTerminatedError as e:
|
|
163
|
+
logger.info("Run #%d terminated: %s", run_number, e)
|
|
164
|
+
raise
|
|
165
|
+
finally:
|
|
166
|
+
try:
|
|
167
|
+
await _cancel_and_await_terminate_task(terminate_task)
|
|
168
|
+
finally:
|
|
169
|
+
await middleware.close()
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
async def main() -> None:
|
|
173
|
+
"""Run the termination demo restart loop.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
None.
|
|
177
|
+
"""
|
|
178
|
+
api_url = os.environ["PREFACTOR_API_URL"]
|
|
179
|
+
api_token = os.environ["PREFACTOR_API_TOKEN"]
|
|
180
|
+
agent_id = os.environ["PREFACTOR_AGENT_ID"]
|
|
181
|
+
auto_terminate_delay = float(os.environ.get("PREFACTOR_AUTO_TERMINATE_DELAY", "6"))
|
|
182
|
+
restart_delay = float(os.environ.get("PREFACTOR_RESTART_DELAY", "75"))
|
|
183
|
+
|
|
184
|
+
run_number = 0
|
|
185
|
+
while True:
|
|
186
|
+
run_number += 1
|
|
187
|
+
try:
|
|
188
|
+
await run_once(
|
|
189
|
+
run_number, api_url, api_token, agent_id, auto_terminate_delay
|
|
190
|
+
)
|
|
191
|
+
except PrefactorTerminatedError:
|
|
192
|
+
logger.info("Service continues — next run in %.0fs.", restart_delay)
|
|
193
|
+
await asyncio.sleep(restart_delay)
|
|
194
|
+
except (KeyboardInterrupt, asyncio.CancelledError):
|
|
195
|
+
logger.info("Stopped by user.")
|
|
196
|
+
break
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.exception("Unexpected error in run #%d: %s", run_number, e)
|
|
199
|
+
await asyncio.sleep(restart_delay)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
asyncio.run(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "prefactor-langchain"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"]
|
|
4
4
|
description = "LangChain integration for Prefactor observability"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -9,7 +9,7 @@ authors = [
|
|
|
9
9
|
]
|
|
10
10
|
requires-python = ">=3.11.0, <4.0.0"
|
|
11
11
|
dependencies = [
|
|
12
|
-
"prefactor-core>=0.
|
|
12
|
+
"prefactor-core>=0.5.1",
|
|
13
13
|
"langchain-core>=1.0.0",
|
|
14
14
|
]
|
|
15
15
|
|
|
@@ -17,5 +17,8 @@ dependencies = [
|
|
|
17
17
|
requires = ["hatchling"]
|
|
18
18
|
build-backend = "hatchling.build"
|
|
19
19
|
|
|
20
|
+
[tool.hatch.version]
|
|
21
|
+
path = "src/prefactor_langchain/_version.py"
|
|
22
|
+
|
|
20
23
|
[tool.hatch.build.targets.wheel]
|
|
21
24
|
packages = ["src/prefactor_langchain"]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from prefactor_langchain._version import __version__
|
|
5
6
|
from prefactor_langchain.metadata_extractor import (
|
|
6
7
|
extract_error_info,
|
|
7
8
|
extract_token_usage,
|
|
@@ -25,8 +26,6 @@ from prefactor_langchain.spans import (
|
|
|
25
26
|
ToolSpan,
|
|
26
27
|
)
|
|
27
28
|
|
|
28
|
-
__version__ = "0.2.4"
|
|
29
|
-
|
|
30
29
|
__all__ = [
|
|
31
30
|
# Middleware
|
|
32
31
|
"PrefactorMiddleware",
|
|
@@ -48,4 +47,5 @@ __all__ = [
|
|
|
48
47
|
"ToolSpan",
|
|
49
48
|
"TokenUsage",
|
|
50
49
|
"ErrorInfo",
|
|
50
|
+
"__version__",
|
|
51
51
|
]
|