langgraph-api 0.5.4__py3-none-any.whl → 0.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langgraph_api/__init__.py +1 -1
- langgraph_api/api/__init__.py +93 -27
- langgraph_api/api/a2a.py +36 -32
- langgraph_api/api/assistants.py +114 -26
- langgraph_api/api/mcp.py +3 -3
- langgraph_api/api/meta.py +15 -2
- langgraph_api/api/openapi.py +27 -17
- langgraph_api/api/profile.py +108 -0
- langgraph_api/api/runs.py +114 -57
- langgraph_api/api/store.py +19 -2
- langgraph_api/api/threads.py +133 -10
- langgraph_api/asgi_transport.py +14 -9
- langgraph_api/auth/custom.py +23 -13
- langgraph_api/cli.py +86 -41
- langgraph_api/command.py +2 -2
- langgraph_api/config/__init__.py +532 -0
- langgraph_api/config/_parse.py +58 -0
- langgraph_api/config/schemas.py +431 -0
- langgraph_api/cron_scheduler.py +17 -1
- langgraph_api/encryption/__init__.py +15 -0
- langgraph_api/encryption/aes_json.py +158 -0
- langgraph_api/encryption/context.py +35 -0
- langgraph_api/encryption/custom.py +280 -0
- langgraph_api/encryption/middleware.py +632 -0
- langgraph_api/encryption/shared.py +63 -0
- langgraph_api/errors.py +12 -1
- langgraph_api/executor_entrypoint.py +11 -6
- langgraph_api/feature_flags.py +19 -0
- langgraph_api/graph.py +163 -64
- langgraph_api/{grpc_ops → grpc}/client.py +142 -12
- langgraph_api/{grpc_ops → grpc}/config_conversion.py +16 -10
- langgraph_api/grpc/generated/__init__.py +29 -0
- langgraph_api/grpc/generated/checkpointer_pb2.py +63 -0
- langgraph_api/grpc/generated/checkpointer_pb2.pyi +99 -0
- langgraph_api/grpc/generated/checkpointer_pb2_grpc.py +329 -0
- langgraph_api/grpc/generated/core_api_pb2.py +216 -0
- langgraph_api/{grpc_ops → grpc}/generated/core_api_pb2.pyi +292 -372
- langgraph_api/{grpc_ops → grpc}/generated/core_api_pb2_grpc.py +252 -31
- langgraph_api/grpc/generated/engine_common_pb2.py +219 -0
- langgraph_api/{grpc_ops → grpc}/generated/engine_common_pb2.pyi +178 -104
- langgraph_api/grpc/generated/enum_cancel_run_action_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_cancel_run_action_pb2.pyi +12 -0
- langgraph_api/grpc/generated/enum_cancel_run_action_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_control_signal_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_control_signal_pb2.pyi +16 -0
- langgraph_api/grpc/generated/enum_control_signal_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_durability_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_durability_pb2.pyi +16 -0
- langgraph_api/grpc/generated/enum_durability_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_multitask_strategy_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_multitask_strategy_pb2.pyi +16 -0
- langgraph_api/grpc/generated/enum_multitask_strategy_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_run_status_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_run_status_pb2.pyi +22 -0
- langgraph_api/grpc/generated/enum_run_status_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_stream_mode_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_stream_mode_pb2.pyi +28 -0
- langgraph_api/grpc/generated/enum_stream_mode_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_thread_status_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_thread_status_pb2.pyi +16 -0
- langgraph_api/grpc/generated/enum_thread_status_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/enum_thread_stream_mode_pb2.py +37 -0
- langgraph_api/grpc/generated/enum_thread_stream_mode_pb2.pyi +16 -0
- langgraph_api/grpc/generated/enum_thread_stream_mode_pb2_grpc.py +24 -0
- langgraph_api/grpc/generated/errors_pb2.py +39 -0
- langgraph_api/grpc/generated/errors_pb2.pyi +21 -0
- langgraph_api/grpc/generated/errors_pb2_grpc.py +24 -0
- langgraph_api/grpc/ops/__init__.py +370 -0
- langgraph_api/grpc/ops/assistants.py +424 -0
- langgraph_api/grpc/ops/runs.py +792 -0
- langgraph_api/grpc/ops/threads.py +1013 -0
- langgraph_api/http.py +16 -5
- langgraph_api/js/client.mts +1 -4
- langgraph_api/js/package.json +28 -27
- langgraph_api/js/remote.py +39 -17
- langgraph_api/js/sse.py +2 -2
- langgraph_api/js/ui.py +1 -1
- langgraph_api/js/yarn.lock +1139 -869
- langgraph_api/metadata.py +29 -3
- langgraph_api/middleware/http_logger.py +1 -1
- langgraph_api/middleware/private_network.py +7 -7
- langgraph_api/models/run.py +44 -26
- langgraph_api/otel_context.py +205 -0
- langgraph_api/patch.py +2 -2
- langgraph_api/queue_entrypoint.py +34 -35
- langgraph_api/route.py +33 -1
- langgraph_api/schema.py +84 -9
- langgraph_api/self_hosted_logs.py +2 -2
- langgraph_api/self_hosted_metrics.py +73 -3
- langgraph_api/serde.py +16 -4
- langgraph_api/server.py +33 -31
- langgraph_api/state.py +3 -2
- langgraph_api/store.py +25 -16
- langgraph_api/stream.py +20 -16
- langgraph_api/thread_ttl.py +28 -13
- langgraph_api/timing/__init__.py +25 -0
- langgraph_api/timing/profiler.py +200 -0
- langgraph_api/timing/timer.py +318 -0
- langgraph_api/utils/__init__.py +53 -8
- langgraph_api/utils/config.py +2 -1
- langgraph_api/utils/future.py +10 -6
- langgraph_api/utils/uuids.py +29 -62
- langgraph_api/validation.py +6 -0
- langgraph_api/webhook.py +120 -6
- langgraph_api/worker.py +54 -24
- {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/METADATA +8 -6
- langgraph_api-0.7.3.dist-info/RECORD +168 -0
- {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/WHEEL +1 -1
- langgraph_runtime/__init__.py +1 -0
- langgraph_runtime/routes.py +11 -0
- logging.json +1 -3
- openapi.json +635 -537
- langgraph_api/config.py +0 -523
- langgraph_api/grpc_ops/generated/__init__.py +0 -5
- langgraph_api/grpc_ops/generated/core_api_pb2.py +0 -275
- langgraph_api/grpc_ops/generated/engine_common_pb2.py +0 -194
- langgraph_api/grpc_ops/ops.py +0 -1045
- langgraph_api-0.5.4.dist-info/RECORD +0 -121
- /langgraph_api/{grpc_ops → grpc}/__init__.py +0 -0
- /langgraph_api/{grpc_ops → grpc}/generated/engine_common_pb2_grpc.py +0 -0
- {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/entry_points.txt +0 -0
- {langgraph_api-0.5.4.dist-info → langgraph_api-0.7.3.dist-info}/licenses/LICENSE +0 -0
langgraph_api/config.py
DELETED
|
@@ -1,523 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from collections.abc import Callable
|
|
3
|
-
from os import environ, getenv
|
|
4
|
-
from typing import Literal, TypeVar, cast
|
|
5
|
-
|
|
6
|
-
import orjson
|
|
7
|
-
from pydantic import TypeAdapter
|
|
8
|
-
from starlette.config import Config, undefined
|
|
9
|
-
from starlette.datastructures import CommaSeparatedStrings
|
|
10
|
-
from typing_extensions import TypedDict
|
|
11
|
-
|
|
12
|
-
from langgraph_api import traceblock
|
|
13
|
-
|
|
14
|
-
# types
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class CorsConfig(TypedDict, total=False):
|
|
18
|
-
allow_origins: list[str]
|
|
19
|
-
allow_methods: list[str]
|
|
20
|
-
allow_headers: list[str]
|
|
21
|
-
allow_credentials: bool
|
|
22
|
-
allow_origin_regex: str
|
|
23
|
-
expose_headers: list[str]
|
|
24
|
-
max_age: int
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class ConfigurableHeaders(TypedDict, total=False):
|
|
28
|
-
includes: list[str] | None
|
|
29
|
-
excludes: list[str] | None
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
MiddlewareOrders = Literal["auth_first", "middleware_first"]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class HttpConfig(TypedDict, total=False):
|
|
36
|
-
app: str
|
|
37
|
-
"""Import path for a custom Starlette/FastAPI app to mount"""
|
|
38
|
-
disable_assistants: bool
|
|
39
|
-
"""Disable /assistants routes"""
|
|
40
|
-
disable_threads: bool
|
|
41
|
-
"""Disable /threads routes"""
|
|
42
|
-
disable_runs: bool
|
|
43
|
-
"""Disable /runs routes"""
|
|
44
|
-
disable_store: bool
|
|
45
|
-
"""Disable /store routes"""
|
|
46
|
-
disable_meta: bool
|
|
47
|
-
"""Disable /ok, /info, /metrics, and /docs routes"""
|
|
48
|
-
disable_webhooks: bool
|
|
49
|
-
"""Disable webhooks calls on run completion in all routes"""
|
|
50
|
-
cors: CorsConfig | None
|
|
51
|
-
"""CORS configuration"""
|
|
52
|
-
disable_ui: bool
|
|
53
|
-
"""Disable /ui routes"""
|
|
54
|
-
disable_mcp: bool
|
|
55
|
-
"""Disable /mcp routes"""
|
|
56
|
-
mount_prefix: str
|
|
57
|
-
"""Prefix for mounted routes. E.g., "/my-deployment/api"."""
|
|
58
|
-
configurable_headers: ConfigurableHeaders | None
|
|
59
|
-
logging_headers: ConfigurableHeaders | None
|
|
60
|
-
enable_custom_route_auth: bool
|
|
61
|
-
middleware_order: MiddlewareOrders | None
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class ThreadTTLConfig(TypedDict, total=False):
|
|
65
|
-
strategy: Literal["delete"]
|
|
66
|
-
default_ttl: float | None
|
|
67
|
-
sweep_interval_minutes: int | None
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
class IndexConfig(TypedDict, total=False):
|
|
71
|
-
"""Configuration for indexing documents for semantic search in the store."""
|
|
72
|
-
|
|
73
|
-
dims: int
|
|
74
|
-
"""Number of dimensions in the embedding vectors.
|
|
75
|
-
|
|
76
|
-
Common embedding models have the following dimensions:
|
|
77
|
-
- OpenAI text-embedding-3-large: 256, 1024, or 3072
|
|
78
|
-
- OpenAI text-embedding-3-small: 512 or 1536
|
|
79
|
-
- OpenAI text-embedding-ada-002: 1536
|
|
80
|
-
- Cohere embed-english-v3.0: 1024
|
|
81
|
-
- Cohere embed-english-light-v3.0: 384
|
|
82
|
-
- Cohere embed-multilingual-v3.0: 1024
|
|
83
|
-
- Cohere embed-multilingual-light-v3.0: 384
|
|
84
|
-
"""
|
|
85
|
-
|
|
86
|
-
embed: str
|
|
87
|
-
"""Either a path to an embedding model (./path/to/file.py:embedding_model)
|
|
88
|
-
or a name of an embedding model (openai:text-embedding-3-small)
|
|
89
|
-
|
|
90
|
-
Note: LangChain is required to use the model format specification.
|
|
91
|
-
"""
|
|
92
|
-
|
|
93
|
-
fields: list[str] | None
|
|
94
|
-
"""Fields to extract text from for embedding generation.
|
|
95
|
-
|
|
96
|
-
Defaults to the root ["$"], which embeds the json object as a whole.
|
|
97
|
-
"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
class TTLConfig(TypedDict, total=False):
|
|
101
|
-
"""Configuration for TTL (time-to-live) behavior in the store."""
|
|
102
|
-
|
|
103
|
-
refresh_on_read: bool
|
|
104
|
-
"""Default behavior for refreshing TTLs on read operations (GET and SEARCH).
|
|
105
|
-
|
|
106
|
-
If True, TTLs will be refreshed on read operations (get/search) by default.
|
|
107
|
-
This can be overridden per-operation by explicitly setting refresh_ttl.
|
|
108
|
-
Defaults to True if not configured.
|
|
109
|
-
"""
|
|
110
|
-
default_ttl: float | None
|
|
111
|
-
"""Default TTL (time-to-live) in minutes for new items.
|
|
112
|
-
|
|
113
|
-
If provided, new items will expire after this many minutes after their last access.
|
|
114
|
-
The expiration timer refreshes on both read and write operations.
|
|
115
|
-
Defaults to None (no expiration).
|
|
116
|
-
"""
|
|
117
|
-
sweep_interval_minutes: int | None
|
|
118
|
-
"""Interval in minutes between TTL sweep operations.
|
|
119
|
-
|
|
120
|
-
If provided, the store will periodically delete expired items based on TTL.
|
|
121
|
-
Defaults to None (no sweeping).
|
|
122
|
-
"""
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class StoreConfig(TypedDict, total=False):
|
|
126
|
-
path: str
|
|
127
|
-
index: IndexConfig
|
|
128
|
-
ttl: TTLConfig
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
class SerdeConfig(TypedDict, total=False):
|
|
132
|
-
"""Configuration for the built-in serde, which handles checkpointing of state.
|
|
133
|
-
|
|
134
|
-
If omitted, no serde is set up (the object store will still be present, however)."""
|
|
135
|
-
|
|
136
|
-
allowed_json_modules: list[list[str]] | Literal[True] | None
|
|
137
|
-
"""Optional. List of allowed python modules to de-serialize custom objects from.
|
|
138
|
-
|
|
139
|
-
If provided, only the specified modules will be allowed to be deserialized.
|
|
140
|
-
If omitted, no modules are allowed, and the object returned will simply be a json object OR
|
|
141
|
-
a deserialized langchain object.
|
|
142
|
-
|
|
143
|
-
Example:
|
|
144
|
-
{...
|
|
145
|
-
"serde": {
|
|
146
|
-
"allowed_json_modules": [
|
|
147
|
-
["my_agent", "my_file", "SomeType"],
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
If you set this to True, any module will be allowed to be deserialized.
|
|
153
|
-
|
|
154
|
-
Example:
|
|
155
|
-
{...
|
|
156
|
-
"serde": {
|
|
157
|
-
"allowed_json_modules": true
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
"""
|
|
162
|
-
pickle_fallback: bool
|
|
163
|
-
"""Optional. Whether to allow pickling as a fallback for deserialization.
|
|
164
|
-
|
|
165
|
-
If True, pickling will be allowed as a fallback for deserialization.
|
|
166
|
-
If False, pickling will not be allowed as a fallback for deserialization.
|
|
167
|
-
Defaults to True if not configured."""
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class CheckpointerConfig(TypedDict, total=False):
|
|
171
|
-
"""Configuration for the built-in checkpointer, which handles checkpointing of state.
|
|
172
|
-
|
|
173
|
-
If omitted, no checkpointer is set up (the object store will still be present, however).
|
|
174
|
-
"""
|
|
175
|
-
|
|
176
|
-
ttl: ThreadTTLConfig | None
|
|
177
|
-
"""Optional. Defines the TTL (time-to-live) behavior configuration.
|
|
178
|
-
|
|
179
|
-
If provided, the checkpointer will apply TTL settings according to the configuration.
|
|
180
|
-
If omitted, no TTL behavior is configured.
|
|
181
|
-
"""
|
|
182
|
-
serde: SerdeConfig | None
|
|
183
|
-
"""Optional. Defines the configuration for how checkpoints are serialized."""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
class SecurityConfig(TypedDict, total=False):
|
|
187
|
-
securitySchemes: dict
|
|
188
|
-
security: list
|
|
189
|
-
# path => {method => security}
|
|
190
|
-
paths: dict[str, dict[str, list]]
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
class CacheConfig(TypedDict, total=False):
|
|
194
|
-
cache_keys: list[str]
|
|
195
|
-
ttl_seconds: int
|
|
196
|
-
max_size: int
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
class AuthConfig(TypedDict, total=False):
|
|
200
|
-
path: str
|
|
201
|
-
"""Path to the authentication function in a Python file."""
|
|
202
|
-
disable_studio_auth: bool
|
|
203
|
-
"""Whether to disable auth when connecting from the LangSmith Studio."""
|
|
204
|
-
openapi: SecurityConfig
|
|
205
|
-
"""The schema to use for updating the openapi spec.
|
|
206
|
-
|
|
207
|
-
Example:
|
|
208
|
-
{
|
|
209
|
-
"securitySchemes": {
|
|
210
|
-
"OAuth2": {
|
|
211
|
-
"type": "oauth2",
|
|
212
|
-
"flows": {
|
|
213
|
-
"password": {
|
|
214
|
-
"tokenUrl": "/token",
|
|
215
|
-
"scopes": {
|
|
216
|
-
"me": "Read information about the current user",
|
|
217
|
-
"items": "Access to create and manage items"
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
"security": [
|
|
224
|
-
{"OAuth2": ["me"]} # Default security requirement for all endpoints
|
|
225
|
-
]
|
|
226
|
-
}
|
|
227
|
-
"""
|
|
228
|
-
cache: CacheConfig | None
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
# env
|
|
232
|
-
|
|
233
|
-
env = Config()
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
TD = TypeVar("TD")
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def _parse_json(json: str | None, schema: TypeAdapter | None = None) -> dict | None:
|
|
240
|
-
if not json:
|
|
241
|
-
return None
|
|
242
|
-
parsed = schema.validate_json(json) if schema else orjson.loads(json)
|
|
243
|
-
return parsed or None
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def _parse_schema(schema: type[TD]) -> Callable[[str | None], TD | None]:
|
|
247
|
-
def composed(json: str | None) -> TD | None:
|
|
248
|
-
return cast(TD | None, _parse_json(json, schema=TypeAdapter(schema)))
|
|
249
|
-
|
|
250
|
-
composed.__name__ = schema.__name__ # This just gives a nicer error message if the user provides an incompatible value
|
|
251
|
-
return composed
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
STATS_INTERVAL_SECS = env("STATS_INTERVAL_SECS", cast=int, default=60)
|
|
255
|
-
|
|
256
|
-
# storage
|
|
257
|
-
|
|
258
|
-
DATABASE_URI = env("DATABASE_URI", cast=str, default=getenv("POSTGRES_URI", undefined))
|
|
259
|
-
MIGRATIONS_PATH = env("MIGRATIONS_PATH", cast=str, default="/storage/migrations")
|
|
260
|
-
POSTGRES_POOL_MAX_SIZE = env("LANGGRAPH_POSTGRES_POOL_MAX_SIZE", cast=int, default=150)
|
|
261
|
-
RESUMABLE_STREAM_TTL_SECONDS = env(
|
|
262
|
-
"RESUMABLE_STREAM_TTL_SECONDS",
|
|
263
|
-
cast=int,
|
|
264
|
-
default=120, # 2 minutes
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def _get_encryption_key(key_str: str | None):
|
|
269
|
-
if not key_str:
|
|
270
|
-
return None
|
|
271
|
-
key = key_str.encode(encoding="utf-8")
|
|
272
|
-
if len(key) not in (16, 24, 32):
|
|
273
|
-
raise ValueError("LANGGRAPH_AES_KEY must be 16, 24, or 32 bytes long.")
|
|
274
|
-
return key
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
LANGGRAPH_AES_KEY = env("LANGGRAPH_AES_KEY", default=None, cast=_get_encryption_key)
|
|
278
|
-
|
|
279
|
-
# redis
|
|
280
|
-
REDIS_URI = env("REDIS_URI", cast=str)
|
|
281
|
-
REDIS_CLUSTER = env("REDIS_CLUSTER", cast=bool, default=False)
|
|
282
|
-
REDIS_MAX_CONNECTIONS = env("REDIS_MAX_CONNECTIONS", cast=int, default=2000)
|
|
283
|
-
REDIS_CONNECT_TIMEOUT = env("REDIS_CONNECT_TIMEOUT", cast=float, default=10.0)
|
|
284
|
-
REDIS_KEY_PREFIX = env("REDIS_KEY_PREFIX", cast=str, default="")
|
|
285
|
-
RUN_STATS_CACHE_SECONDS = env("RUN_STATS_CACHE_SECONDS", cast=int, default=60)
|
|
286
|
-
|
|
287
|
-
# server
|
|
288
|
-
ALLOW_PRIVATE_NETWORK = env("ALLOW_PRIVATE_NETWORK", cast=bool, default=False)
|
|
289
|
-
"""Only enable for langgraph dev when server is running on loopback address.
|
|
290
|
-
|
|
291
|
-
See https://developer.chrome.com/blog/private-network-access-update-2024-03
|
|
292
|
-
"""
|
|
293
|
-
|
|
294
|
-
# gRPC client pool size for persistence server.
|
|
295
|
-
GRPC_CLIENT_POOL_SIZE = env("GRPC_CLIENT_POOL_SIZE", cast=int, default=5)
|
|
296
|
-
|
|
297
|
-
# Minimum payload size to use the dedicated thread pool for JSON parsing.
|
|
298
|
-
# (Otherwise, the payload is parsed directly in the event loop.)
|
|
299
|
-
JSON_THREAD_POOL_MINIMUM_SIZE_BYTES = 100 * 1024 # 100 KB
|
|
300
|
-
|
|
301
|
-
HTTP_CONFIG = env("LANGGRAPH_HTTP", cast=_parse_schema(HttpConfig), default=None)
|
|
302
|
-
STORE_CONFIG = env("LANGGRAPH_STORE", cast=_parse_schema(StoreConfig), default=None)
|
|
303
|
-
|
|
304
|
-
MOUNT_PREFIX: str | None = env("MOUNT_PREFIX", cast=str, default=None) or (
|
|
305
|
-
HTTP_CONFIG.get("mount_prefix") if HTTP_CONFIG else None
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
CORS_ALLOW_ORIGINS = env("CORS_ALLOW_ORIGINS", cast=CommaSeparatedStrings, default="*")
|
|
309
|
-
CORS_CONFIG = env("CORS_CONFIG", cast=_parse_schema(CorsConfig), default=None) or (
|
|
310
|
-
HTTP_CONFIG.get("cors") if HTTP_CONFIG else None
|
|
311
|
-
)
|
|
312
|
-
"""
|
|
313
|
-
{
|
|
314
|
-
"type": "object",
|
|
315
|
-
"properties": {
|
|
316
|
-
"allow_origins": {
|
|
317
|
-
"type": "array",
|
|
318
|
-
"items": {"type": "string"},
|
|
319
|
-
"default": []
|
|
320
|
-
},
|
|
321
|
-
"allow_methods": {
|
|
322
|
-
"type": "array",
|
|
323
|
-
"items": {"type": "string"},
|
|
324
|
-
"default": ["GET"]
|
|
325
|
-
},
|
|
326
|
-
"allow_headers": {
|
|
327
|
-
"type": "array",
|
|
328
|
-
"items": {"type": "string"},
|
|
329
|
-
"default": []
|
|
330
|
-
},
|
|
331
|
-
"allow_credentials": {
|
|
332
|
-
"type": "boolean",
|
|
333
|
-
"default": false
|
|
334
|
-
},
|
|
335
|
-
"allow_origin_regex": {
|
|
336
|
-
"type": ["string", "null"],
|
|
337
|
-
"default": null
|
|
338
|
-
},
|
|
339
|
-
"expose_headers": {
|
|
340
|
-
"type": "array",
|
|
341
|
-
"items": {"type": "string"},
|
|
342
|
-
"default": []
|
|
343
|
-
},
|
|
344
|
-
"max_age": {
|
|
345
|
-
"type": "integer",
|
|
346
|
-
"default": 600
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
"""
|
|
351
|
-
if (
|
|
352
|
-
CORS_CONFIG is not None
|
|
353
|
-
and CORS_ALLOW_ORIGINS != "*"
|
|
354
|
-
and CORS_CONFIG.get("allow_origins") is None
|
|
355
|
-
):
|
|
356
|
-
CORS_CONFIG["allow_origins"] = CORS_ALLOW_ORIGINS
|
|
357
|
-
|
|
358
|
-
# queue
|
|
359
|
-
|
|
360
|
-
BG_JOB_HEARTBEAT = 120 # seconds
|
|
361
|
-
BG_JOB_INTERVAL = 30 # seconds
|
|
362
|
-
BG_JOB_MAX_RETRIES = 3
|
|
363
|
-
BG_JOB_ISOLATED_LOOPS = env("BG_JOB_ISOLATED_LOOPS", cast=bool, default=False)
|
|
364
|
-
BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS = env(
|
|
365
|
-
"BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS",
|
|
366
|
-
cast=int,
|
|
367
|
-
default=180, # 3 minutes
|
|
368
|
-
)
|
|
369
|
-
MAX_STREAM_CHUNK_SIZE_BYTES = env(
|
|
370
|
-
"MAX_STREAM_CHUNK_SIZE_BYTES", cast=int, default=1024 * 1024 * 128
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
def _parse_thread_ttl(value: str | None) -> ThreadTTLConfig | None:
|
|
375
|
-
if not value:
|
|
376
|
-
return None
|
|
377
|
-
if str(value).strip().startswith("{"):
|
|
378
|
-
return _parse_json(value.strip())
|
|
379
|
-
return {
|
|
380
|
-
"strategy": "delete",
|
|
381
|
-
# We permit float values mainly for testing purposes
|
|
382
|
-
"default_ttl": float(value),
|
|
383
|
-
"sweep_interval_minutes": 5.1,
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
CHECKPOINTER_CONFIG = env(
|
|
388
|
-
"LANGGRAPH_CHECKPOINTER", cast=_parse_schema(CheckpointerConfig), default=None
|
|
389
|
-
)
|
|
390
|
-
SERDE: SerdeConfig | None = (
|
|
391
|
-
CHECKPOINTER_CONFIG["serde"]
|
|
392
|
-
if CHECKPOINTER_CONFIG and "serde" in CHECKPOINTER_CONFIG
|
|
393
|
-
else None
|
|
394
|
-
)
|
|
395
|
-
THREAD_TTL: ThreadTTLConfig | None = env(
|
|
396
|
-
"LANGGRAPH_THREAD_TTL", cast=_parse_thread_ttl, default=None
|
|
397
|
-
)
|
|
398
|
-
if THREAD_TTL is None and CHECKPOINTER_CONFIG is not None:
|
|
399
|
-
THREAD_TTL = CHECKPOINTER_CONFIG.get("ttl")
|
|
400
|
-
|
|
401
|
-
N_JOBS_PER_WORKER = env("N_JOBS_PER_WORKER", cast=int, default=10)
|
|
402
|
-
BG_JOB_TIMEOUT_SECS = env("BG_JOB_TIMEOUT_SECS", cast=float, default=3600)
|
|
403
|
-
|
|
404
|
-
FF_CRONS_ENABLED = env("FF_CRONS_ENABLED", cast=bool, default=True)
|
|
405
|
-
FF_LOG_DROPPED_EVENTS = env("FF_LOG_DROPPED_EVENTS", cast=bool, default=False)
|
|
406
|
-
FF_LOG_QUERY_AND_PARAMS = env("FF_LOG_QUERY_AND_PARAMS", cast=bool, default=False)
|
|
407
|
-
|
|
408
|
-
# auth
|
|
409
|
-
|
|
410
|
-
LANGGRAPH_AUTH_TYPE = env("LANGGRAPH_AUTH_TYPE", cast=str, default="noop")
|
|
411
|
-
LANGGRAPH_POSTGRES_EXTENSIONS: Literal["standard", "lite"] = env(
|
|
412
|
-
"LANGGRAPH_POSTGRES_EXTENSIONS", cast=str, default="standard"
|
|
413
|
-
)
|
|
414
|
-
if LANGGRAPH_POSTGRES_EXTENSIONS not in ("standard", "lite"):
|
|
415
|
-
raise ValueError(
|
|
416
|
-
f"Unknown LANGGRAPH_POSTGRES_EXTENSIONS value: {LANGGRAPH_POSTGRES_EXTENSIONS}"
|
|
417
|
-
)
|
|
418
|
-
LANGGRAPH_AUTH = env("LANGGRAPH_AUTH", cast=_parse_schema(AuthConfig), default=None)
|
|
419
|
-
LANGSMITH_TENANT_ID = env("LANGSMITH_TENANT_ID", cast=str, default=None)
|
|
420
|
-
LANGSMITH_AUTH_VERIFY_TENANT_ID = env(
|
|
421
|
-
"LANGSMITH_AUTH_VERIFY_TENANT_ID",
|
|
422
|
-
cast=bool,
|
|
423
|
-
default=LANGSMITH_TENANT_ID is not None,
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
if LANGGRAPH_AUTH_TYPE == "langsmith":
|
|
427
|
-
LANGSMITH_AUTH_ENDPOINT = env("LANGSMITH_AUTH_ENDPOINT", cast=str)
|
|
428
|
-
LANGSMITH_TENANT_ID = env("LANGSMITH_TENANT_ID", cast=str)
|
|
429
|
-
LANGSMITH_AUTH_VERIFY_TENANT_ID = env(
|
|
430
|
-
"LANGSMITH_AUTH_VERIFY_TENANT_ID", cast=bool, default=True
|
|
431
|
-
)
|
|
432
|
-
|
|
433
|
-
else:
|
|
434
|
-
LANGSMITH_AUTH_ENDPOINT = env(
|
|
435
|
-
"LANGSMITH_AUTH_ENDPOINT",
|
|
436
|
-
cast=str,
|
|
437
|
-
default=getenv(
|
|
438
|
-
"LANGCHAIN_ENDPOINT",
|
|
439
|
-
getenv("LANGSMITH_ENDPOINT", "https://api.smith.langchain.com"),
|
|
440
|
-
),
|
|
441
|
-
)
|
|
442
|
-
|
|
443
|
-
# license
|
|
444
|
-
|
|
445
|
-
LANGGRAPH_CLOUD_LICENSE_KEY = env("LANGGRAPH_CLOUD_LICENSE_KEY", cast=str, default="")
|
|
446
|
-
LANGSMITH_API_KEY = env(
|
|
447
|
-
"LANGSMITH_API_KEY", cast=str, default=getenv("LANGCHAIN_API_KEY", "")
|
|
448
|
-
)
|
|
449
|
-
# LANGSMITH_CONTROL_PLANE_API_KEY is used for license verification and
|
|
450
|
-
# submitting usage metadata to LangSmith SaaS.
|
|
451
|
-
#
|
|
452
|
-
# Use case: A self-hosted deployment can configure LANGSMITH_API_KEY
|
|
453
|
-
# from a self-hosted LangSmith instance (i.e. trace to self-hosted
|
|
454
|
-
# LangSmith) and configure LANGSMITH_CONTROL_PLANE_API_KEY from LangSmith SaaS
|
|
455
|
-
# to facilitate license key verification and metadata submission.
|
|
456
|
-
LANGSMITH_CONTROL_PLANE_API_KEY = env(
|
|
457
|
-
"LANGSMITH_CONTROL_PLANE_API_KEY", cast=str, default=LANGSMITH_API_KEY
|
|
458
|
-
)
|
|
459
|
-
|
|
460
|
-
# if langsmith api key is set, enable tracing unless explicitly disabled
|
|
461
|
-
|
|
462
|
-
if (
|
|
463
|
-
LANGSMITH_CONTROL_PLANE_API_KEY
|
|
464
|
-
and not getenv("LANGCHAIN_TRACING_V2")
|
|
465
|
-
and not getenv("LANGCHAIN_TRACING")
|
|
466
|
-
and not getenv("LANGSMITH_TRACING_V2")
|
|
467
|
-
and not getenv("LANGSMITH_TRACING")
|
|
468
|
-
):
|
|
469
|
-
environ["LANGCHAIN_TRACING_V2"] = "true"
|
|
470
|
-
|
|
471
|
-
TRACING = (
|
|
472
|
-
env("LANGCHAIN_TRACING_V2", cast=bool, default=None)
|
|
473
|
-
or env("LANGCHAIN_TRACING", cast=bool, default=None)
|
|
474
|
-
or env("LANGSMITH_TRACING_V2", cast=bool, default=None)
|
|
475
|
-
or env("LANGSMITH_TRACING", cast=bool, default=None)
|
|
476
|
-
)
|
|
477
|
-
|
|
478
|
-
# if variant is "licensed", update to "local" if using LANGSMITH_CONTROL_PLANE_API_KEY instead
|
|
479
|
-
|
|
480
|
-
if (
|
|
481
|
-
getenv("LANGSMITH_LANGGRAPH_API_VARIANT") == "licensed"
|
|
482
|
-
and LANGSMITH_CONTROL_PLANE_API_KEY
|
|
483
|
-
):
|
|
484
|
-
environ["LANGSMITH_LANGGRAPH_API_VARIANT"] = "local"
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
# Metrics.
|
|
488
|
-
USES_INDEXING = (
|
|
489
|
-
STORE_CONFIG
|
|
490
|
-
and STORE_CONFIG.get("index")
|
|
491
|
-
and STORE_CONFIG.get("index").get("embed")
|
|
492
|
-
)
|
|
493
|
-
USES_CUSTOM_APP = HTTP_CONFIG and HTTP_CONFIG.get("app")
|
|
494
|
-
USES_CUSTOM_AUTH = bool(LANGGRAPH_AUTH)
|
|
495
|
-
USES_THREAD_TTL = bool(THREAD_TTL)
|
|
496
|
-
USES_STORE_TTL = bool(STORE_CONFIG and STORE_CONFIG.get("ttl"))
|
|
497
|
-
|
|
498
|
-
API_VARIANT = env("LANGSMITH_LANGGRAPH_API_VARIANT", cast=str, default="")
|
|
499
|
-
|
|
500
|
-
# UI
|
|
501
|
-
UI_USE_BUNDLER = env("LANGGRAPH_UI_BUNDLER", cast=bool, default=False)
|
|
502
|
-
|
|
503
|
-
LANGGRAPH_METRICS_ENABLED = env("LANGGRAPH_METRICS_ENABLED", cast=bool, default=False)
|
|
504
|
-
LANGGRAPH_METRICS_ENDPOINT = env("LANGGRAPH_METRICS_ENDPOINT", cast=str, default=None)
|
|
505
|
-
LANGGRAPH_METRICS_EXPORT_INTERVAL_MS = env(
|
|
506
|
-
"LANGGRAPH_METRICS_EXPORT_INTERVAL_MS", cast=int, default=60000
|
|
507
|
-
)
|
|
508
|
-
LANGGRAPH_LOGS_ENDPOINT = env("LANGGRAPH_LOGS_ENDPOINT", cast=str, default=None)
|
|
509
|
-
LANGGRAPH_LOGS_ENABLED = env("LANGGRAPH_LOGS_ENABLED", cast=bool, default=False)
|
|
510
|
-
|
|
511
|
-
SELF_HOSTED_OBSERVABILITY_SERVICE_NAME = "LGP_Self_Hosted"
|
|
512
|
-
|
|
513
|
-
IS_QUEUE_ENTRYPOINT = False
|
|
514
|
-
IS_EXECUTOR_ENTRYPOINT = False
|
|
515
|
-
ref_sha = None
|
|
516
|
-
if not os.getenv("LANGCHAIN_REVISION_ID") and (
|
|
517
|
-
ref_sha := os.getenv("LANGSMITH_LANGGRAPH_GIT_REF_SHA")
|
|
518
|
-
):
|
|
519
|
-
# This is respected by the langsmith SDK env inference
|
|
520
|
-
# https://github.com/langchain-ai/langsmith-sdk/blob/1b93e4c13b8369d92db891ae3babc3e2254f0e56/python/langsmith/env/_runtime_env.py#L190
|
|
521
|
-
os.environ["LANGCHAIN_REVISION_ID"] = ref_sha
|
|
522
|
-
|
|
523
|
-
traceblock.patch_requests()
|