langgraph-api 0.2.64__tar.gz → 0.2.67__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.64 → langgraph_api-0.2.67}/Makefile +1 -1
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/PKG-INFO +1 -1
- langgraph_api-0.2.67/benchmark/.gitignore +3 -0
- langgraph_api-0.2.67/benchmark/Makefile +6 -0
- langgraph_api-0.2.67/benchmark/README.md +43 -0
- langgraph_api-0.2.67/benchmark/burst.js +195 -0
- langgraph_api-0.2.67/langgraph_api/__init__.py +1 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/custom.py +3 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/cli.py +46 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/remote.py +2 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/worker.py +2 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/openapi.json +1 -3
- langgraph_api-0.2.64/langgraph_api/__init__.py +0 -1
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/.gitignore +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/LICENSE +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/README.md +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/benchmark/weather.js +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/constraints.txt +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/forbidden.txt +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/healthcheck.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/assistants.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/mcp.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/meta.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/openapi.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/runs.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/store.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/threads.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/api/ui.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/asgi_transport.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/asyncio.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/langsmith/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/langsmith/backend.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/langsmith/client.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/middleware.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/noop.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/auth/studio_user.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/command.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/config.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/cron_scheduler.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/errors.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/graph.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/http.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/.gitignore +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/.prettierrc +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/base.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/build.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/client.http.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/client.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/errors.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/global.d.ts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/package.json +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/schema.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/graph.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/load.hooks.mjs +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/preload.mjs +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/utils/files.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/utils/importMap.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/src/utils/serde.mts +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/sse.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/tsconfig.json +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/ui.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/js/yarn.lock +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/logging.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/metadata.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/middleware/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/middleware/http_logger.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/middleware/private_network.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/middleware/request_id.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/models/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/models/run.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/patch.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/queue_entrypoint.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/route.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/schema.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/serde.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/server.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/sse.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/state.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/store.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/stream.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/thread_ttl.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/tunneling/cloudflare.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/utils.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/validation.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_api/webhook.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_license/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_license/validation.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/__init__.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/checkpoint.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/database.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/lifespan.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/metrics.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/ops.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/queue.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/retry.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/langgraph_runtime/store.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/logging.json +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/pyproject.toml +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/scripts/create_license.py +0 -0
- {langgraph_api-0.2.64 → langgraph_api-0.2.67}/uv.lock +0 -0
|
@@ -55,7 +55,7 @@ start:
|
|
|
55
55
|
LANGGRAPH_AES_KEY='$(LANGGRAPH_AES_KEY)' \
|
|
56
56
|
N_JOBS_PER_WORKER=2 \
|
|
57
57
|
LANGGRAPH_CONFIG='{"agent": {"configurable": {"model_name": "openai"}}}' \
|
|
58
|
-
LANGSERVE_GRAPHS='{"agent": "./tests/graphs/agent.py:graph", "single_node": "./tests/graphs/single_node.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph"}' \
|
|
58
|
+
LANGSERVE_GRAPHS='{"agent": "./tests/graphs/agent.py:graph", "single_node": "./tests/graphs/single_node.py:graph", "benchmark": "./tests/graphs/benchmark.py:graph", "other": "./tests/graphs/other.py:make_graph", "weather": "./tests/graphs/weather.py:mk_weather_graph", "searchy": "./tests/graphs/searchy.py:graph", "agent_simple": "./tests/graphs/agent_simple.py:graph"}' \
|
|
59
59
|
LANGGRAPH_STORE='$(STORE_CONFIG)' \
|
|
60
60
|
LANGGRAPH_CONFIG='{"agent": {"configurable": {"model_name": "openai"}}}' \
|
|
61
61
|
LANGSMITH_LANGGRAPH_API_VARIANT=test \
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# K6 Performance Testing
|
|
2
|
+
|
|
3
|
+
K6 is a modern load testing tool that allows you to test the performance and reliability of your APIs. The tests in this directory are designed to validate the performance characteristics of the LangGraph API under various load conditions.
|
|
4
|
+
|
|
5
|
+
## Test Scenarios
|
|
6
|
+
|
|
7
|
+
### Available Tests
|
|
8
|
+
|
|
9
|
+
1. Burst - Kick off a burst of /run/wait requests.
|
|
10
|
+
|
|
11
|
+
## Running Tests Locally
|
|
12
|
+
|
|
13
|
+
### Prerequisites
|
|
14
|
+
|
|
15
|
+
1. Install k6: https://k6.io/docs/getting-started/installation/
|
|
16
|
+
2. Start your LangGraph API service
|
|
17
|
+
3. Ensure the API is accessible at `http://localhost:9123`
|
|
18
|
+
|
|
19
|
+
### Basic Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Run burst test with default burst size (50)
|
|
23
|
+
make benchmark-burst
|
|
24
|
+
|
|
25
|
+
# Run burst test with custom burst size
|
|
26
|
+
BURST_SIZE=500 make benchmark-burst
|
|
27
|
+
|
|
28
|
+
# Run burst test against a deployment
|
|
29
|
+
BASE_URL=https://jdr-debug-31ac2c83eef557309f21c1e98d822025.us.langgraph.app make benchmark-burst
|
|
30
|
+
|
|
31
|
+
# Clean up result files
|
|
32
|
+
make benchmark-clean
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Output
|
|
36
|
+
|
|
37
|
+
Summary results are written to stdout and persisted in a summary_burst file. More detailed results for the same burst are persisted in a results_burst file.
|
|
38
|
+
|
|
39
|
+
## Resources
|
|
40
|
+
|
|
41
|
+
- [K6 Documentation](https://k6.io/docs/)
|
|
42
|
+
- [K6 JavaScript API](https://k6.io/docs/javascript-api/)
|
|
43
|
+
- [Performance Testing Best Practices](https://k6.io/docs/testing-guides/)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import http from 'k6/http';
|
|
2
|
+
import { check } from 'k6';
|
|
3
|
+
import { Counter, Trend, Rate } from 'k6/metrics';
|
|
4
|
+
import exec from 'k6/execution';
|
|
5
|
+
|
|
6
|
+
// Custom metrics
|
|
7
|
+
const runDuration = new Trend('run_duration');
|
|
8
|
+
const successfulRuns = new Counter('successful_runs');
|
|
9
|
+
const failedRuns = new Counter('failed_runs');
|
|
10
|
+
const timeoutErrors = new Counter('timeout_errors');
|
|
11
|
+
const connectionErrors = new Counter('connection_errors');
|
|
12
|
+
const serverErrors = new Counter('server_errors');
|
|
13
|
+
const otherErrors = new Counter('other_errors');
|
|
14
|
+
const burstSuccessRate = new Rate('burst_success_rate');
|
|
15
|
+
|
|
16
|
+
// URL of your LangGraph server
|
|
17
|
+
const BASE_URL = __ENV.BASE_URL || 'http://localhost:9123';
|
|
18
|
+
const BURST_SIZE = parseInt(__ENV.BURST_SIZE || '50');
|
|
19
|
+
|
|
20
|
+
// Burst testing configuration
|
|
21
|
+
export let options = {
|
|
22
|
+
scenarios: {
|
|
23
|
+
burst_test: {
|
|
24
|
+
executor: 'shared-iterations', // All VUs share the total iterations
|
|
25
|
+
vus: BURST_SIZE, // Number of concurrent requests in the burst
|
|
26
|
+
iterations: BURST_SIZE, // Each VU does one request per burst
|
|
27
|
+
maxDuration: '10s', // Time limit for each burst
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
thresholds: {
|
|
31
|
+
'run_duration': ['p(95)<3500'],
|
|
32
|
+
'burst_success_rate': ['rate>0.99'],
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Main test function - executes during the burst
|
|
37
|
+
export default function() {
|
|
38
|
+
const startTime = new Date().getTime();
|
|
39
|
+
|
|
40
|
+
// Create a unique identifier for each VU
|
|
41
|
+
const burstId = __ENV.BURST_ID || '1';
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
// Log burst start
|
|
45
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} starting request`);
|
|
46
|
+
|
|
47
|
+
// Prepare the request payload
|
|
48
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
49
|
+
|
|
50
|
+
// Create a payload with the LangGraph agent configuration
|
|
51
|
+
const payload = JSON.stringify({
|
|
52
|
+
assistant_id: "benchmark",
|
|
53
|
+
config: { delay: 0.1 },
|
|
54
|
+
input: {delay: 0.1, random_value: 'hello'},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Make a single request to the wait endpoint
|
|
58
|
+
const response = http.post(`${BASE_URL}/runs/wait`, payload, {
|
|
59
|
+
headers,
|
|
60
|
+
timeout: '35s'
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Check the response
|
|
64
|
+
const success = check(response, {
|
|
65
|
+
'Run completed successfully': (r) => r.status === 200,
|
|
66
|
+
'Response contains data': (r) => r.body.length > 0,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (success) {
|
|
70
|
+
// Record success metrics
|
|
71
|
+
const duration = new Date().getTime() - startTime;
|
|
72
|
+
runDuration.add(duration);
|
|
73
|
+
successfulRuns.add(1);
|
|
74
|
+
burstSuccessRate.add(1); // 1 = success
|
|
75
|
+
|
|
76
|
+
// Optional: Log successful run details
|
|
77
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} completed in ${duration/1000}s`);
|
|
78
|
+
} else {
|
|
79
|
+
// Handle failure
|
|
80
|
+
failedRuns.add(1);
|
|
81
|
+
burstSuccessRate.add(0); // 0 = failure
|
|
82
|
+
|
|
83
|
+
// Classify error based on status code or response
|
|
84
|
+
if (response.status >= 500) {
|
|
85
|
+
serverErrors.add(1);
|
|
86
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} server error: ${response.status}`);
|
|
87
|
+
} else if (response.status === 408 || response.error === 'timeout') {
|
|
88
|
+
timeoutErrors.add(1);
|
|
89
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} timeout error: ${response.error}`);
|
|
90
|
+
} else {
|
|
91
|
+
otherErrors.add(1);
|
|
92
|
+
console.log(`response: ${JSON.stringify(response)}`);
|
|
93
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} other error: Status ${response.status}, ${response.error}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
} catch (error) {
|
|
98
|
+
// Handle exceptions (network errors, etc.)
|
|
99
|
+
failedRuns.add(1);
|
|
100
|
+
burstSuccessRate.add(0); // 0 = failure
|
|
101
|
+
|
|
102
|
+
if (error.message.includes('timeout')) {
|
|
103
|
+
timeoutErrors.add(1);
|
|
104
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} timeout error: ${error.message}`);
|
|
105
|
+
} else if (error.message.includes('connection') || error.message.includes('network')) {
|
|
106
|
+
connectionErrors.add(1);
|
|
107
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} connection error: ${error.message}`);
|
|
108
|
+
} else {
|
|
109
|
+
otherErrors.add(1);
|
|
110
|
+
console.log(`[Burst ${burstId}] VU ${exec.vu.idInInstance} unexpected error: ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Setup function
|
|
116
|
+
export function setup() {
|
|
117
|
+
console.log(`Starting burst benchmark`);
|
|
118
|
+
console.log(`Running on pod: ${__ENV.POD_NAME || 'local'}`);
|
|
119
|
+
console.log(`Burst size: ${BURST_SIZE}`);
|
|
120
|
+
|
|
121
|
+
return { startTime: new Date().toISOString() };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Handle summary
|
|
125
|
+
export function handleSummary(data) {
|
|
126
|
+
// Helper function to safely access nested properties
|
|
127
|
+
const safeGet = (obj, path, defaultValue) => {
|
|
128
|
+
try {
|
|
129
|
+
const parts = path.split('.');
|
|
130
|
+
let result = obj;
|
|
131
|
+
|
|
132
|
+
for (const part of parts) {
|
|
133
|
+
if (result === undefined || result === null) return defaultValue;
|
|
134
|
+
result = result[part];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result === undefined || result === null ? defaultValue : result;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
return defaultValue;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// Calculate average burst success rate
|
|
144
|
+
const burstRate = safeGet(data, 'metrics.burst_success_rate.values.rate', 0) * 100;
|
|
145
|
+
|
|
146
|
+
// Create a condensed summary with key metrics
|
|
147
|
+
const summary = {
|
|
148
|
+
timestamp: new Date().toISOString(),
|
|
149
|
+
podName: __ENV.POD_NAME || 'local',
|
|
150
|
+
burstSettings: {
|
|
151
|
+
burstSize: BURST_SIZE,
|
|
152
|
+
},
|
|
153
|
+
metrics: {
|
|
154
|
+
totalRuns: safeGet(data, 'metrics.iterations.values.count', 0),
|
|
155
|
+
successfulRuns: safeGet(data, 'metrics.successful_runs.values.count', 0),
|
|
156
|
+
failedRuns: safeGet(data, 'metrics.failed_runs.values.count', 0),
|
|
157
|
+
burstSuccessRate: burstRate.toFixed(2) + '%',
|
|
158
|
+
avgDuration: safeGet(data, 'metrics.run_duration.values.avg', 0) / 1000,
|
|
159
|
+
p95Duration: safeGet(data, 'metrics.run_duration.values.p(95)', 0) / 1000,
|
|
160
|
+
errors: {
|
|
161
|
+
timeout: safeGet(data, 'metrics.timeout_errors.values.count', 0),
|
|
162
|
+
connection: safeGet(data, 'metrics.connection_errors.values.count', 0),
|
|
163
|
+
server: safeGet(data, 'metrics.server_errors.values.count', 0),
|
|
164
|
+
other: safeGet(data, 'metrics.other_errors.values.count', 0)
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
raw: {
|
|
168
|
+
http_reqs: safeGet(data, 'metrics.http_reqs.values.count', 0),
|
|
169
|
+
http_req_failed: safeGet(data, 'metrics.http_req_failed.values.rate', 0),
|
|
170
|
+
http_req_duration: {
|
|
171
|
+
avg: safeGet(data, 'metrics.http_req_duration.values.avg', 0),
|
|
172
|
+
min: safeGet(data, 'metrics.http_req_duration.values.min', 0),
|
|
173
|
+
med: safeGet(data, 'metrics.http_req_duration.values.med', 0),
|
|
174
|
+
max: safeGet(data, 'metrics.http_req_duration.values.max', 0),
|
|
175
|
+
p90: safeGet(data, 'metrics.http_req_duration.values.p(90)', 0),
|
|
176
|
+
p95: safeGet(data, 'metrics.http_req_duration.values.p(95)', 0),
|
|
177
|
+
p99: safeGet(data, 'metrics.http_req_duration.values.p(99)', 0)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Print the summary as JSON to the logs
|
|
183
|
+
console.log(`====== BURST TEST SUMMARY ======`);
|
|
184
|
+
console.log(`SUMMARY_JSON_START ${JSON.stringify(summary)} SUMMARY_JSON_END`);
|
|
185
|
+
|
|
186
|
+
// Generate output files
|
|
187
|
+
const burstStr = `burst${BURST_SIZE}`;
|
|
188
|
+
const timestamp = new Date().toISOString().replace(/:/g, '-').replace(/\..+/, '');
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
[`results_${burstStr}_${timestamp}.json`]: JSON.stringify(data, null, 2),
|
|
192
|
+
[`summary_${burstStr}_${timestamp}.json`]: JSON.stringify(summary, null, 2),
|
|
193
|
+
stdout: JSON.stringify(summary, null, 2) // Also print summary to console
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.67"
|
|
@@ -114,6 +114,46 @@ class AuthConfig(TypedDict, total=False):
|
|
|
114
114
|
"""
|
|
115
115
|
|
|
116
116
|
|
|
117
|
+
def _check_newer_version(pkg: str, timeout: float = 0.2) -> None:
|
|
118
|
+
"""Log a notice if PyPI reports a newer version."""
|
|
119
|
+
import importlib.metadata as md
|
|
120
|
+
import json
|
|
121
|
+
import urllib.request
|
|
122
|
+
|
|
123
|
+
from packaging.version import Version
|
|
124
|
+
|
|
125
|
+
thread_logger = logging.getLogger("check_version")
|
|
126
|
+
if not thread_logger.handlers:
|
|
127
|
+
handler = logging.StreamHandler()
|
|
128
|
+
handler.setFormatter(logging.Formatter("%(message)s"))
|
|
129
|
+
thread_logger.addHandler(handler)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
current = Version(md.version(pkg))
|
|
133
|
+
with urllib.request.urlopen(
|
|
134
|
+
f"https://pypi.org/pypi/{pkg}/json", timeout=timeout
|
|
135
|
+
) as resp:
|
|
136
|
+
latest_str = json.load(resp)["info"]["version"]
|
|
137
|
+
latest = Version(latest_str)
|
|
138
|
+
if latest > current:
|
|
139
|
+
thread_logger.info(
|
|
140
|
+
"🔔 A newer version of %s is available: %s → %s (pip install -U %s)",
|
|
141
|
+
pkg,
|
|
142
|
+
current,
|
|
143
|
+
latest,
|
|
144
|
+
pkg,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
except Exception:
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
except RuntimeError:
|
|
151
|
+
thread_logger.info(
|
|
152
|
+
f"Failed to check for newer version of {pkg}."
|
|
153
|
+
" To disable version checks, set LANGGRAPH_NO_VERSION_CHECK=true"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
117
157
|
def run_server(
|
|
118
158
|
host: str = "127.0.0.1",
|
|
119
159
|
port: int = 2024,
|
|
@@ -312,6 +352,12 @@ For production use, please use LangGraph Cloud.
|
|
|
312
352
|
logger.info(welcome)
|
|
313
353
|
if open_browser:
|
|
314
354
|
threading.Thread(target=_open_browser, daemon=True).start()
|
|
355
|
+
nvc = os.getenv("LANGGRAPH_NO_VERSION_CHECK")
|
|
356
|
+
if nvc is None or nvc.lower() not in ("true", "1"):
|
|
357
|
+
print("Checking for newer version...")
|
|
358
|
+
threading.Thread(
|
|
359
|
+
target=_check_newer_version, args=("langgraph-api",), daemon=True
|
|
360
|
+
).start()
|
|
315
361
|
supported_kwargs = {
|
|
316
362
|
k: v
|
|
317
363
|
for k, v in kwargs.items()
|
|
@@ -51,6 +51,8 @@ async def set_auth_ctx_for_run(
|
|
|
51
51
|
user = run_kwargs["config"]["configurable"]["langgraph_auth_user"]
|
|
52
52
|
permissions = run_kwargs["config"]["configurable"]["langgraph_auth_permissions"]
|
|
53
53
|
user = normalize_user(user)
|
|
54
|
+
# Reapply normalization to the kwargs
|
|
55
|
+
run_kwargs["config"]["configurable"]["langgraph_auth_user"] = user
|
|
54
56
|
except Exception:
|
|
55
57
|
user = SimpleUser(user_id) if user_id is not None else None
|
|
56
58
|
permissions = None
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.64"
|
|
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
|