langgraph-api 0.2.78__tar.gz → 0.2.85__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.
Potentially problematic release.
This version of langgraph-api might be problematic. Click here for more details.
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/PKG-INFO +1 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/benchmark/README.md +12 -2
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/benchmark/burst.js +14 -7
- langgraph_api-0.2.85/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/__init__.py +13 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/meta.py +2 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/runs.py +7 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/cli.py +1 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/config.py +1 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/remote.py +24 -2
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/metadata.py +72 -21
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/serde.py +13 -7
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/worker.py +3 -17
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/uv.lock +54 -58
- langgraph_api-0.2.78/langgraph_api/__init__.py +0 -1
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/.gitignore +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/LICENSE +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/Makefile +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/README.md +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/benchmark/.gitignore +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/benchmark/Makefile +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/benchmark/weather.js +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/constraints.txt +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/forbidden.txt +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/healthcheck.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/mcp.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/custom.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/command.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/http.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/http_metrics.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/models/run.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/route.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/server.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/state.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/store.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/thread_ttl.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/utils/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/utils/config.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/utils/future.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/utils.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/logging.json +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/openapi.json +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/pyproject.toml +0 -0
- {langgraph_api-0.2.78 → langgraph_api-0.2.85}/scripts/create_license.py +0 -0
|
@@ -6,7 +6,14 @@ K6 is a modern load testing tool that allows you to test the performance and rel
|
|
|
6
6
|
|
|
7
7
|
### Available Tests
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
We use a local benchmark agent that has a MODE that can be any of the following:
|
|
10
|
+
- `single` - Run a single node
|
|
11
|
+
- `parallel` - Run EXPAND nodes in parallel
|
|
12
|
+
- `sequential` - Run EXPAND nodes in sequence
|
|
13
|
+
|
|
14
|
+
By default, MODE is `single` and EXPAND is 50.
|
|
15
|
+
|
|
16
|
+
1. Burst - Kick off a burst of /run/wait requests. Default BURST_SIZE is 100.
|
|
10
17
|
|
|
11
18
|
## Running Tests Locally
|
|
12
19
|
|
|
@@ -19,12 +26,15 @@ K6 is a modern load testing tool that allows you to test the performance and rel
|
|
|
19
26
|
### Basic Usage
|
|
20
27
|
|
|
21
28
|
```bash
|
|
22
|
-
# Run burst test with default burst size
|
|
29
|
+
# Run burst test with default burst size
|
|
23
30
|
make benchmark-burst
|
|
24
31
|
|
|
25
32
|
# Run burst test with custom burst size
|
|
26
33
|
BURST_SIZE=500 make benchmark-burst
|
|
27
34
|
|
|
35
|
+
# Run burst test with a different mode and expand size
|
|
36
|
+
MODE='parallel' EXPAND=100 make benchmark-burst
|
|
37
|
+
|
|
28
38
|
# Run burst test against a deployment
|
|
29
39
|
BASE_URL=https://jdr-debug-31ac2c83eef557309f21c1e98d822025.us.langgraph.app make benchmark-burst
|
|
30
40
|
|
|
@@ -15,7 +15,9 @@ const burstSuccessRate = new Rate('burst_success_rate');
|
|
|
15
15
|
|
|
16
16
|
// URL of your LangGraph server
|
|
17
17
|
const BASE_URL = __ENV.BASE_URL || 'http://localhost:9123';
|
|
18
|
-
const BURST_SIZE = parseInt(__ENV.BURST_SIZE || '
|
|
18
|
+
const BURST_SIZE = parseInt(__ENV.BURST_SIZE || '100');
|
|
19
|
+
const MODE = __ENV.MODE || 'single';
|
|
20
|
+
const EXPAND = parseInt(__ENV.EXPAND || '50');
|
|
19
21
|
|
|
20
22
|
// Burst testing configuration
|
|
21
23
|
export let options = {
|
|
@@ -28,8 +30,8 @@ export let options = {
|
|
|
28
30
|
},
|
|
29
31
|
},
|
|
30
32
|
thresholds: {
|
|
31
|
-
'run_duration': ['p(95)<
|
|
32
|
-
'burst_success_rate': ['rate
|
|
33
|
+
'run_duration': ['p(95)<2000'],
|
|
34
|
+
'burst_success_rate': ['rate>=0.99'],
|
|
33
35
|
},
|
|
34
36
|
};
|
|
35
37
|
|
|
@@ -50,8 +52,10 @@ export default function() {
|
|
|
50
52
|
// Create a payload with the LangGraph agent configuration
|
|
51
53
|
const payload = JSON.stringify({
|
|
52
54
|
assistant_id: "benchmark",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
input: {mode: MODE, expand: EXPAND},
|
|
56
|
+
config: {
|
|
57
|
+
recursion_limit: EXPAND + 2,
|
|
58
|
+
}
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
// Make a single request to the wait endpoint
|
|
@@ -60,15 +64,18 @@ export default function() {
|
|
|
60
64
|
timeout: '35s'
|
|
61
65
|
});
|
|
62
66
|
|
|
67
|
+
// Don't include verification in the duration of the request
|
|
68
|
+
const duration = new Date().getTime() - startTime;
|
|
69
|
+
|
|
63
70
|
// Check the response
|
|
71
|
+
const expected_length = MODE === 'single' ? 1 : EXPAND + 1;
|
|
64
72
|
const success = check(response, {
|
|
65
73
|
'Run completed successfully': (r) => r.status === 200,
|
|
66
|
-
'Response contains
|
|
74
|
+
'Response contains expected number of messages': (r) => JSON.parse(r.body).messages.length === expected_length,
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
if (success) {
|
|
70
78
|
// Record success metrics
|
|
71
|
-
const duration = new Date().getTime() - startTime;
|
|
72
79
|
runDuration.add(duration);
|
|
73
80
|
successfulRuns.add(1);
|
|
74
81
|
burstSuccessRate.add(1); // 1 = success
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.85"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import functools
|
|
2
3
|
import importlib
|
|
3
4
|
import importlib.util
|
|
4
5
|
import os
|
|
@@ -27,7 +28,11 @@ from langgraph_runtime.database import connect, healthcheck
|
|
|
27
28
|
logger = structlog.stdlib.get_logger(__name__)
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
async def ok(request: Request):
|
|
31
|
+
async def ok(request: Request, *, disabled: bool = False):
|
|
32
|
+
if disabled:
|
|
33
|
+
# We still expose an /ok endpoint even if disable_meta is set so that
|
|
34
|
+
# the operator knows the server started up.
|
|
35
|
+
return JSONResponse({"ok": True})
|
|
31
36
|
check_db = int(request.query_params.get("check_db", "0")) # must be "0" or "1"
|
|
32
37
|
if check_db:
|
|
33
38
|
await healthcheck()
|
|
@@ -126,6 +131,13 @@ if HTTP_CONFIG:
|
|
|
126
131
|
user_router = load_custom_app(router_import)
|
|
127
132
|
if not HTTP_CONFIG.get("disable_meta"):
|
|
128
133
|
routes.extend(meta_routes)
|
|
134
|
+
else:
|
|
135
|
+
# Otherwise the deployment will never be considered healthy
|
|
136
|
+
routes.append(
|
|
137
|
+
Route(
|
|
138
|
+
"/ok", functools.partial(ok, disabled=True), methods=["GET"], name="ok"
|
|
139
|
+
)
|
|
140
|
+
)
|
|
129
141
|
if protected_routes:
|
|
130
142
|
routes.append(
|
|
131
143
|
Mount(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import langgraph.version
|
|
1
2
|
from starlette.responses import JSONResponse, PlainTextResponse
|
|
2
3
|
|
|
3
4
|
from langgraph_api import __version__, config, metadata
|
|
@@ -16,6 +17,7 @@ async def meta_info(request: ApiRequest):
|
|
|
16
17
|
return JSONResponse(
|
|
17
18
|
{
|
|
18
19
|
"version": __version__,
|
|
20
|
+
"langgraph_py_version": langgraph.version.__version__,
|
|
19
21
|
"flags": {
|
|
20
22
|
"assistants": True,
|
|
21
23
|
"crons": plus and config.FF_CRONS_ENABLED,
|
|
@@ -172,6 +172,7 @@ async def wait_run(request: ApiRequest):
|
|
|
172
172
|
"""Create a run, wait for the output."""
|
|
173
173
|
thread_id = request.path_params["thread_id"]
|
|
174
174
|
payload = await request.json(RunCreateStateful)
|
|
175
|
+
on_disconnect = payload.get("on_disconnect", "continue")
|
|
175
176
|
run_id = uuid6()
|
|
176
177
|
sub = asyncio.create_task(Runs.Stream.subscribe(run_id))
|
|
177
178
|
|
|
@@ -197,7 +198,10 @@ async def wait_run(request: ApiRequest):
|
|
|
197
198
|
vchunk: bytes | None = None
|
|
198
199
|
async with aclosing(
|
|
199
200
|
Runs.Stream.join(
|
|
200
|
-
run["run_id"],
|
|
201
|
+
run["run_id"],
|
|
202
|
+
thread_id=run["thread_id"],
|
|
203
|
+
stream_mode=await sub,
|
|
204
|
+
cancel_on_disconnect=on_disconnect == "cancel",
|
|
201
205
|
)
|
|
202
206
|
) as stream:
|
|
203
207
|
async for mode, chunk, _ in stream:
|
|
@@ -248,6 +252,7 @@ async def wait_run(request: ApiRequest):
|
|
|
248
252
|
async def wait_run_stateless(request: ApiRequest):
|
|
249
253
|
"""Create a stateless run, wait for the output."""
|
|
250
254
|
payload = await request.json(RunCreateStateless)
|
|
255
|
+
on_disconnect = payload.get("on_disconnect", "continue")
|
|
251
256
|
run_id = uuid6()
|
|
252
257
|
sub = asyncio.create_task(Runs.Stream.subscribe(run_id))
|
|
253
258
|
|
|
@@ -277,6 +282,7 @@ async def wait_run_stateless(request: ApiRequest):
|
|
|
277
282
|
thread_id=run["thread_id"],
|
|
278
283
|
stream_mode=await sub,
|
|
279
284
|
ignore_404=True,
|
|
285
|
+
cancel_on_disconnect=on_disconnect == "cancel",
|
|
280
286
|
)
|
|
281
287
|
) as stream:
|
|
282
288
|
async for mode, chunk, _ in stream:
|
|
@@ -346,7 +346,7 @@ def run_server(
|
|
|
346
346
|
- 📚 API Docs: \033[36m{local_url}/docs\033[0m
|
|
347
347
|
|
|
348
348
|
This in-memory server is designed for development and testing.
|
|
349
|
-
For production use, please use LangGraph
|
|
349
|
+
For production use, please use LangGraph Platform.
|
|
350
350
|
|
|
351
351
|
"""
|
|
352
352
|
logger.info(welcome)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import json
|
|
2
3
|
import logging
|
|
3
4
|
import os
|
|
5
|
+
import re
|
|
4
6
|
import shutil
|
|
5
7
|
import ssl
|
|
6
8
|
from collections import deque
|
|
@@ -452,6 +454,26 @@ async def run_js_http_process(paths_str: str, http_config: dict, watch: bool = F
|
|
|
452
454
|
attempt += 1
|
|
453
455
|
|
|
454
456
|
|
|
457
|
+
_BAD_SURROGATE_RE = re.compile(r"\\u[dD][89a-fA-F][0-9a-fA-F]{2}")
|
|
458
|
+
_BAD_ESCAPE_RE = re.compile(r"\\(?![\"\\/bfnrtu])")
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _safe_json_loads(data: bytes):
|
|
462
|
+
"""Attempt *orjson.loads* first; if it fails, repair common escape issues.
|
|
463
|
+
|
|
464
|
+
For a time, we had a bug in our surrogate cleanup in serde.py, which
|
|
465
|
+
allowed sequences containing a stray backslash to be stored which would
|
|
466
|
+
then fail upon loading. This function attempts to repair those sequences.
|
|
467
|
+
"""
|
|
468
|
+
try:
|
|
469
|
+
return orjson.loads(data)
|
|
470
|
+
except orjson.JSONDecodeError:
|
|
471
|
+
txt = data.decode("utf-8", "replace")
|
|
472
|
+
txt = _BAD_ESCAPE_RE.sub(r"\\\\", txt)
|
|
473
|
+
txt = _BAD_SURROGATE_RE.sub("", txt)
|
|
474
|
+
return json.loads(txt)
|
|
475
|
+
|
|
476
|
+
|
|
455
477
|
class PassthroughSerialiser(SerializerProtocol):
|
|
456
478
|
def dumps(self, obj: Any) -> bytes:
|
|
457
479
|
return json_dumpb(obj)
|
|
@@ -460,13 +482,13 @@ class PassthroughSerialiser(SerializerProtocol):
|
|
|
460
482
|
return "json", json_dumpb(obj)
|
|
461
483
|
|
|
462
484
|
def loads(self, data: bytes) -> Any:
|
|
463
|
-
return
|
|
485
|
+
return _safe_json_loads(data)
|
|
464
486
|
|
|
465
487
|
def loads_typed(self, data: tuple[str, bytes]) -> Any:
|
|
466
488
|
type, payload = data
|
|
467
489
|
if type != "json":
|
|
468
490
|
raise ValueError(f"Unsupported type {type}")
|
|
469
|
-
return
|
|
491
|
+
return _safe_json_loads(payload)
|
|
470
492
|
|
|
471
493
|
|
|
472
494
|
def _get_passthrough_checkpointer():
|
|
@@ -55,13 +55,15 @@ RUN_COUNTER = 0
|
|
|
55
55
|
NODE_COUNTER = 0
|
|
56
56
|
FROM_TIMESTAMP = datetime.now(UTC).isoformat()
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
# Beacon endpoint for license key submissions
|
|
59
|
+
BEACON_ENDPOINT = "https://api.smith.langchain.com/v1/metadata/submit"
|
|
60
|
+
|
|
61
|
+
# LangChain auth endpoint for API key submissions
|
|
62
|
+
LANGCHAIN_METADATA_ENDPOINT = None
|
|
63
|
+
if LANGSMITH_AUTH_ENDPOINT:
|
|
64
|
+
LANGCHAIN_METADATA_ENDPOINT = (
|
|
65
|
+
LANGSMITH_AUTH_ENDPOINT.rstrip("/") + "/v1/metadata/submit"
|
|
66
|
+
)
|
|
65
67
|
|
|
66
68
|
|
|
67
69
|
def incr_runs(*, incr: int = 1) -> None:
|
|
@@ -82,8 +84,10 @@ async def metadata_loop() -> None:
|
|
|
82
84
|
if not LANGGRAPH_CLOUD_LICENSE_KEY and not LANGSMITH_API_KEY:
|
|
83
85
|
return
|
|
84
86
|
|
|
85
|
-
if
|
|
86
|
-
|
|
87
|
+
if (
|
|
88
|
+
LANGGRAPH_CLOUD_LICENSE_KEY
|
|
89
|
+
and not LANGGRAPH_CLOUD_LICENSE_KEY.startswith("lcl_")
|
|
90
|
+
and not LANGSMITH_API_KEY
|
|
87
91
|
):
|
|
88
92
|
logger.info("Running in air-gapped mode, skipping metadata loop")
|
|
89
93
|
return
|
|
@@ -102,9 +106,7 @@ async def metadata_loop() -> None:
|
|
|
102
106
|
NODE_COUNTER = 0
|
|
103
107
|
FROM_TIMESTAMP = to_timestamp
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
"license_key": LANGGRAPH_CLOUD_LICENSE_KEY,
|
|
107
|
-
"api_key": LANGSMITH_API_KEY,
|
|
109
|
+
base_payload = {
|
|
108
110
|
"from_timestamp": from_timestamp,
|
|
109
111
|
"to_timestamp": to_timestamp,
|
|
110
112
|
"tags": {
|
|
@@ -130,17 +132,66 @@ async def metadata_loop() -> None:
|
|
|
130
132
|
},
|
|
131
133
|
"logs": [],
|
|
132
134
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
|
|
136
|
+
# Track successful submissions
|
|
137
|
+
submissions_attempted = []
|
|
138
|
+
submissions_failed = []
|
|
139
|
+
|
|
140
|
+
# 1. Send to beacon endpoint if license key starts with lcl_
|
|
141
|
+
if LANGGRAPH_CLOUD_LICENSE_KEY and LANGGRAPH_CLOUD_LICENSE_KEY.startswith(
|
|
142
|
+
"lcl_"
|
|
143
|
+
):
|
|
144
|
+
beacon_payload = {
|
|
145
|
+
**base_payload,
|
|
146
|
+
"license_key": LANGGRAPH_CLOUD_LICENSE_KEY,
|
|
147
|
+
}
|
|
148
|
+
submissions_attempted.append("beacon")
|
|
149
|
+
try:
|
|
150
|
+
await http_request(
|
|
151
|
+
"POST",
|
|
152
|
+
BEACON_ENDPOINT,
|
|
153
|
+
body=orjson.dumps(beacon_payload),
|
|
154
|
+
headers={"Content-Type": "application/json"},
|
|
155
|
+
)
|
|
156
|
+
await logger.ainfo("Successfully submitted metadata to beacon endpoint")
|
|
157
|
+
except Exception as e:
|
|
158
|
+
submissions_failed.append("beacon")
|
|
159
|
+
await logger.awarning(
|
|
160
|
+
"Beacon metadata submission failed.", error=str(e)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# 2. Send to langchain auth endpoint if API key is set
|
|
164
|
+
if LANGSMITH_API_KEY and LANGCHAIN_METADATA_ENDPOINT:
|
|
165
|
+
langchain_payload = {
|
|
166
|
+
**base_payload,
|
|
167
|
+
"api_key": LANGSMITH_API_KEY,
|
|
168
|
+
}
|
|
169
|
+
submissions_attempted.append("langchain")
|
|
170
|
+
try:
|
|
171
|
+
await http_request(
|
|
172
|
+
"POST",
|
|
173
|
+
LANGCHAIN_METADATA_ENDPOINT,
|
|
174
|
+
body=orjson.dumps(langchain_payload),
|
|
175
|
+
headers={"Content-Type": "application/json"},
|
|
176
|
+
)
|
|
177
|
+
logger.info("Successfully submitted metadata to LangSmith instance")
|
|
178
|
+
except Exception as e:
|
|
179
|
+
submissions_failed.append("langchain")
|
|
180
|
+
await logger.awarning(
|
|
181
|
+
"LangChain metadata submission failed.", error=str(e)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if submissions_attempted and len(submissions_failed) == len(
|
|
185
|
+
submissions_attempted
|
|
186
|
+
):
|
|
141
187
|
# retry on next iteration
|
|
142
188
|
incr_runs(incr=runs)
|
|
143
189
|
incr_nodes("", incr=nodes)
|
|
144
190
|
FROM_TIMESTAMP = from_timestamp
|
|
145
|
-
await logger.
|
|
191
|
+
await logger.awarning(
|
|
192
|
+
"All metadata submissions failed, will retry",
|
|
193
|
+
attempted=submissions_attempted,
|
|
194
|
+
failed=submissions_failed,
|
|
195
|
+
)
|
|
196
|
+
|
|
146
197
|
await asyncio.sleep(INTERVAL)
|
|
@@ -123,16 +123,18 @@ def _sanitise(o: Any) -> Any:
|
|
|
123
123
|
|
|
124
124
|
def json_dumpb(obj) -> bytes:
|
|
125
125
|
try:
|
|
126
|
-
|
|
127
|
-
rb"\u0000", b""
|
|
128
|
-
) # null unicode char not allowed in json
|
|
126
|
+
dumped = orjson.dumps(obj, default=default, option=_option)
|
|
129
127
|
except TypeError as e:
|
|
130
128
|
if "surrogates not allowed" not in str(e):
|
|
131
129
|
raise
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
130
|
+
dumped = orjson.dumps(_sanitise(obj), default=default, option=_option)
|
|
131
|
+
return (
|
|
132
|
+
# Unfortunately simply doing ``.replace(rb"\\u0000", b"")`` on
|
|
133
|
+
# the dumped bytes can leave an **orphaned back-slash** (e.g. ``\\q``)
|
|
134
|
+
# which makes the resulting JSON invalid. The fix is to delete the *double*
|
|
135
|
+
# back-slash form **first**, then (optionally) the single-escapes.
|
|
136
|
+
dumped.replace(rb"\\u0000", b"").replace(rb"\u0000", b"")
|
|
137
|
+
)
|
|
136
138
|
|
|
137
139
|
|
|
138
140
|
def json_loads(content: bytes | Fragment | dict) -> Any:
|
|
@@ -154,6 +156,10 @@ class Serializer(JsonPlusSerializer):
|
|
|
154
156
|
except TypeError:
|
|
155
157
|
return "pickle", cloudpickle.dumps(obj)
|
|
156
158
|
|
|
159
|
+
def dumps(self, obj: Any) -> bytes:
|
|
160
|
+
# See comment above (in json_dumpb)
|
|
161
|
+
return super().dumps(obj).replace(rb"\\u0000", b"").replace(rb"\u0000", b"")
|
|
162
|
+
|
|
157
163
|
def loads_typed(self, data: tuple[str, bytes]) -> Any:
|
|
158
164
|
if data[0] == "pickle":
|
|
159
165
|
try:
|
|
@@ -307,23 +307,9 @@ async def worker(
|
|
|
307
307
|
conn, run["thread_id"], run_id, status, checkpoint, exception
|
|
308
308
|
)
|
|
309
309
|
|
|
310
|
-
# delete
|
|
311
|
-
if not isinstance(exception, ALL_RETRIABLE_EXCEPTIONS):
|
|
312
|
-
|
|
313
|
-
await Threads.delete(conn, run["thread_id"])
|
|
314
|
-
else:
|
|
315
|
-
try:
|
|
316
|
-
await Threads.set_status(
|
|
317
|
-
conn, run["thread_id"], checkpoint, exception
|
|
318
|
-
)
|
|
319
|
-
except HTTPException as e:
|
|
320
|
-
if e.status_code == 404:
|
|
321
|
-
await logger.ainfo(
|
|
322
|
-
"Ignoring set_status error for missing thread",
|
|
323
|
-
exc=str(e),
|
|
324
|
-
)
|
|
325
|
-
else:
|
|
326
|
-
raise
|
|
310
|
+
# delete thread if it's temporary and we don't want to retry
|
|
311
|
+
if temporary and not isinstance(exception, ALL_RETRIABLE_EXCEPTIONS):
|
|
312
|
+
await Threads.delete(conn, run["thread_id"])
|
|
327
313
|
|
|
328
314
|
if isinstance(exception, ALL_RETRIABLE_EXCEPTIONS):
|
|
329
315
|
await logger.awarning("RETRYING", exc_info=exception)
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
version = 1
|
|
2
2
|
revision = 2
|
|
3
3
|
requires-python = ">=3.11"
|
|
4
|
-
resolution-markers = [
|
|
5
|
-
"python_full_version >= '3.12.4'",
|
|
6
|
-
"python_full_version < '3.12.4'",
|
|
7
|
-
]
|
|
8
4
|
|
|
9
5
|
[[package]]
|
|
10
6
|
name = "aiosqlite"
|
|
@@ -55,11 +51,11 @@ wheels = [
|
|
|
55
51
|
|
|
56
52
|
[[package]]
|
|
57
53
|
name = "certifi"
|
|
58
|
-
version = "2025.
|
|
54
|
+
version = "2025.7.9"
|
|
59
55
|
source = { registry = "https://pypi.org/simple" }
|
|
60
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
56
|
+
sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" }
|
|
61
57
|
wheels = [
|
|
62
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
58
|
+
{ url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" },
|
|
63
59
|
]
|
|
64
60
|
|
|
65
61
|
[[package]]
|
|
@@ -237,16 +233,16 @@ wheels = [
|
|
|
237
233
|
|
|
238
234
|
[[package]]
|
|
239
235
|
name = "fastapi"
|
|
240
|
-
version = "0.
|
|
236
|
+
version = "0.116.0"
|
|
241
237
|
source = { registry = "https://pypi.org/simple" }
|
|
242
238
|
dependencies = [
|
|
243
239
|
{ name = "pydantic" },
|
|
244
240
|
{ name = "starlette" },
|
|
245
241
|
{ name = "typing-extensions" },
|
|
246
242
|
]
|
|
247
|
-
sdist = { url = "https://files.pythonhosted.org/packages/20/
|
|
243
|
+
sdist = { url = "https://files.pythonhosted.org/packages/20/38/e1da78736143fd885c36213a3ccc493c384ae8fea6a0f0bc272ef42ebea8/fastapi-0.116.0.tar.gz", hash = "sha256:80dc0794627af0390353a6d1171618276616310d37d24faba6648398e57d687a", size = 296518, upload-time = "2025-07-07T15:09:27.82Z" }
|
|
248
244
|
wheels = [
|
|
249
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
245
|
+
{ url = "https://files.pythonhosted.org/packages/2f/68/d80347fe2360445b5f58cf290e588a4729746e7501080947e6cdae114b1f/fastapi-0.116.0-py3-none-any.whl", hash = "sha256:fdcc9ed272eaef038952923bef2b735c02372402d1203ee1210af4eea7a78d2b", size = 95625, upload-time = "2025-07-07T15:09:26.348Z" },
|
|
250
246
|
]
|
|
251
247
|
|
|
252
248
|
[[package]]
|
|
@@ -362,7 +358,7 @@ wheels = [
|
|
|
362
358
|
|
|
363
359
|
[[package]]
|
|
364
360
|
name = "langchain-core"
|
|
365
|
-
version = "0.3.
|
|
361
|
+
version = "0.3.68"
|
|
366
362
|
source = { registry = "https://pypi.org/simple" }
|
|
367
363
|
dependencies = [
|
|
368
364
|
{ name = "jsonpatch" },
|
|
@@ -373,14 +369,14 @@ dependencies = [
|
|
|
373
369
|
{ name = "tenacity" },
|
|
374
370
|
{ name = "typing-extensions" },
|
|
375
371
|
]
|
|
376
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
372
|
+
sdist = { url = "https://files.pythonhosted.org/packages/23/20/f5b18a17bfbe3416177e702ab2fd230b7d168abb17be31fb48f43f0bb772/langchain_core-0.3.68.tar.gz", hash = "sha256:312e1932ac9aa2eaf111b70fdc171776fa571d1a86c1f873dcac88a094b19c6f", size = 563041, upload-time = "2025-07-03T17:02:28.704Z" }
|
|
377
373
|
wheels = [
|
|
378
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
374
|
+
{ url = "https://files.pythonhosted.org/packages/f9/da/c89be0a272993bfcb762b2a356b9f55de507784c2755ad63caec25d183bf/langchain_core-0.3.68-py3-none-any.whl", hash = "sha256:5e5c1fbef419590537c91b8c2d86af896fbcbaf0d5ed7fdcdd77f7d8f3467ba0", size = 441405, upload-time = "2025-07-03T17:02:27.115Z" },
|
|
379
375
|
]
|
|
380
376
|
|
|
381
377
|
[[package]]
|
|
382
378
|
name = "langgraph"
|
|
383
|
-
version = "0.5.
|
|
379
|
+
version = "0.5.2"
|
|
384
380
|
source = { registry = "https://pypi.org/simple" }
|
|
385
381
|
dependencies = [
|
|
386
382
|
{ name = "langchain-core" },
|
|
@@ -390,9 +386,9 @@ dependencies = [
|
|
|
390
386
|
{ name = "pydantic" },
|
|
391
387
|
{ name = "xxhash" },
|
|
392
388
|
]
|
|
393
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
389
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/18/1e255fc8c36ff5056d797d83c9ca9fd926683ace294a9ba38c4b40599237/langgraph-0.5.2.tar.gz", hash = "sha256:393b767e9d6a129636a9df36edc492499336c71e4ee268e64b9d1299d30e636c", size = 442564, upload-time = "2025-07-09T19:15:20.219Z" }
|
|
394
390
|
wheels = [
|
|
395
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
391
|
+
{ url = "https://files.pythonhosted.org/packages/3b/44/6e6c41a3cc00d533dc91cc5f086862b1fccf34aa0ec9605a2cbd116c6ba0/langgraph-0.5.2-py3-none-any.whl", hash = "sha256:db6b8053bf99887957fe45ec27918f8819c4bba269afde88b538e00e9301a581", size = 143735, upload-time = "2025-07-09T19:15:18.733Z" },
|
|
396
392
|
]
|
|
397
393
|
|
|
398
394
|
[[package]]
|
|
@@ -512,28 +508,28 @@ wheels = [
|
|
|
512
508
|
|
|
513
509
|
[[package]]
|
|
514
510
|
name = "langgraph-cli"
|
|
515
|
-
version = "0.3.
|
|
511
|
+
version = "0.3.4"
|
|
516
512
|
source = { registry = "https://pypi.org/simple" }
|
|
517
513
|
dependencies = [
|
|
518
514
|
{ name = "click" },
|
|
519
515
|
{ name = "langgraph-sdk" },
|
|
520
516
|
]
|
|
521
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
517
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fe/ee/41f54032b2ab64c06e66e7f5e7a6c22d9159f2bff6bf08a38c9f11f84753/langgraph_cli-0.3.4.tar.gz", hash = "sha256:6300df4fc6f7106fd5fcdba2cbec9e8b1158daa6760d41333d1b3b5999280ad0", size = 728156, upload-time = "2025-07-08T19:52:24.687Z" }
|
|
522
518
|
wheels = [
|
|
523
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
519
|
+
{ url = "https://files.pythonhosted.org/packages/e2/9c/310dae8c638477e2f0e5744726d4b283878c1e11639fa693bf24b23cf7ac/langgraph_cli-0.3.4-py3-none-any.whl", hash = "sha256:b3ac9fbc67cec5d0295c23a9e7a9014f34502639fb52b2d02c89b3bb2ba36c33", size = 36525, upload-time = "2025-07-08T19:52:23.351Z" },
|
|
524
520
|
]
|
|
525
521
|
|
|
526
522
|
[[package]]
|
|
527
523
|
name = "langgraph-prebuilt"
|
|
528
|
-
version = "0.5.
|
|
524
|
+
version = "0.5.2"
|
|
529
525
|
source = { registry = "https://pypi.org/simple" }
|
|
530
526
|
dependencies = [
|
|
531
527
|
{ name = "langchain-core" },
|
|
532
528
|
{ name = "langgraph-checkpoint" },
|
|
533
529
|
]
|
|
534
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
530
|
+
sdist = { url = "https://files.pythonhosted.org/packages/bb/11/98134c47832fbde0caf0e06f1a104577da9215c358d7854093c1d835b272/langgraph_prebuilt-0.5.2.tar.gz", hash = "sha256:2c900a5be0d6a93ea2521e0d931697cad2b646f1fcda7aa5c39d8d7539772465", size = 117808, upload-time = "2025-06-30T19:52:48.307Z" }
|
|
535
531
|
wheels = [
|
|
536
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
532
|
+
{ url = "https://files.pythonhosted.org/packages/c3/64/6bc45ab9e0e1112698ebff579fe21f5606ea65cd08266995a357e312a4d2/langgraph_prebuilt-0.5.2-py3-none-any.whl", hash = "sha256:1f4cd55deca49dffc3e5127eec12fcd244fc381321002f728afa88642d5ec59d", size = 23776, upload-time = "2025-06-30T19:52:47.494Z" },
|
|
537
533
|
]
|
|
538
534
|
|
|
539
535
|
[[package]]
|
|
@@ -571,20 +567,20 @@ dev = [
|
|
|
571
567
|
|
|
572
568
|
[[package]]
|
|
573
569
|
name = "langgraph-sdk"
|
|
574
|
-
version = "0.1.
|
|
570
|
+
version = "0.1.72"
|
|
575
571
|
source = { registry = "https://pypi.org/simple" }
|
|
576
572
|
dependencies = [
|
|
577
573
|
{ name = "httpx" },
|
|
578
574
|
{ name = "orjson" },
|
|
579
575
|
]
|
|
580
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
576
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/a6/cf13ace9bc7f0e8b13852ced0b37ece97f3140e232821c28bc852f8c1ea2/langgraph_sdk-0.1.72.tar.gz", hash = "sha256:396d8195881830700e2d54a0a9ee273e8b1173428e667502ef9c182a3cec7ab7", size = 71600, upload-time = "2025-06-27T01:12:03.788Z" }
|
|
581
577
|
wheels = [
|
|
582
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
578
|
+
{ url = "https://files.pythonhosted.org/packages/4b/4b/d56b51da08d168c2315cd092faa47bc83388b116756dbd6995026ec9ba3f/langgraph_sdk-0.1.72-py3-none-any.whl", hash = "sha256:925d3fcc7a26361db04f9c4beb3ec05bc36361b2a836d181ff2ab145071ec3ce", size = 50129, upload-time = "2025-06-27T01:12:02.449Z" },
|
|
583
579
|
]
|
|
584
580
|
|
|
585
581
|
[[package]]
|
|
586
582
|
name = "langsmith"
|
|
587
|
-
version = "0.
|
|
583
|
+
version = "0.4.4"
|
|
588
584
|
source = { registry = "https://pypi.org/simple" }
|
|
589
585
|
dependencies = [
|
|
590
586
|
{ name = "httpx" },
|
|
@@ -595,9 +591,9 @@ dependencies = [
|
|
|
595
591
|
{ name = "requests-toolbelt" },
|
|
596
592
|
{ name = "zstandard" },
|
|
597
593
|
]
|
|
598
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
594
|
+
sdist = { url = "https://files.pythonhosted.org/packages/20/c8/8d2e0fc438d2d3d8d4300f7684ea30a754344ed00d7ba9cc2705241d2a5f/langsmith-0.4.4.tar.gz", hash = "sha256:70c53bbff24a7872e88e6fa0af98270f4986a6e364f9e85db1cc5636defa4d66", size = 352105, upload-time = "2025-06-27T19:20:36.207Z" }
|
|
599
595
|
wheels = [
|
|
600
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
596
|
+
{ url = "https://files.pythonhosted.org/packages/1d/33/a3337eb70d795495a299a1640d7a75f17fb917155a64309b96106e7b9452/langsmith-0.4.4-py3-none-any.whl", hash = "sha256:014c68329bd085bd6c770a6405c61bb6881f82eb554ce8c4d1984b0035fd1716", size = 367687, upload-time = "2025-06-27T19:20:33.839Z" },
|
|
601
597
|
]
|
|
602
598
|
|
|
603
599
|
[[package]]
|
|
@@ -881,11 +877,11 @@ wheels = [
|
|
|
881
877
|
|
|
882
878
|
[[package]]
|
|
883
879
|
name = "pygments"
|
|
884
|
-
version = "2.19.
|
|
880
|
+
version = "2.19.2"
|
|
885
881
|
source = { registry = "https://pypi.org/simple" }
|
|
886
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
882
|
+
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
|
887
883
|
wheels = [
|
|
888
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
884
|
+
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
|
889
885
|
]
|
|
890
886
|
|
|
891
887
|
[[package]]
|
|
@@ -1025,27 +1021,27 @@ wheels = [
|
|
|
1025
1021
|
|
|
1026
1022
|
[[package]]
|
|
1027
1023
|
name = "ruff"
|
|
1028
|
-
version = "0.12.
|
|
1029
|
-
source = { registry = "https://pypi.org/simple" }
|
|
1030
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1031
|
-
wheels = [
|
|
1032
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1033
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1034
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1035
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1036
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1037
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1038
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1039
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1040
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1041
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1042
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1043
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1044
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1045
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1046
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1047
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1048
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1024
|
+
version = "0.12.2"
|
|
1025
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1026
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6c/3d/d9a195676f25d00dbfcf3cf95fdd4c685c497fcfa7e862a44ac5e4e96480/ruff-0.12.2.tar.gz", hash = "sha256:d7b4f55cd6f325cb7621244f19c873c565a08aff5a4ba9c69aa7355f3f7afd3e", size = 4432239, upload-time = "2025-07-03T16:40:19.566Z" }
|
|
1027
|
+
wheels = [
|
|
1028
|
+
{ url = "https://files.pythonhosted.org/packages/74/b6/2098d0126d2d3318fd5bec3ad40d06c25d377d95749f7a0c5af17129b3b1/ruff-0.12.2-py3-none-linux_armv6l.whl", hash = "sha256:093ea2b221df1d2b8e7ad92fc6ffdca40a2cb10d8564477a987b44fd4008a7be", size = 10369761, upload-time = "2025-07-03T16:39:38.847Z" },
|
|
1029
|
+
{ url = "https://files.pythonhosted.org/packages/b1/4b/5da0142033dbe155dc598cfb99262d8ee2449d76920ea92c4eeb9547c208/ruff-0.12.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:09e4cf27cc10f96b1708100fa851e0daf21767e9709e1649175355280e0d950e", size = 11155659, upload-time = "2025-07-03T16:39:42.294Z" },
|
|
1030
|
+
{ url = "https://files.pythonhosted.org/packages/3e/21/967b82550a503d7c5c5c127d11c935344b35e8c521f52915fc858fb3e473/ruff-0.12.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8ae64755b22f4ff85e9c52d1f82644abd0b6b6b6deedceb74bd71f35c24044cc", size = 10537769, upload-time = "2025-07-03T16:39:44.75Z" },
|
|
1031
|
+
{ url = "https://files.pythonhosted.org/packages/33/91/00cff7102e2ec71a4890fb7ba1803f2cdb122d82787c7d7cf8041fe8cbc1/ruff-0.12.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eb3a6b2db4d6e2c77e682f0b988d4d61aff06860158fdb413118ca133d57922", size = 10717602, upload-time = "2025-07-03T16:39:47.652Z" },
|
|
1032
|
+
{ url = "https://files.pythonhosted.org/packages/9b/eb/928814daec4e1ba9115858adcda44a637fb9010618721937491e4e2283b8/ruff-0.12.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:73448de992d05517170fc37169cbca857dfeaeaa8c2b9be494d7bcb0d36c8f4b", size = 10198772, upload-time = "2025-07-03T16:39:49.641Z" },
|
|
1033
|
+
{ url = "https://files.pythonhosted.org/packages/50/fa/f15089bc20c40f4f72334f9145dde55ab2b680e51afb3b55422effbf2fb6/ruff-0.12.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b8b94317cbc2ae4a2771af641739f933934b03555e51515e6e021c64441532d", size = 11845173, upload-time = "2025-07-03T16:39:52.069Z" },
|
|
1034
|
+
{ url = "https://files.pythonhosted.org/packages/43/9f/1f6f98f39f2b9302acc161a4a2187b1e3a97634fe918a8e731e591841cf4/ruff-0.12.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45fc42c3bf1d30d2008023a0a9a0cfb06bf9835b147f11fe0679f21ae86d34b1", size = 12553002, upload-time = "2025-07-03T16:39:54.551Z" },
|
|
1035
|
+
{ url = "https://files.pythonhosted.org/packages/d8/70/08991ac46e38ddd231c8f4fd05ef189b1b94be8883e8c0c146a025c20a19/ruff-0.12.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce48f675c394c37e958bf229fb5c1e843e20945a6d962cf3ea20b7a107dcd9f4", size = 12171330, upload-time = "2025-07-03T16:39:57.55Z" },
|
|
1036
|
+
{ url = "https://files.pythonhosted.org/packages/88/a9/5a55266fec474acfd0a1c73285f19dd22461d95a538f29bba02edd07a5d9/ruff-0.12.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:793d8859445ea47591272021a81391350205a4af65a9392401f418a95dfb75c9", size = 11774717, upload-time = "2025-07-03T16:39:59.78Z" },
|
|
1037
|
+
{ url = "https://files.pythonhosted.org/packages/87/e5/0c270e458fc73c46c0d0f7cf970bb14786e5fdb88c87b5e423a4bd65232b/ruff-0.12.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6932323db80484dda89153da3d8e58164d01d6da86857c79f1961934354992da", size = 11646659, upload-time = "2025-07-03T16:40:01.934Z" },
|
|
1038
|
+
{ url = "https://files.pythonhosted.org/packages/b7/b6/45ab96070c9752af37f0be364d849ed70e9ccede07675b0ec4e3ef76b63b/ruff-0.12.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6aa7e623a3a11538108f61e859ebf016c4f14a7e6e4eba1980190cacb57714ce", size = 10604012, upload-time = "2025-07-03T16:40:04.363Z" },
|
|
1039
|
+
{ url = "https://files.pythonhosted.org/packages/86/91/26a6e6a424eb147cc7627eebae095cfa0b4b337a7c1c413c447c9ebb72fd/ruff-0.12.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2a4a20aeed74671b2def096bdf2eac610c7d8ffcbf4fb0e627c06947a1d7078d", size = 10176799, upload-time = "2025-07-03T16:40:06.514Z" },
|
|
1040
|
+
{ url = "https://files.pythonhosted.org/packages/f5/0c/9f344583465a61c8918a7cda604226e77b2c548daf8ef7c2bfccf2b37200/ruff-0.12.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:71a4c550195612f486c9d1f2b045a600aeba851b298c667807ae933478fcef04", size = 11241507, upload-time = "2025-07-03T16:40:08.708Z" },
|
|
1041
|
+
{ url = "https://files.pythonhosted.org/packages/1c/b7/99c34ded8fb5f86c0280278fa89a0066c3760edc326e935ce0b1550d315d/ruff-0.12.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4987b8f4ceadf597c927beee65a5eaf994c6e2b631df963f86d8ad1bdea99342", size = 11717609, upload-time = "2025-07-03T16:40:10.836Z" },
|
|
1042
|
+
{ url = "https://files.pythonhosted.org/packages/51/de/8589fa724590faa057e5a6d171e7f2f6cffe3287406ef40e49c682c07d89/ruff-0.12.2-py3-none-win32.whl", hash = "sha256:369ffb69b70cd55b6c3fc453b9492d98aed98062db9fec828cdfd069555f5f1a", size = 10523823, upload-time = "2025-07-03T16:40:13.203Z" },
|
|
1043
|
+
{ url = "https://files.pythonhosted.org/packages/94/47/8abf129102ae4c90cba0c2199a1a9b0fa896f6f806238d6f8c14448cc748/ruff-0.12.2-py3-none-win_amd64.whl", hash = "sha256:dca8a3b6d6dc9810ed8f328d406516bf4d660c00caeaef36eb831cf4871b0639", size = 11629831, upload-time = "2025-07-03T16:40:15.478Z" },
|
|
1044
|
+
{ url = "https://files.pythonhosted.org/packages/e2/1f/72d2946e3cc7456bb837e88000eb3437e55f80db339c840c04015a11115d/ruff-0.12.2-py3-none-win_arm64.whl", hash = "sha256:48d6c6bfb4761df68bc05ae630e24f506755e702d4fb08f08460be778c7ccb12", size = 10735334, upload-time = "2025-07-03T16:40:17.677Z" },
|
|
1049
1045
|
]
|
|
1050
1046
|
|
|
1051
1047
|
[[package]]
|
|
@@ -1124,11 +1120,11 @@ wheels = [
|
|
|
1124
1120
|
|
|
1125
1121
|
[[package]]
|
|
1126
1122
|
name = "typing-extensions"
|
|
1127
|
-
version = "4.14.
|
|
1123
|
+
version = "4.14.1"
|
|
1128
1124
|
source = { registry = "https://pypi.org/simple" }
|
|
1129
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1125
|
+
sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" }
|
|
1130
1126
|
wheels = [
|
|
1131
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1127
|
+
{ url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" },
|
|
1132
1128
|
]
|
|
1133
1129
|
|
|
1134
1130
|
[[package]]
|
|
@@ -1154,15 +1150,15 @@ wheels = [
|
|
|
1154
1150
|
|
|
1155
1151
|
[[package]]
|
|
1156
1152
|
name = "uvicorn"
|
|
1157
|
-
version = "0.
|
|
1153
|
+
version = "0.35.0"
|
|
1158
1154
|
source = { registry = "https://pypi.org/simple" }
|
|
1159
1155
|
dependencies = [
|
|
1160
1156
|
{ name = "click" },
|
|
1161
1157
|
{ name = "h11" },
|
|
1162
1158
|
]
|
|
1163
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
1159
|
+
sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" }
|
|
1164
1160
|
wheels = [
|
|
1165
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1161
|
+
{ url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" },
|
|
1166
1162
|
]
|
|
1167
1163
|
|
|
1168
1164
|
[[package]]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.78"
|
|
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
|
|
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
|