langgraph-api 0.2.66__tar.gz → 0.2.68__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.

Files changed (104) hide show
  1. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/Makefile +1 -1
  2. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/PKG-INFO +1 -1
  3. langgraph_api-0.2.68/benchmark/.gitignore +3 -0
  4. langgraph_api-0.2.68/benchmark/Makefile +6 -0
  5. langgraph_api-0.2.68/benchmark/README.md +43 -0
  6. langgraph_api-0.2.68/benchmark/burst.js +195 -0
  7. langgraph_api-0.2.68/langgraph_api/__init__.py +1 -0
  8. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/cli.py +45 -0
  9. langgraph_api-0.2.66/langgraph_api/__init__.py +0 -1
  10. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/.gitignore +0 -0
  11. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/LICENSE +0 -0
  12. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/README.md +0 -0
  13. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/benchmark/weather.js +0 -0
  14. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/constraints.txt +0 -0
  15. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/forbidden.txt +0 -0
  16. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/healthcheck.py +0 -0
  17. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/__init__.py +0 -0
  18. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/assistants.py +0 -0
  19. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/mcp.py +0 -0
  20. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/meta.py +0 -0
  21. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/openapi.py +0 -0
  22. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/runs.py +0 -0
  23. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/store.py +0 -0
  24. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/threads.py +0 -0
  25. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/api/ui.py +0 -0
  26. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/asgi_transport.py +0 -0
  27. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/asyncio.py +0 -0
  28. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/__init__.py +0 -0
  29. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/custom.py +0 -0
  30. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/langsmith/__init__.py +0 -0
  31. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/langsmith/backend.py +0 -0
  32. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/langsmith/client.py +0 -0
  33. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/middleware.py +0 -0
  34. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/noop.py +0 -0
  35. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/auth/studio_user.py +0 -0
  36. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/command.py +0 -0
  37. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/config.py +0 -0
  38. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/cron_scheduler.py +0 -0
  39. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/errors.py +0 -0
  40. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/graph.py +0 -0
  41. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/http.py +0 -0
  42. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/.gitignore +0 -0
  43. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/.prettierrc +0 -0
  44. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/__init__.py +0 -0
  45. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/base.py +0 -0
  46. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/build.mts +0 -0
  47. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/client.http.mts +0 -0
  48. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/client.mts +0 -0
  49. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/errors.py +0 -0
  50. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/global.d.ts +0 -0
  51. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/package.json +0 -0
  52. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/remote.py +0 -0
  53. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/schema.py +0 -0
  54. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/graph.mts +0 -0
  55. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/load.hooks.mjs +0 -0
  56. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/preload.mjs +0 -0
  57. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/utils/files.mts +0 -0
  58. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/utils/importMap.mts +0 -0
  59. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/utils/pythonSchemas.mts +0 -0
  60. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/src/utils/serde.mts +0 -0
  61. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/sse.py +0 -0
  62. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/tsconfig.json +0 -0
  63. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/ui.py +0 -0
  64. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/js/yarn.lock +0 -0
  65. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/logging.py +0 -0
  66. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/metadata.py +0 -0
  67. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/middleware/__init__.py +0 -0
  68. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/middleware/http_logger.py +0 -0
  69. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/middleware/private_network.py +0 -0
  70. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/middleware/request_id.py +0 -0
  71. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/models/__init__.py +0 -0
  72. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/models/run.py +0 -0
  73. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/patch.py +0 -0
  74. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/queue_entrypoint.py +0 -0
  75. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/route.py +0 -0
  76. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/schema.py +0 -0
  77. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/serde.py +0 -0
  78. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/server.py +0 -0
  79. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/sse.py +0 -0
  80. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/state.py +0 -0
  81. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/store.py +0 -0
  82. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/stream.py +0 -0
  83. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/thread_ttl.py +0 -0
  84. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/tunneling/cloudflare.py +0 -0
  85. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/utils.py +0 -0
  86. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/validation.py +0 -0
  87. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/webhook.py +0 -0
  88. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_api/worker.py +0 -0
  89. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_license/__init__.py +0 -0
  90. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_license/validation.py +0 -0
  91. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/__init__.py +0 -0
  92. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/checkpoint.py +0 -0
  93. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/database.py +0 -0
  94. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/lifespan.py +0 -0
  95. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/metrics.py +0 -0
  96. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/ops.py +0 -0
  97. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/queue.py +0 -0
  98. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/retry.py +0 -0
  99. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/langgraph_runtime/store.py +0 -0
  100. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/logging.json +0 -0
  101. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/openapi.json +0 -0
  102. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/pyproject.toml +0 -0
  103. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/scripts/create_license.py +0 -0
  104. {langgraph_api-0.2.66 → langgraph_api-0.2.68}/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 \
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-api
3
- Version: 0.2.66
3
+ Version: 0.2.68
4
4
  Author-email: Nuno Campos <nuno@langchain.dev>, Will Fu-Hinthorn <will@langchain.dev>
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
@@ -0,0 +1,3 @@
1
+ # K6 summary and results files
2
+ results_*.json
3
+ summary_*.json
@@ -0,0 +1,6 @@
1
+ # Benchmark commands
2
+ benchmark-burst:
3
+ k6 run burst.js
4
+
5
+ benchmark-clean:
6
+ rm -f results_*.json summary_*.json
@@ -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.68"
@@ -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,11 @@ 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
+ threading.Thread(
358
+ target=_check_newer_version, args=("langgraph-api",), daemon=True
359
+ ).start()
315
360
  supported_kwargs = {
316
361
  k: v
317
362
  for k, v in kwargs.items()
@@ -1 +0,0 @@
1
- __version__ = "0.2.66"
File without changes
File without changes
File without changes