coco-framework 0.1.0__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.
- coco/__init__.py +3 -0
- coco/agents/__init__.py +9 -0
- coco/agents/_subagent_transformer.py +307 -0
- coco/agents/factory.py +2164 -0
- coco/agents/middleware/__init__.py +100 -0
- coco/agents/middleware/_execution.py +385 -0
- coco/agents/middleware/_redaction.py +454 -0
- coco/agents/middleware/_retry.py +134 -0
- coco/agents/middleware/_trace_policy.py +61 -0
- coco/agents/middleware/context_editing.py +306 -0
- coco/agents/middleware/file_search.py +433 -0
- coco/agents/middleware/human_in_the_loop.py +680 -0
- coco/agents/middleware/internal_call_transformer.py +108 -0
- coco/agents/middleware/model_call_limit.py +267 -0
- coco/agents/middleware/model_fallback.py +417 -0
- coco/agents/middleware/model_retry.py +327 -0
- coco/agents/middleware/pii.py +878 -0
- coco/agents/middleware/provider_tool_search.py +307 -0
- coco/agents/middleware/shell_tool.py +949 -0
- coco/agents/middleware/summarization.py +910 -0
- coco/agents/middleware/todo.py +357 -0
- coco/agents/middleware/tool_call_limit.py +495 -0
- coco/agents/middleware/tool_emulator.py +251 -0
- coco/agents/middleware/tool_error.py +209 -0
- coco/agents/middleware/tool_retry.py +421 -0
- coco/agents/middleware/tool_selection.py +515 -0
- coco/agents/middleware/types.py +2201 -0
- coco/agents/structured_output.py +472 -0
- coco/chat_models/__init__.py +7 -0
- coco/chat_models/base.py +1082 -0
- coco/embeddings/__init__.py +18 -0
- coco/embeddings/base.py +279 -0
- coco/mcp/__init__.py +36 -0
- coco/mcp/adapter.py +245 -0
- coco/mcp/elicitation.py +394 -0
- coco/mcp/tools.py +307 -0
- coco/messages/__init__.py +73 -0
- coco/py.typed +0 -0
- coco/rate_limiters/__init__.py +13 -0
- coco/tools/__init__.py +22 -0
- coco/tools/tool_node.py +20 -0
- coco_anthropic/__init__.py +15 -0
- coco_anthropic/_client_utils.py +81 -0
- coco_anthropic/_compat.py +228 -0
- coco_anthropic/_sdk_compat.py +124 -0
- coco_anthropic/_version.py +3 -0
- coco_anthropic/chat_models.py +3349 -0
- coco_anthropic/data/__init__.py +1 -0
- coco_anthropic/data/_profiles.py +491 -0
- coco_anthropic/data/profile_augmentations.toml +69 -0
- coco_anthropic/experimental.py +140 -0
- coco_anthropic/llms.py +428 -0
- coco_anthropic/middleware/__init__.py +25 -0
- coco_anthropic/middleware/anthropic_tools.py +1197 -0
- coco_anthropic/middleware/bash.py +84 -0
- coco_anthropic/middleware/file_search.py +360 -0
- coco_anthropic/middleware/prompt_caching.py +276 -0
- coco_anthropic/output_parsers.py +93 -0
- coco_anthropic/py.typed +0 -0
- coco_core/__init__.py +20 -0
- coco_core/_api/__init__.py +87 -0
- coco_core/_api/beta_decorator.py +266 -0
- coco_core/_api/deprecation.py +637 -0
- coco_core/_api/internal.py +23 -0
- coco_core/_api/path.py +50 -0
- coco_core/_import_utils.py +41 -0
- coco_core/_protocol.py +625 -0
- coco_core/_security/__init__.py +36 -0
- coco_core/_security/_exceptions.py +9 -0
- coco_core/_security/_policy.py +313 -0
- coco_core/_security/_ssrf_protection.py +155 -0
- coco_core/_security/_transport.py +254 -0
- coco_core/agents.py +258 -0
- coco_core/caches.py +272 -0
- coco_core/callbacks/__init__.py +132 -0
- coco_core/callbacks/base.py +1229 -0
- coco_core/callbacks/file.py +266 -0
- coco_core/callbacks/manager.py +2826 -0
- coco_core/callbacks/stdout.py +123 -0
- coco_core/callbacks/streaming_stdout.py +154 -0
- coco_core/callbacks/usage.py +124 -0
- coco_core/chat_history.py +267 -0
- coco_core/chat_loaders.py +26 -0
- coco_core/chat_sessions.py +19 -0
- coco_core/cross_encoders.py +18 -0
- coco_core/document_loaders/__init__.py +36 -0
- coco_core/document_loaders/base.py +155 -0
- coco_core/document_loaders/blob_loaders.py +38 -0
- coco_core/documents/__init__.py +55 -0
- coco_core/documents/base.py +347 -0
- coco_core/documents/compressor.py +74 -0
- coco_core/documents/transformers.py +79 -0
- coco_core/embeddings/__init__.py +31 -0
- coco_core/embeddings/embeddings.py +78 -0
- coco_core/embeddings/fake.py +129 -0
- coco_core/env.py +22 -0
- coco_core/example_selectors/__init__.py +47 -0
- coco_core/example_selectors/base.py +60 -0
- coco_core/example_selectors/length_based.py +131 -0
- coco_core/example_selectors/semantic_similarity.py +366 -0
- coco_core/exceptions.py +166 -0
- coco_core/globals.py +72 -0
- coco_core/indexing/__init__.py +53 -0
- coco_core/indexing/api.py +954 -0
- coco_core/indexing/base.py +661 -0
- coco_core/indexing/in_memory.py +104 -0
- coco_core/language_models/__init__.py +116 -0
- coco_core/language_models/_compat_bridge.py +844 -0
- coco_core/language_models/_utils.py +343 -0
- coco_core/language_models/base.py +500 -0
- coco_core/language_models/chat_model_stream.py +1525 -0
- coco_core/language_models/chat_models.py +2748 -0
- coco_core/language_models/fake.py +137 -0
- coco_core/language_models/fake_chat_models.py +396 -0
- coco_core/language_models/llms.py +1569 -0
- coco_core/language_models/model_profile.py +183 -0
- coco_core/load/__init__.py +44 -0
- coco_core/load/_validation.py +191 -0
- coco_core/load/dump.py +120 -0
- coco_core/load/load.py +828 -0
- coco_core/load/mapping.py +1097 -0
- coco_core/load/serializable.py +406 -0
- coco_core/messages/__init__.py +198 -0
- coco_core/messages/ai.py +854 -0
- coco_core/messages/base.py +518 -0
- coco_core/messages/block_translators/__init__.py +112 -0
- coco_core/messages/block_translators/anthropic.py +534 -0
- coco_core/messages/block_translators/bedrock.py +108 -0
- coco_core/messages/block_translators/bedrock_converse.py +329 -0
- coco_core/messages/block_translators/coco_v0.py +303 -0
- coco_core/messages/block_translators/google_genai.py +610 -0
- coco_core/messages/block_translators/google_vertexai.py +21 -0
- coco_core/messages/block_translators/groq.py +157 -0
- coco_core/messages/block_translators/openai.py +1089 -0
- coco_core/messages/chat.py +64 -0
- coco_core/messages/content.py +1488 -0
- coco_core/messages/function.py +62 -0
- coco_core/messages/human.py +70 -0
- coco_core/messages/modifier.py +33 -0
- coco_core/messages/system.py +70 -0
- coco_core/messages/tool.py +418 -0
- coco_core/messages/utils.py +2442 -0
- coco_core/output_parsers/__init__.py +101 -0
- coco_core/output_parsers/base.py +361 -0
- coco_core/output_parsers/format_instructions.py +16 -0
- coco_core/output_parsers/json.py +139 -0
- coco_core/output_parsers/list.py +249 -0
- coco_core/output_parsers/openai_functions.py +324 -0
- coco_core/output_parsers/openai_tools.py +383 -0
- coco_core/output_parsers/pydantic.py +141 -0
- coco_core/output_parsers/string.py +63 -0
- coco_core/output_parsers/transform.py +175 -0
- coco_core/output_parsers/xml.py +301 -0
- coco_core/outputs/__init__.py +66 -0
- coco_core/outputs/chat_generation.py +147 -0
- coco_core/outputs/chat_result.py +39 -0
- coco_core/outputs/generation.py +80 -0
- coco_core/outputs/llm_result.py +112 -0
- coco_core/outputs/run_info.py +22 -0
- coco_core/prompt_values.py +161 -0
- coco_core/prompts/__init__.py +101 -0
- coco_core/prompts/base.py +508 -0
- coco_core/prompts/chat.py +1495 -0
- coco_core/prompts/dict.py +177 -0
- coco_core/prompts/few_shot.py +483 -0
- coco_core/prompts/few_shot_with_templates.py +239 -0
- coco_core/prompts/image.py +177 -0
- coco_core/prompts/loading.py +296 -0
- coco_core/prompts/message.py +97 -0
- coco_core/prompts/prompt.py +312 -0
- coco_core/prompts/string.py +399 -0
- coco_core/prompts/structured.py +214 -0
- coco_core/py.typed +0 -0
- coco_core/rate_limiters.py +254 -0
- coco_core/retrievers.py +328 -0
- coco_core/runnables/__init__.py +136 -0
- coco_core/runnables/base.py +6725 -0
- coco_core/runnables/branch.py +457 -0
- coco_core/runnables/config.py +712 -0
- coco_core/runnables/configurable.py +710 -0
- coco_core/runnables/fallbacks.py +663 -0
- coco_core/runnables/graph.py +741 -0
- coco_core/runnables/graph_ascii.py +366 -0
- coco_core/runnables/graph_mermaid.py +503 -0
- coco_core/runnables/graph_png.py +215 -0
- coco_core/runnables/history.py +631 -0
- coco_core/runnables/passthrough.py +849 -0
- coco_core/runnables/retry.py +379 -0
- coco_core/runnables/router.py +239 -0
- coco_core/runnables/schema.py +188 -0
- coco_core/runnables/utils.py +798 -0
- coco_core/stores.py +291 -0
- coco_core/structured_query.py +203 -0
- coco_core/sys_info.py +154 -0
- coco_core/tools/__init__.py +95 -0
- coco_core/tools/base.py +1948 -0
- coco_core/tools/convert.py +497 -0
- coco_core/tools/render.py +67 -0
- coco_core/tools/retriever.py +94 -0
- coco_core/tools/simple.py +208 -0
- coco_core/tools/structured.py +322 -0
- coco_core/tracers/__init__.py +47 -0
- coco_core/tracers/_compat.py +95 -0
- coco_core/tracers/_context.py +337 -0
- coco_core/tracers/_streaming.py +53 -0
- coco_core/tracers/base.py +955 -0
- coco_core/tracers/coco.py +279 -0
- coco_core/tracers/context.py +205 -0
- coco_core/tracers/core.py +766 -0
- coco_core/tracers/event_stream.py +1101 -0
- coco_core/tracers/log_stream.py +765 -0
- coco_core/tracers/memory_stream.py +200 -0
- coco_core/tracers/root_listeners.py +130 -0
- coco_core/tracers/run_collector.py +40 -0
- coco_core/tracers/schemas.py +14 -0
- coco_core/tracers/stdout.py +205 -0
- coco_core/utils/__init__.py +111 -0
- coco_core/utils/_gateway.py +274 -0
- coco_core/utils/_merge.py +218 -0
- coco_core/utils/aiter.py +357 -0
- coco_core/utils/env.py +86 -0
- coco_core/utils/formatting.py +80 -0
- coco_core/utils/function_calling.py +869 -0
- coco_core/utils/html.py +132 -0
- coco_core/utils/image.py +15 -0
- coco_core/utils/input.py +82 -0
- coco_core/utils/interactive_env.py +12 -0
- coco_core/utils/iter.py +229 -0
- coco_core/utils/json.py +230 -0
- coco_core/utils/json_schema.py +273 -0
- coco_core/utils/mustache.py +706 -0
- coco_core/utils/pydantic.py +631 -0
- coco_core/utils/strings.py +69 -0
- coco_core/utils/usage.py +61 -0
- coco_core/utils/utils.py +528 -0
- coco_core/utils/uuid.py +57 -0
- coco_core/vectorstores/__init__.py +53 -0
- coco_core/vectorstores/base.py +1111 -0
- coco_core/vectorstores/in_memory.py +546 -0
- coco_core/vectorstores/utils.py +163 -0
- coco_core/version.py +3 -0
- coco_framework-0.1.0.dist-info/METADATA +184 -0
- coco_framework-0.1.0.dist-info/RECORD +400 -0
- coco_framework-0.1.0.dist-info/WHEEL +4 -0
- coco_framework-0.1.0.dist-info/licenses/LICENSE +24 -0
- coco_framework-0.1.0.dist-info/licenses/NOTICE +15 -0
- coco_graph/_internal/__init__.py +4 -0
- coco_graph/_internal/_cache.py +31 -0
- coco_graph/_internal/_config.py +474 -0
- coco_graph/_internal/_constants.py +140 -0
- coco_graph/_internal/_fields.py +213 -0
- coco_graph/_internal/_future.py +220 -0
- coco_graph/_internal/_pydantic.py +275 -0
- coco_graph/_internal/_queue.py +124 -0
- coco_graph/_internal/_replay.py +90 -0
- coco_graph/_internal/_retry.py +29 -0
- coco_graph/_internal/_runnable.py +969 -0
- coco_graph/_internal/_scratchpad.py +19 -0
- coco_graph/_internal/_serde.py +253 -0
- coco_graph/_internal/_timeout.py +25 -0
- coco_graph/_internal/_typing.py +54 -0
- coco_graph/cache/base/__init__.py +48 -0
- coco_graph/cache/base/py.typed +0 -0
- coco_graph/cache/memory/__init__.py +73 -0
- coco_graph/cache/redis/__init__.py +144 -0
- coco_graph/cache/sqlite/__init__.py +120 -0
- coco_graph/callbacks.py +394 -0
- coco_graph/channels/__init__.py +29 -0
- coco_graph/channels/any_value.py +72 -0
- coco_graph/channels/base.py +121 -0
- coco_graph/channels/binop.py +155 -0
- coco_graph/channels/delta.py +202 -0
- coco_graph/channels/ephemeral_value.py +79 -0
- coco_graph/channels/last_value.py +151 -0
- coco_graph/channels/named_barrier_value.py +167 -0
- coco_graph/channels/topic.py +94 -0
- coco_graph/channels/untracked_value.py +73 -0
- coco_graph/checkpoint/base/__init__.py +861 -0
- coco_graph/checkpoint/base/id.py +109 -0
- coco_graph/checkpoint/base/py.typed +0 -0
- coco_graph/checkpoint/memory/__init__.py +698 -0
- coco_graph/checkpoint/memory/py.typed +0 -0
- coco_graph/checkpoint/postgres/__init__.py +602 -0
- coco_graph/checkpoint/postgres/_ainternal.py +23 -0
- coco_graph/checkpoint/postgres/_internal.py +21 -0
- coco_graph/checkpoint/postgres/aio.py +691 -0
- coco_graph/checkpoint/postgres/base.py +666 -0
- coco_graph/checkpoint/postgres/py.typed +0 -0
- coco_graph/checkpoint/postgres/shallow.py +967 -0
- coco_graph/checkpoint/serde/__init__.py +0 -0
- coco_graph/checkpoint/serde/_msgpack.py +97 -0
- coco_graph/checkpoint/serde/base.py +64 -0
- coco_graph/checkpoint/serde/encrypted.py +80 -0
- coco_graph/checkpoint/serde/event_hooks.py +52 -0
- coco_graph/checkpoint/serde/jsonplus.py +883 -0
- coco_graph/checkpoint/serde/py.typed +0 -0
- coco_graph/checkpoint/serde/types.py +68 -0
- coco_graph/checkpoint/sqlite/__init__.py +645 -0
- coco_graph/checkpoint/sqlite/_delta.py +172 -0
- coco_graph/checkpoint/sqlite/aio.py +738 -0
- coco_graph/checkpoint/sqlite/py.typed +0 -0
- coco_graph/checkpoint/sqlite/utils.py +116 -0
- coco_graph/config.py +196 -0
- coco_graph/constants.py +64 -0
- coco_graph/errors.py +241 -0
- coco_graph/func/__init__.py +620 -0
- coco_graph/graph/__init__.py +12 -0
- coco_graph/graph/_branch.py +225 -0
- coco_graph/graph/_node.py +103 -0
- coco_graph/graph/message.py +437 -0
- coco_graph/graph/state.py +1978 -0
- coco_graph/graph/ui.py +227 -0
- coco_graph/managed/__init__.py +3 -0
- coco_graph/managed/base.py +31 -0
- coco_graph/managed/is_last_step.py +24 -0
- coco_graph/prebuilt/__init__.py +23 -0
- coco_graph/prebuilt/_tool_call_stream.py +117 -0
- coco_graph/prebuilt/_tool_call_transformer.py +165 -0
- coco_graph/prebuilt/chat_agent_executor.py +1015 -0
- coco_graph/prebuilt/interrupt.py +105 -0
- coco_graph/prebuilt/py.typed +0 -0
- coco_graph/prebuilt/tool_node.py +2030 -0
- coco_graph/prebuilt/tool_validator.py +221 -0
- coco_graph/pregel/__init__.py +3 -0
- coco_graph/pregel/_algo.py +1460 -0
- coco_graph/pregel/_call.py +298 -0
- coco_graph/pregel/_checkpoint.py +331 -0
- coco_graph/pregel/_config.py +0 -0
- coco_graph/pregel/_draw.py +294 -0
- coco_graph/pregel/_executor.py +223 -0
- coco_graph/pregel/_io.py +174 -0
- coco_graph/pregel/_log.py +3 -0
- coco_graph/pregel/_loop.py +1988 -0
- coco_graph/pregel/_messages.py +461 -0
- coco_graph/pregel/_read.py +312 -0
- coco_graph/pregel/_retry.py +854 -0
- coco_graph/pregel/_runner.py +941 -0
- coco_graph/pregel/_tools.py +268 -0
- coco_graph/pregel/_utils.py +221 -0
- coco_graph/pregel/_validate.py +120 -0
- coco_graph/pregel/_write.py +192 -0
- coco_graph/pregel/debug.py +302 -0
- coco_graph/pregel/main.py +4364 -0
- coco_graph/pregel/protocol.py +288 -0
- coco_graph/pregel/types.py +38 -0
- coco_graph/py.typed +0 -0
- coco_graph/runtime.py +350 -0
- coco_graph/store/base/__init__.py +1322 -0
- coco_graph/store/base/batch.py +371 -0
- coco_graph/store/base/embed.py +436 -0
- coco_graph/store/base/py.typed +0 -0
- coco_graph/store/memory/__init__.py +592 -0
- coco_graph/store/memory/py.typed +0 -0
- coco_graph/store/postgres/__init__.py +4 -0
- coco_graph/store/postgres/aio.py +592 -0
- coco_graph/store/postgres/base.py +1480 -0
- coco_graph/store/postgres/py.typed +0 -0
- coco_graph/store/sqlite/__init__.py +4 -0
- coco_graph/store/sqlite/aio.py +632 -0
- coco_graph/store/sqlite/base.py +1514 -0
- coco_graph/stream/__init__.py +45 -0
- coco_graph/stream/_convert.py +32 -0
- coco_graph/stream/_mux.py +523 -0
- coco_graph/stream/_types.py +330 -0
- coco_graph/stream/run_stream.py +735 -0
- coco_graph/stream/stream_channel.py +341 -0
- coco_graph/stream/transformers.py +1039 -0
- coco_graph/types.py +1079 -0
- coco_graph/typing.py +48 -0
- coco_graph/utils/__init__.py +1 -0
- coco_graph/utils/config.py +4 -0
- coco_graph/utils/runnable.py +3 -0
- coco_graph/version.py +13 -0
- coco_graph/warnings.py +69 -0
- coco_openai/__init__.py +20 -0
- coco_openai/_compat.py +45 -0
- coco_openai/_version.py +3 -0
- coco_openai/chat_models/__init__.py +6 -0
- coco_openai/chat_models/_client_utils.py +684 -0
- coco_openai/chat_models/_compat.py +525 -0
- coco_openai/chat_models/azure.py +1227 -0
- coco_openai/chat_models/base.py +5654 -0
- coco_openai/chat_models/codex.py +557 -0
- coco_openai/chatgpt_oauth.py +1063 -0
- coco_openai/data/__init__.py +1 -0
- coco_openai/data/_profiles.py +1655 -0
- coco_openai/data/profile_augmentations.toml +127 -0
- coco_openai/embeddings/__init__.py +6 -0
- coco_openai/embeddings/azure.py +240 -0
- coco_openai/embeddings/base.py +820 -0
- coco_openai/llms/__init__.py +6 -0
- coco_openai/llms/azure.py +249 -0
- coco_openai/llms/base.py +919 -0
- coco_openai/middleware/__init__.py +11 -0
- coco_openai/middleware/openai_moderation.py +484 -0
- coco_openai/output_parsers/__init__.py +9 -0
- coco_openai/output_parsers/tools.py +9 -0
- coco_openai/py.typed +0 -0
- coco_openai/tools/__init__.py +5 -0
- coco_openai/tools/custom_tool.py +111 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Hashable, Mapping, Sequence
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _freeze(obj: Any, depth: int = 10) -> Hashable:
|
|
8
|
+
if isinstance(obj, Hashable) or depth <= 0:
|
|
9
|
+
# already hashable, no need to freeze
|
|
10
|
+
return obj
|
|
11
|
+
elif isinstance(obj, Mapping):
|
|
12
|
+
# sort keys so {"a":1,"b":2} == {"b":2,"a":1}
|
|
13
|
+
return tuple(sorted((k, _freeze(v, depth - 1)) for k, v in obj.items()))
|
|
14
|
+
elif isinstance(obj, Sequence):
|
|
15
|
+
return tuple(_freeze(x, depth - 1) for x in obj)
|
|
16
|
+
# numpy / pandas etc. can provide their own .tobytes()
|
|
17
|
+
elif hasattr(obj, "tobytes"):
|
|
18
|
+
return (
|
|
19
|
+
type(obj).__name__,
|
|
20
|
+
obj.tobytes(),
|
|
21
|
+
obj.shape if hasattr(obj, "shape") else None,
|
|
22
|
+
)
|
|
23
|
+
return obj # strings, ints, dataclasses with frozen=True, etc.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def default_cache_key(*args: Any, **kwargs: Any) -> str | bytes:
|
|
27
|
+
"""Default cache key function that uses the arguments and keyword arguments to generate a hashable key."""
|
|
28
|
+
import pickle
|
|
29
|
+
|
|
30
|
+
# protocol 5 strikes a good balance between speed and size
|
|
31
|
+
return pickle.dumps((_freeze(args), _freeze(kwargs)), protocol=5, fix_imports=False)
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import ChainMap
|
|
4
|
+
from collections.abc import Mapping, Sequence
|
|
5
|
+
from os import getenv
|
|
6
|
+
from typing import Any, cast
|
|
7
|
+
|
|
8
|
+
from coco_core.callbacks import (
|
|
9
|
+
AsyncCallbackManager,
|
|
10
|
+
BaseCallbackManager,
|
|
11
|
+
CallbackManager,
|
|
12
|
+
Callbacks,
|
|
13
|
+
)
|
|
14
|
+
from coco_core.runnables import RunnableConfig
|
|
15
|
+
from coco_core.runnables.config import (
|
|
16
|
+
CONFIG_KEYS,
|
|
17
|
+
COPIABLE_KEYS,
|
|
18
|
+
var_child_runnable_config,
|
|
19
|
+
)
|
|
20
|
+
from coco_graph.checkpoint.base import CheckpointMetadata
|
|
21
|
+
|
|
22
|
+
from coco_graph._internal._constants import (
|
|
23
|
+
_CHECKPOINT_COORDINATE_KEYS,
|
|
24
|
+
CONF,
|
|
25
|
+
CONFIG_KEY_CHECKPOINT_ID,
|
|
26
|
+
CONFIG_KEY_CHECKPOINT_MAP,
|
|
27
|
+
CONFIG_KEY_CHECKPOINT_NS,
|
|
28
|
+
NS_END,
|
|
29
|
+
NS_SEP,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
DEFAULT_RECURSION_LIMIT = int(getenv("COCO_GRAPH_DEFAULT_RECURSION_LIMIT", "10007"))
|
|
33
|
+
DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT = int(
|
|
34
|
+
getenv("COCO_GRAPH_DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT", "5000")
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def recast_checkpoint_ns(ns: str) -> str:
|
|
39
|
+
"""Remove task IDs from checkpoint namespace.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
ns: The checkpoint namespace with task IDs.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
str: The checkpoint namespace without task IDs.
|
|
46
|
+
"""
|
|
47
|
+
return NS_SEP.join(
|
|
48
|
+
part.split(NS_END)[0] for part in ns.split(NS_SEP) if not part.isdigit()
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def patch_configurable(
|
|
53
|
+
config: RunnableConfig | None, patch: dict[str, Any]
|
|
54
|
+
) -> RunnableConfig:
|
|
55
|
+
if config is None:
|
|
56
|
+
return {CONF: patch}
|
|
57
|
+
elif CONF not in config:
|
|
58
|
+
return {**config, CONF: patch}
|
|
59
|
+
else:
|
|
60
|
+
return {**config, CONF: {**config[CONF], **patch}}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def patch_checkpoint_map(
|
|
64
|
+
config: RunnableConfig | None, metadata: CheckpointMetadata | None
|
|
65
|
+
) -> RunnableConfig:
|
|
66
|
+
if config is None:
|
|
67
|
+
return config
|
|
68
|
+
elif parents := (metadata.get("parents") if metadata else None):
|
|
69
|
+
conf = config[CONF]
|
|
70
|
+
return patch_configurable(
|
|
71
|
+
config,
|
|
72
|
+
{
|
|
73
|
+
CONFIG_KEY_CHECKPOINT_MAP: {
|
|
74
|
+
**parents,
|
|
75
|
+
conf[CONFIG_KEY_CHECKPOINT_NS]: conf[CONFIG_KEY_CHECKPOINT_ID],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
return config
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _copy_mapping_value(value: Any) -> Any:
|
|
84
|
+
return dict(value) if isinstance(value, Mapping) else value
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _merge_metadata(
|
|
88
|
+
base: Mapping[str, Any] | None, new: Mapping[str, Any] | None
|
|
89
|
+
) -> dict[str, Any]:
|
|
90
|
+
"""Merge metadata without mutating inputs.
|
|
91
|
+
|
|
92
|
+
Top-level keys merge with newer values winning. `lc_versions` is the only
|
|
93
|
+
mapping-valued key that merges one level deeper, so independent Coco
|
|
94
|
+
packages can contribute package versions without changing generic metadata
|
|
95
|
+
semantics. Mapping values are copied one level, so deeper nested objects
|
|
96
|
+
remain shared. `None` inputs are treated as empty metadata.
|
|
97
|
+
|
|
98
|
+
Mirrors `coco_core.runnables.config._merge_metadata_dicts` so configs
|
|
99
|
+
that pass through CocoGraph's merge keep the same `lc_versions` semantics;
|
|
100
|
+
keep the two in sync. Unlike lc-core, this copies mapping values one level
|
|
101
|
+
(intentionally more defensive — do not "simplify" back to a shared ref).
|
|
102
|
+
"""
|
|
103
|
+
merged = {key: _copy_mapping_value(value) for key, value in (base or {}).items()}
|
|
104
|
+
for key, value in (new or {}).items():
|
|
105
|
+
if (
|
|
106
|
+
key == "lc_versions"
|
|
107
|
+
and isinstance(merged.get(key), Mapping)
|
|
108
|
+
and isinstance(value, Mapping)
|
|
109
|
+
):
|
|
110
|
+
merged[key] = {
|
|
111
|
+
**cast(Mapping[str, Any], merged[key]),
|
|
112
|
+
**value,
|
|
113
|
+
}
|
|
114
|
+
else:
|
|
115
|
+
merged[key] = _copy_mapping_value(value)
|
|
116
|
+
return merged
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _merge_callbacks(base: Callbacks, new: Callbacks) -> Callbacks:
|
|
120
|
+
"""Merge two callbacks values (None / list / BaseCallbackManager).
|
|
121
|
+
|
|
122
|
+
Six cases total (3 base types x 2 non-None new types).
|
|
123
|
+
"""
|
|
124
|
+
if new is None:
|
|
125
|
+
return base
|
|
126
|
+
if base is None:
|
|
127
|
+
return new.copy() if isinstance(new, (list, BaseCallbackManager)) else new
|
|
128
|
+
if isinstance(new, list):
|
|
129
|
+
if isinstance(base, list):
|
|
130
|
+
return base + new
|
|
131
|
+
if isinstance(base, BaseCallbackManager):
|
|
132
|
+
mngr = base.copy()
|
|
133
|
+
for cb in new:
|
|
134
|
+
mngr.add_handler(cb, inherit=True)
|
|
135
|
+
return mngr
|
|
136
|
+
elif isinstance(new, BaseCallbackManager):
|
|
137
|
+
if isinstance(base, list):
|
|
138
|
+
mngr = new.copy()
|
|
139
|
+
for cb in base:
|
|
140
|
+
mngr.add_handler(cb, inherit=True)
|
|
141
|
+
return mngr
|
|
142
|
+
if isinstance(base, BaseCallbackManager):
|
|
143
|
+
return base.merge(new)
|
|
144
|
+
raise NotImplementedError(f"Unsupported callback types: {type(base)}, {type(new)}")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def merge_configs(*configs: RunnableConfig | None) -> RunnableConfig:
|
|
148
|
+
"""Merge multiple configs into one.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
*configs: The configs to merge.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
RunnableConfig: The merged config.
|
|
155
|
+
"""
|
|
156
|
+
base: RunnableConfig = {}
|
|
157
|
+
# Even though the keys aren't literals, this is correct
|
|
158
|
+
# because both dicts are the same type
|
|
159
|
+
for config in configs:
|
|
160
|
+
if config is None:
|
|
161
|
+
continue
|
|
162
|
+
for key, value in config.items():
|
|
163
|
+
if not value:
|
|
164
|
+
continue
|
|
165
|
+
if key == "metadata":
|
|
166
|
+
base[key] = _merge_metadata(
|
|
167
|
+
cast(Mapping[str, Any] | None, base.get(key)),
|
|
168
|
+
cast(Mapping[str, Any], value),
|
|
169
|
+
)
|
|
170
|
+
elif key == "tags":
|
|
171
|
+
if base_value := base.get(key):
|
|
172
|
+
base[key] = [*base_value, *value] # type: ignore
|
|
173
|
+
else:
|
|
174
|
+
base[key] = value # type: ignore[literal-required]
|
|
175
|
+
elif key == CONF:
|
|
176
|
+
if base_value := base.get(key):
|
|
177
|
+
base[key] = {**base_value, **value} # type: ignore[dict-item]
|
|
178
|
+
else:
|
|
179
|
+
base[key] = value
|
|
180
|
+
elif key == "callbacks":
|
|
181
|
+
base["callbacks"] = _merge_callbacks(
|
|
182
|
+
base.get("callbacks"), cast(Callbacks, value)
|
|
183
|
+
)
|
|
184
|
+
elif key == "recursion_limit":
|
|
185
|
+
if config["recursion_limit"] != DEFAULT_RECURSION_LIMIT:
|
|
186
|
+
base["recursion_limit"] = config["recursion_limit"]
|
|
187
|
+
else:
|
|
188
|
+
base[key] = config[key] # type: ignore[literal-required]
|
|
189
|
+
if CONF not in base:
|
|
190
|
+
base[CONF] = {}
|
|
191
|
+
return base
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def patch_config(
|
|
195
|
+
config: RunnableConfig | None,
|
|
196
|
+
*,
|
|
197
|
+
callbacks: Callbacks = None,
|
|
198
|
+
recursion_limit: int | None = None,
|
|
199
|
+
max_concurrency: int | None = None,
|
|
200
|
+
run_name: str | None = None,
|
|
201
|
+
configurable: dict[str, Any] | None = None,
|
|
202
|
+
) -> RunnableConfig:
|
|
203
|
+
"""Patch a config with new values.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
config: The config to patch.
|
|
207
|
+
callbacks: The callbacks to set.
|
|
208
|
+
recursion_limit: The recursion limit to set.
|
|
209
|
+
max_concurrency: The max number of concurrent steps to run, which also applies to parallelized steps.
|
|
210
|
+
run_name: The run name to set.
|
|
211
|
+
configurable: The configurable to set.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
RunnableConfig: The patched config.
|
|
215
|
+
"""
|
|
216
|
+
config = config.copy() if config is not None else {}
|
|
217
|
+
if callbacks is not None:
|
|
218
|
+
# If we're replacing callbacks, we need to unset run_name
|
|
219
|
+
# As that should apply only to the same run as the original callbacks
|
|
220
|
+
config["callbacks"] = callbacks
|
|
221
|
+
if "run_name" in config:
|
|
222
|
+
del config["run_name"]
|
|
223
|
+
if "run_id" in config:
|
|
224
|
+
del config["run_id"]
|
|
225
|
+
if recursion_limit is not None:
|
|
226
|
+
config["recursion_limit"] = recursion_limit
|
|
227
|
+
if max_concurrency is not None:
|
|
228
|
+
config["max_concurrency"] = max_concurrency
|
|
229
|
+
if run_name is not None:
|
|
230
|
+
config["run_name"] = run_name
|
|
231
|
+
if configurable is not None:
|
|
232
|
+
config[CONF] = {**config.get(CONF, {}), **configurable}
|
|
233
|
+
return config
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def get_callback_manager_for_config(
|
|
237
|
+
config: RunnableConfig, tags: Sequence[str] | None = None
|
|
238
|
+
) -> CallbackManager:
|
|
239
|
+
"""Get a callback manager for a config.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
config: The config.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
CallbackManager: The callback manager.
|
|
246
|
+
"""
|
|
247
|
+
from coco_core.callbacks.manager import CallbackManager
|
|
248
|
+
|
|
249
|
+
# merge tags
|
|
250
|
+
all_tags = config.get("tags")
|
|
251
|
+
if all_tags is not None and tags is not None:
|
|
252
|
+
all_tags = [*all_tags, *tags]
|
|
253
|
+
elif tags is not None:
|
|
254
|
+
all_tags = list(tags)
|
|
255
|
+
# use existing callbacks if they exist
|
|
256
|
+
if (callbacks := config.get("callbacks")) and isinstance(
|
|
257
|
+
callbacks, CallbackManager
|
|
258
|
+
):
|
|
259
|
+
if all_tags:
|
|
260
|
+
callbacks.add_tags(all_tags)
|
|
261
|
+
if metadata := config.get("metadata"):
|
|
262
|
+
callbacks.add_metadata(metadata)
|
|
263
|
+
manager = callbacks
|
|
264
|
+
else:
|
|
265
|
+
# otherwise create a new manager
|
|
266
|
+
manager = CallbackManager.configure(
|
|
267
|
+
inheritable_callbacks=config.get("callbacks"),
|
|
268
|
+
inheritable_tags=all_tags,
|
|
269
|
+
inheritable_metadata=config.get("metadata"),
|
|
270
|
+
langsmith_inheritable_metadata=_get_tracing_metadata_defaults(config),
|
|
271
|
+
)
|
|
272
|
+
return manager
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def get_async_callback_manager_for_config(
|
|
276
|
+
config: RunnableConfig,
|
|
277
|
+
tags: Sequence[str] | None = None,
|
|
278
|
+
) -> AsyncCallbackManager:
|
|
279
|
+
"""Get an async callback manager for a config.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
config: The config.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
AsyncCallbackManager: The async callback manager.
|
|
286
|
+
"""
|
|
287
|
+
from coco_core.callbacks.manager import AsyncCallbackManager
|
|
288
|
+
|
|
289
|
+
# merge tags
|
|
290
|
+
all_tags = config.get("tags")
|
|
291
|
+
if all_tags is not None and tags is not None:
|
|
292
|
+
all_tags = [*all_tags, *tags]
|
|
293
|
+
elif tags is not None:
|
|
294
|
+
all_tags = list(tags)
|
|
295
|
+
# use existing callbacks if they exist
|
|
296
|
+
if (callbacks := config.get("callbacks")) and isinstance(
|
|
297
|
+
callbacks, AsyncCallbackManager
|
|
298
|
+
):
|
|
299
|
+
if all_tags:
|
|
300
|
+
callbacks.add_tags(all_tags)
|
|
301
|
+
if metadata := config.get("metadata"):
|
|
302
|
+
callbacks.add_metadata(metadata)
|
|
303
|
+
manager = callbacks
|
|
304
|
+
else:
|
|
305
|
+
# otherwise create a new manager
|
|
306
|
+
manager = AsyncCallbackManager.configure(
|
|
307
|
+
inheritable_callbacks=config.get("callbacks"),
|
|
308
|
+
inheritable_tags=all_tags,
|
|
309
|
+
inheritable_metadata=config.get("metadata"),
|
|
310
|
+
langsmith_inheritable_metadata=_get_tracing_metadata_defaults(config),
|
|
311
|
+
)
|
|
312
|
+
return manager
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def _is_not_empty(value: Any) -> bool:
|
|
316
|
+
if isinstance(value, (list, tuple, dict)):
|
|
317
|
+
return len(value) > 0
|
|
318
|
+
else:
|
|
319
|
+
return value is not None
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
|
|
323
|
+
"""Return a config with all keys, merging any provided configs.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
*configs: Configs to merge before ensuring defaults.
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
RunnableConfig: The merged and ensured config.
|
|
330
|
+
"""
|
|
331
|
+
empty = RunnableConfig(
|
|
332
|
+
tags=[],
|
|
333
|
+
metadata=ChainMap(),
|
|
334
|
+
callbacks=None,
|
|
335
|
+
recursion_limit=DEFAULT_RECURSION_LIMIT,
|
|
336
|
+
configurable={},
|
|
337
|
+
)
|
|
338
|
+
if var_config := var_child_runnable_config.get():
|
|
339
|
+
empty.update(
|
|
340
|
+
{
|
|
341
|
+
k: v.copy() if k in COPIABLE_KEYS else v # type: ignore[attr-defined]
|
|
342
|
+
for k, v in var_config.items()
|
|
343
|
+
if _is_not_empty(v)
|
|
344
|
+
},
|
|
345
|
+
)
|
|
346
|
+
# An explicit config that supplies its own checkpoint coordinate (a
|
|
347
|
+
# thread_id, or any checkpoint_ns/checkpoint_id/checkpoint_map) is addressing
|
|
348
|
+
# its own checkpoint lineage, so drop the inherited ambient configurable
|
|
349
|
+
# rather than merging over it: a child graph invoked inside a parent node
|
|
350
|
+
# would otherwise write its checkpoints under the parent's namespace and
|
|
351
|
+
# never find them again. An explicit thread_id resets even when it equals the
|
|
352
|
+
# ambient one, since a child reusing the parent's thread id still addresses
|
|
353
|
+
# its own root namespace, not the parent task's. Configs that only refine
|
|
354
|
+
# other keys keep the ambient and shallow-merge over it below.
|
|
355
|
+
if empty.get(CONF):
|
|
356
|
+
for config in configs:
|
|
357
|
+
if config is None:
|
|
358
|
+
continue
|
|
359
|
+
explicit_configurable = config.get(CONF)
|
|
360
|
+
if not explicit_configurable:
|
|
361
|
+
continue
|
|
362
|
+
if any(
|
|
363
|
+
_is_not_empty(explicit_configurable.get(k))
|
|
364
|
+
for k in _CHECKPOINT_COORDINATE_KEYS
|
|
365
|
+
):
|
|
366
|
+
empty[CONF] = {}
|
|
367
|
+
break
|
|
368
|
+
for config in configs:
|
|
369
|
+
if config is None:
|
|
370
|
+
continue
|
|
371
|
+
for k, v in config.items():
|
|
372
|
+
if _is_not_empty(v) and k in CONFIG_KEYS:
|
|
373
|
+
if k == CONF:
|
|
374
|
+
# Shallow-merge configurable dicts across configs so values
|
|
375
|
+
# bound via with_config(...) (e.g. ls_agent_type) are
|
|
376
|
+
# preserved when later configs (e.g. invoke-time) only
|
|
377
|
+
# specify a subset of keys like thread_id.
|
|
378
|
+
existing = empty.get(k)
|
|
379
|
+
empty[k] = (
|
|
380
|
+
{**cast(dict, existing), **cast(dict, v)}
|
|
381
|
+
if existing
|
|
382
|
+
else cast(dict, v).copy()
|
|
383
|
+
)
|
|
384
|
+
elif k == "callbacks":
|
|
385
|
+
empty["callbacks"] = _merge_callbacks(
|
|
386
|
+
empty.get("callbacks"), cast(Callbacks, v)
|
|
387
|
+
)
|
|
388
|
+
elif k == "metadata":
|
|
389
|
+
# Matches merge_configs: top-level metadata keys merge, and
|
|
390
|
+
# only `lc_versions` merges one level deeper.
|
|
391
|
+
empty["metadata"] = _merge_metadata(
|
|
392
|
+
cast(Mapping[str, Any] | None, empty.get("metadata")),
|
|
393
|
+
cast(Mapping[str, Any], v),
|
|
394
|
+
)
|
|
395
|
+
elif k == "tags":
|
|
396
|
+
# Concatenate tags across configs so values bound via
|
|
397
|
+
# with_config(...) are preserved when later configs
|
|
398
|
+
# supply additional tags. Matches merge_configs.
|
|
399
|
+
existing_tags: list[str] | None = empty.get("tags")
|
|
400
|
+
empty["tags"] = (
|
|
401
|
+
[*existing_tags, *cast(list, v)]
|
|
402
|
+
if existing_tags
|
|
403
|
+
else list(cast(list, v))
|
|
404
|
+
)
|
|
405
|
+
else:
|
|
406
|
+
empty[k] = v # type: ignore[literal-required]
|
|
407
|
+
for k, v in config.items():
|
|
408
|
+
if _is_not_empty(v) and k not in CONFIG_KEYS:
|
|
409
|
+
empty[CONF][k] = v
|
|
410
|
+
|
|
411
|
+
configurable = empty.get("configurable")
|
|
412
|
+
metadata = empty.get("metadata")
|
|
413
|
+
if configurable and metadata is not None:
|
|
414
|
+
for key in _PROPAGATE_TO_METADATA:
|
|
415
|
+
if key in metadata:
|
|
416
|
+
continue
|
|
417
|
+
value = configurable.get(key)
|
|
418
|
+
if value:
|
|
419
|
+
metadata[key] = value
|
|
420
|
+
return empty
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
_OMIT = ("key", "token", "secret", "password", "auth")
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _exclude_as_metadata(key: str, value: Any) -> bool:
|
|
427
|
+
key_lower = key.casefold()
|
|
428
|
+
return (
|
|
429
|
+
key.startswith("__")
|
|
430
|
+
or not isinstance(value, (str, int, float, bool))
|
|
431
|
+
or any(substr in key_lower for substr in _OMIT)
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def _get_tracing_metadata_defaults(
|
|
436
|
+
config: RunnableConfig,
|
|
437
|
+
) -> dict[str, Any] | None:
|
|
438
|
+
"""Get tracer-only metadata defaults from configurable values."""
|
|
439
|
+
configurable = config.get("configurable")
|
|
440
|
+
if not configurable:
|
|
441
|
+
return None
|
|
442
|
+
metadata: dict[str, Any] = {}
|
|
443
|
+
for key, value in configurable.items():
|
|
444
|
+
if _exclude_as_metadata(key, value):
|
|
445
|
+
continue
|
|
446
|
+
metadata[key] = value
|
|
447
|
+
return metadata or None
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
_PROPAGATE_TO_METADATA = frozenset(
|
|
451
|
+
(
|
|
452
|
+
"thread_id",
|
|
453
|
+
"checkpoint_id",
|
|
454
|
+
"checkpoint_ns",
|
|
455
|
+
"task_id",
|
|
456
|
+
"run_id",
|
|
457
|
+
"assistant_id",
|
|
458
|
+
"graph_id",
|
|
459
|
+
)
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def filter_to_user_tags(tags: Sequence[str] | None) -> list[str] | None:
|
|
464
|
+
"""Drop coco_graph's internal `seq:step:*` bookkeeping tags.
|
|
465
|
+
|
|
466
|
+
`seq:step:N` tags are added internally to mark sequence steps; everything
|
|
467
|
+
else (user-supplied tags and any other framework tags) is kept. Returns the
|
|
468
|
+
surviving tags, or `None` if none remain. Shared by the `messages` and
|
|
469
|
+
`tasks` stream handlers so both surface the same tag set on their metadata.
|
|
470
|
+
"""
|
|
471
|
+
if not tags:
|
|
472
|
+
return None
|
|
473
|
+
filtered = [t for t in tags if not t.startswith("seq:step")]
|
|
474
|
+
return filtered or None
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""Constants used for Pregel operations."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from typing import Literal, cast
|
|
5
|
+
|
|
6
|
+
# --- Reserved write keys ---
|
|
7
|
+
INPUT = sys.intern("__input__")
|
|
8
|
+
# for values passed as input to the graph
|
|
9
|
+
INTERRUPT = sys.intern("__interrupt__")
|
|
10
|
+
# for dynamic interrupts raised by nodes
|
|
11
|
+
RESUME = sys.intern("__resume__")
|
|
12
|
+
# for values passed to resume a node after an interrupt
|
|
13
|
+
ERROR = sys.intern("__error__")
|
|
14
|
+
# for errors raised by nodes
|
|
15
|
+
ERROR_SOURCE_NODE = sys.intern("__error_source_node__")
|
|
16
|
+
# failed source node name for node-level error handlers
|
|
17
|
+
# value format in pending writes: `(task_id, ERROR_SOURCE_NODE, node_name: str)`
|
|
18
|
+
NO_WRITES = sys.intern("__no_writes__")
|
|
19
|
+
# marker to signal node didn't write anything
|
|
20
|
+
TASKS = sys.intern("__pregel_tasks")
|
|
21
|
+
# for Send objects returned by nodes/edges, corresponds to PUSH below
|
|
22
|
+
RETURN = sys.intern("__return__")
|
|
23
|
+
# for writes of a task where we simply record the return value
|
|
24
|
+
PREVIOUS = sys.intern("__previous__")
|
|
25
|
+
# the implicit branch that handles each node's Control values
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# --- Reserved cache namespaces ---
|
|
29
|
+
CACHE_NS_WRITES = sys.intern("__pregel_ns_writes")
|
|
30
|
+
# cache namespace for node writes
|
|
31
|
+
|
|
32
|
+
# --- Reserved config.configurable keys ---
|
|
33
|
+
CONFIG_KEY_SEND = sys.intern("__pregel_send")
|
|
34
|
+
# holds the `write` function that accepts writes to state/edges/reserved keys
|
|
35
|
+
CONFIG_KEY_READ = sys.intern("__pregel_read")
|
|
36
|
+
# holds the `read` function that returns a copy of the current state
|
|
37
|
+
CONFIG_KEY_CALL = sys.intern("__pregel_call")
|
|
38
|
+
# holds the `call` function that accepts a node/func, args and returns a future
|
|
39
|
+
CONFIG_KEY_CHECKPOINTER = sys.intern("__pregel_checkpointer")
|
|
40
|
+
# holds a `BaseCheckpointSaver` passed from parent graph to child graphs
|
|
41
|
+
CONFIG_KEY_STREAM = sys.intern("__pregel_stream")
|
|
42
|
+
# holds a `StreamProtocol` passed from parent graph to child graphs
|
|
43
|
+
CONFIG_KEY_CACHE = sys.intern("__pregel_cache")
|
|
44
|
+
# holds a `BaseCache` made available to subgraphs
|
|
45
|
+
CONFIG_KEY_RESUMING = sys.intern("__pregel_resuming")
|
|
46
|
+
# holds a boolean indicating if subgraphs should resume from a previous checkpoint
|
|
47
|
+
CONFIG_KEY_REPLAY_STATE = sys.intern("__pregel_replay_state")
|
|
48
|
+
# holds a ReplayState tracking the parent checkpoint_id upper bound and which
|
|
49
|
+
# subgraph namespaces have already loaded their pre-replay checkpoint
|
|
50
|
+
CONFIG_KEY_TASK_ID = sys.intern("__pregel_task_id")
|
|
51
|
+
# holds the task ID for the current task
|
|
52
|
+
CONFIG_KEY_THREAD_ID = sys.intern("thread_id")
|
|
53
|
+
# holds the thread ID for the current invocation
|
|
54
|
+
CONFIG_KEY_CHECKPOINT_MAP = sys.intern("checkpoint_map")
|
|
55
|
+
# holds a mapping of checkpoint_ns -> checkpoint_id for parent graphs
|
|
56
|
+
CONFIG_KEY_CHECKPOINT_ID = sys.intern("checkpoint_id")
|
|
57
|
+
# holds the current checkpoint_id, if any
|
|
58
|
+
CONFIG_KEY_CHECKPOINT_NS = sys.intern("checkpoint_ns")
|
|
59
|
+
# holds the current checkpoint_ns, "" for root graph
|
|
60
|
+
CONFIG_KEY_NODE_FINISHED = sys.intern("__pregel_node_finished")
|
|
61
|
+
# holds a callback to be called when a node is finished
|
|
62
|
+
CONFIG_KEY_TIMED_ATTEMPT_OBSERVER = sys.intern("__pregel_timed_attempt_observer")
|
|
63
|
+
# holds a callback to be called when an idle-timed node attempt starts or finishes
|
|
64
|
+
CONFIG_KEY_SCRATCHPAD = sys.intern("__pregel_scratchpad")
|
|
65
|
+
# holds a mutable dict for temporary storage scoped to the current task
|
|
66
|
+
CONFIG_KEY_RUNNER_SUBMIT = sys.intern("__pregel_runner_submit")
|
|
67
|
+
# holds a function that receives tasks from runner, executes them and returns results
|
|
68
|
+
CONFIG_KEY_DURABILITY = sys.intern("__pregel_durability")
|
|
69
|
+
# holds the durability mode, one of "sync", "async", or "exit"
|
|
70
|
+
CONFIG_KEY_RUNTIME = sys.intern("__pregel_runtime")
|
|
71
|
+
# holds a `Runtime` instance with context, store, stream writer, etc.
|
|
72
|
+
CONFIG_KEY_RESUME_MAP = sys.intern("__pregel_resume_map")
|
|
73
|
+
# holds a mapping of task ns -> resume value for resuming tasks
|
|
74
|
+
CONFIG_KEY_STREAM_MESSAGES_V2 = sys.intern("__pregel_stream_messages_v2")
|
|
75
|
+
# when True, attach StreamMessagesHandlerV2 so content-block (v2) events
|
|
76
|
+
# flow through stream_mode="messages"; set by StreamingHandler only.
|
|
77
|
+
CONFIG_KEY_NODE_ERROR = sys.intern("__pregel_node_error")
|
|
78
|
+
# holds a `NodeError` (failed source node + exception) for the current
|
|
79
|
+
# node-level error handler invocation, injected when handler signature
|
|
80
|
+
# requests `error: NodeError`
|
|
81
|
+
|
|
82
|
+
# --- Other constants ---
|
|
83
|
+
PUSH = sys.intern("__pregel_push")
|
|
84
|
+
# denotes push-style tasks, ie. those created by Send objects
|
|
85
|
+
PULL = sys.intern("__pregel_pull")
|
|
86
|
+
# denotes pull-style tasks, ie. those triggered by edges
|
|
87
|
+
NS_SEP = sys.intern("|")
|
|
88
|
+
# for checkpoint_ns, separates each level (ie. graph|subgraph|subsubgraph)
|
|
89
|
+
NS_END = sys.intern(":")
|
|
90
|
+
# for checkpoint_ns, for each level, separates the namespace from the task_id
|
|
91
|
+
CONF = cast(Literal["configurable"], sys.intern("configurable"))
|
|
92
|
+
# key for the configurable dict in RunnableConfig
|
|
93
|
+
NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
|
|
94
|
+
# the task_id to use for writes that are not associated with a task
|
|
95
|
+
OVERWRITE = sys.intern("__overwrite__")
|
|
96
|
+
# dict key for the overwrite value, used as `{'__overwrite__': value}`
|
|
97
|
+
|
|
98
|
+
# Checkpoint coordinate keys: when any of these appear in an explicit
|
|
99
|
+
# configurable, the caller is addressing its own checkpoint lineage.
|
|
100
|
+
_CHECKPOINT_COORDINATE_KEYS = (
|
|
101
|
+
CONFIG_KEY_THREAD_ID,
|
|
102
|
+
CONFIG_KEY_CHECKPOINT_NS,
|
|
103
|
+
CONFIG_KEY_CHECKPOINT_ID,
|
|
104
|
+
CONFIG_KEY_CHECKPOINT_MAP,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# redefined to avoid circular import with coco_graph.constants
|
|
108
|
+
_TAG_HIDDEN = sys.intern("langsmith:hidden")
|
|
109
|
+
|
|
110
|
+
RESERVED = {
|
|
111
|
+
_TAG_HIDDEN,
|
|
112
|
+
# reserved write keys
|
|
113
|
+
INPUT,
|
|
114
|
+
INTERRUPT,
|
|
115
|
+
RESUME,
|
|
116
|
+
ERROR,
|
|
117
|
+
ERROR_SOURCE_NODE,
|
|
118
|
+
NO_WRITES,
|
|
119
|
+
# reserved config.configurable keys
|
|
120
|
+
CONFIG_KEY_SEND,
|
|
121
|
+
CONFIG_KEY_READ,
|
|
122
|
+
CONFIG_KEY_CHECKPOINTER,
|
|
123
|
+
CONFIG_KEY_STREAM,
|
|
124
|
+
CONFIG_KEY_CHECKPOINT_MAP,
|
|
125
|
+
CONFIG_KEY_RESUMING,
|
|
126
|
+
CONFIG_KEY_REPLAY_STATE,
|
|
127
|
+
CONFIG_KEY_TASK_ID,
|
|
128
|
+
CONFIG_KEY_CHECKPOINT_MAP,
|
|
129
|
+
CONFIG_KEY_CHECKPOINT_ID,
|
|
130
|
+
CONFIG_KEY_CHECKPOINT_NS,
|
|
131
|
+
CONFIG_KEY_TIMED_ATTEMPT_OBSERVER,
|
|
132
|
+
CONFIG_KEY_RESUME_MAP,
|
|
133
|
+
CONFIG_KEY_STREAM_MESSAGES_V2,
|
|
134
|
+
# other constants
|
|
135
|
+
PUSH,
|
|
136
|
+
PULL,
|
|
137
|
+
NS_SEP,
|
|
138
|
+
NS_END,
|
|
139
|
+
CONF,
|
|
140
|
+
}
|