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,620 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import inspect
|
|
5
|
+
import warnings
|
|
6
|
+
from collections.abc import Awaitable, Callable, Sequence
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import timedelta
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Generic,
|
|
12
|
+
TypeVar,
|
|
13
|
+
cast,
|
|
14
|
+
get_args,
|
|
15
|
+
get_origin,
|
|
16
|
+
overload,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from coco_graph.cache.base import BaseCache
|
|
20
|
+
from coco_graph.checkpoint.base import BaseCheckpointSaver
|
|
21
|
+
from coco_graph.store.base import BaseStore
|
|
22
|
+
from typing_extensions import Unpack
|
|
23
|
+
|
|
24
|
+
from coco_graph._internal import _serde
|
|
25
|
+
from coco_graph._internal._constants import CACHE_NS_WRITES, PREVIOUS
|
|
26
|
+
from coco_graph._internal._runnable import is_async_callable
|
|
27
|
+
from coco_graph._internal._timeout import (
|
|
28
|
+
coerce_timeout_policy,
|
|
29
|
+
sync_timeout_unsupported,
|
|
30
|
+
)
|
|
31
|
+
from coco_graph._internal._typing import MISSING, DeprecatedKwargs
|
|
32
|
+
from coco_graph.channels.ephemeral_value import EphemeralValue
|
|
33
|
+
from coco_graph.channels.last_value import LastValue
|
|
34
|
+
from coco_graph.constants import END, START
|
|
35
|
+
from coco_graph.pregel import Pregel
|
|
36
|
+
from coco_graph.pregel._call import (
|
|
37
|
+
P,
|
|
38
|
+
SyncAsyncFuture,
|
|
39
|
+
T,
|
|
40
|
+
_call_with_options,
|
|
41
|
+
get_runnable_for_entrypoint,
|
|
42
|
+
identifier,
|
|
43
|
+
)
|
|
44
|
+
from coco_graph.pregel._read import PregelNode
|
|
45
|
+
from coco_graph.pregel._write import ChannelWrite, ChannelWriteEntry
|
|
46
|
+
from coco_graph.types import (
|
|
47
|
+
_DC_KWARGS,
|
|
48
|
+
CachePolicy,
|
|
49
|
+
RetryPolicy,
|
|
50
|
+
StreamMode,
|
|
51
|
+
TimeoutPolicy,
|
|
52
|
+
)
|
|
53
|
+
from coco_graph.typing import ContextT
|
|
54
|
+
from coco_graph.warnings import CocoGraphDeprecatedSinceV05, CocoGraphDeprecatedSinceV10
|
|
55
|
+
|
|
56
|
+
__all__ = ("task", "entrypoint")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class _TaskFunction(Generic[P, T]):
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
func: Callable[P, Awaitable[T]] | Callable[P, T],
|
|
63
|
+
*,
|
|
64
|
+
retry_policy: Sequence[RetryPolicy],
|
|
65
|
+
cache_policy: CachePolicy[Callable[P, str | bytes]] | None = None,
|
|
66
|
+
timeout: TimeoutPolicy | None = None,
|
|
67
|
+
name: str | None = None,
|
|
68
|
+
) -> None:
|
|
69
|
+
if name is not None:
|
|
70
|
+
if hasattr(func, "__func__"):
|
|
71
|
+
# handle class methods
|
|
72
|
+
# NOTE: we're modifying the instance method to avoid modifying
|
|
73
|
+
# the original class method in case it's shared across multiple tasks
|
|
74
|
+
instance_method = functools.partial(func.__func__, func.__self__) # type: ignore [union-attr]
|
|
75
|
+
instance_method.__name__ = name # type: ignore [attr-defined]
|
|
76
|
+
func = instance_method
|
|
77
|
+
else:
|
|
78
|
+
# handle regular functions / partials / callable classes, etc.
|
|
79
|
+
func.__name__ = name
|
|
80
|
+
self.func = func
|
|
81
|
+
self.retry_policy = retry_policy
|
|
82
|
+
self.cache_policy = cache_policy
|
|
83
|
+
self.timeout = timeout
|
|
84
|
+
functools.update_wrapper(self, func)
|
|
85
|
+
|
|
86
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> SyncAsyncFuture[T]:
|
|
87
|
+
return _call_with_options(
|
|
88
|
+
self.func,
|
|
89
|
+
args,
|
|
90
|
+
kwargs,
|
|
91
|
+
retry_policy=self.retry_policy,
|
|
92
|
+
cache_policy=self.cache_policy,
|
|
93
|
+
timeout=self.timeout,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def clear_cache(self, cache: BaseCache) -> None:
|
|
97
|
+
"""Clear the cache for this task."""
|
|
98
|
+
if self.cache_policy is not None:
|
|
99
|
+
cache.clear(((CACHE_NS_WRITES, identifier(self.func) or "__dynamic__"),))
|
|
100
|
+
|
|
101
|
+
async def aclear_cache(self, cache: BaseCache) -> None:
|
|
102
|
+
"""Clear the cache for this task."""
|
|
103
|
+
if self.cache_policy is not None:
|
|
104
|
+
await cache.aclear(
|
|
105
|
+
((CACHE_NS_WRITES, identifier(self.func) or "__dynamic__"),)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@overload
|
|
110
|
+
def task(
|
|
111
|
+
__func_or_none__: None = None,
|
|
112
|
+
*,
|
|
113
|
+
name: str | None = None,
|
|
114
|
+
retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
|
|
115
|
+
cache_policy: CachePolicy[Callable[P, str | bytes]] | None = None,
|
|
116
|
+
timeout: float | timedelta | TimeoutPolicy | None = None,
|
|
117
|
+
**kwargs: Unpack[DeprecatedKwargs],
|
|
118
|
+
) -> Callable[
|
|
119
|
+
[Callable[P, Awaitable[T]] | Callable[P, T]],
|
|
120
|
+
_TaskFunction[P, T],
|
|
121
|
+
]: ...
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@overload
|
|
125
|
+
def task(__func_or_none__: Callable[P, Awaitable[T]]) -> _TaskFunction[P, T]: ...
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@overload
|
|
129
|
+
def task(__func_or_none__: Callable[P, T]) -> _TaskFunction[P, T]: ...
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def task(
|
|
133
|
+
__func_or_none__: Callable[P, Awaitable[T]] | Callable[P, T] | None = None,
|
|
134
|
+
*,
|
|
135
|
+
name: str | None = None,
|
|
136
|
+
retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
|
|
137
|
+
cache_policy: CachePolicy[Callable[P, str | bytes]] | None = None,
|
|
138
|
+
timeout: float | timedelta | TimeoutPolicy | None = None,
|
|
139
|
+
**kwargs: Unpack[DeprecatedKwargs],
|
|
140
|
+
) -> (
|
|
141
|
+
Callable[[Callable[P, Awaitable[T]] | Callable[P, T]], _TaskFunction[P, T]]
|
|
142
|
+
| _TaskFunction[P, T]
|
|
143
|
+
):
|
|
144
|
+
"""Define a CocoGraph task using the `task` decorator.
|
|
145
|
+
|
|
146
|
+
!!! important "Requires python 3.11 or higher for async functions"
|
|
147
|
+
The `task` decorator supports both sync and async functions. To use async
|
|
148
|
+
functions, ensure that you are using Python 3.11 or higher.
|
|
149
|
+
|
|
150
|
+
Tasks can only be called from within an [`entrypoint`][coco_graph.func.entrypoint] or
|
|
151
|
+
from within a `StateGraph`. A task can be called like a regular function with the
|
|
152
|
+
following differences:
|
|
153
|
+
|
|
154
|
+
- When a checkpointer is enabled, the function inputs and outputs must be serializable.
|
|
155
|
+
- The decorated function can only be called from within an entrypoint or `StateGraph`.
|
|
156
|
+
- Calling the function produces a future. This makes it easy to parallelize tasks.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
name: An optional name for the task. If not provided, the function name will be used.
|
|
160
|
+
retry_policy: An optional retry policy (or list of policies) to use for the task in case of a failure.
|
|
161
|
+
cache_policy: An optional cache policy to use for the task. This allows caching of the task results.
|
|
162
|
+
timeout: Timeout for each task attempt. A number or `timedelta` is a hard
|
|
163
|
+
wall-clock cap and is not refreshed. Use `TimeoutPolicy` to configure
|
|
164
|
+
both a wall-clock `run_timeout` and an `idle_timeout` refreshed by
|
|
165
|
+
progress signals. For long-running work that doesn't naturally emit
|
|
166
|
+
progress, call `runtime.heartbeat()` from inside the task. When the
|
|
167
|
+
timeout fires, `NodeTimeoutError` is raised and the retry policy (if
|
|
168
|
+
any) decides whether to retry. Supported only for async tasks; sync
|
|
169
|
+
tasks cannot be safely cancelled in-process.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
A callable function when used as a decorator.
|
|
173
|
+
|
|
174
|
+
Example: Sync Task
|
|
175
|
+
```python
|
|
176
|
+
from coco_graph.func import entrypoint, task
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@task
|
|
180
|
+
def add_one_task(a: int) -> int:
|
|
181
|
+
return a + 1
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@entrypoint()
|
|
185
|
+
def add_one(numbers: list[int]) -> list[int]:
|
|
186
|
+
futures = [add_one_task(n) for n in numbers]
|
|
187
|
+
results = [f.result() for f in futures]
|
|
188
|
+
return results
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# Call the entrypoint
|
|
192
|
+
add_one.invoke([1, 2, 3]) # Returns [2, 3, 4]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Example: Async Task
|
|
196
|
+
```python
|
|
197
|
+
import asyncio
|
|
198
|
+
from coco_graph.func import entrypoint, task
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@task
|
|
202
|
+
async def add_one_task(a: int) -> int:
|
|
203
|
+
return a + 1
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@entrypoint()
|
|
207
|
+
async def add_one(numbers: list[int]) -> list[int]:
|
|
208
|
+
futures = [add_one_task(n) for n in numbers]
|
|
209
|
+
return asyncio.gather(*futures)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# Call the entrypoint
|
|
213
|
+
await add_one.ainvoke([1, 2, 3]) # Returns [2, 3, 4]
|
|
214
|
+
```
|
|
215
|
+
"""
|
|
216
|
+
if (retry := kwargs.get("retry", MISSING)) is not MISSING:
|
|
217
|
+
warnings.warn(
|
|
218
|
+
"`retry` is deprecated and will be removed. Please use `retry_policy` instead.",
|
|
219
|
+
category=CocoGraphDeprecatedSinceV05,
|
|
220
|
+
stacklevel=2,
|
|
221
|
+
)
|
|
222
|
+
if retry_policy is None:
|
|
223
|
+
retry_policy = retry # type: ignore[assignment]
|
|
224
|
+
timeout_policy = coerce_timeout_policy(timeout)
|
|
225
|
+
|
|
226
|
+
retry_policies: Sequence[RetryPolicy] = (
|
|
227
|
+
()
|
|
228
|
+
if retry_policy is None
|
|
229
|
+
else (retry_policy,)
|
|
230
|
+
if isinstance(retry_policy, RetryPolicy)
|
|
231
|
+
else retry_policy
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def decorator(
|
|
235
|
+
func: Callable[P, Awaitable[T]] | Callable[P, T],
|
|
236
|
+
) -> Callable[P, SyncAsyncFuture[T]]:
|
|
237
|
+
if timeout_policy is not None and not is_async_callable(func):
|
|
238
|
+
name_ = name or getattr(func, "__name__", func.__class__.__name__)
|
|
239
|
+
raise sync_timeout_unsupported(str(name_), kind="Task")
|
|
240
|
+
return _TaskFunction(
|
|
241
|
+
func,
|
|
242
|
+
retry_policy=retry_policies,
|
|
243
|
+
cache_policy=cache_policy,
|
|
244
|
+
timeout=timeout_policy,
|
|
245
|
+
name=name,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if __func_or_none__ is not None:
|
|
249
|
+
return decorator(__func_or_none__)
|
|
250
|
+
|
|
251
|
+
return decorator
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
R = TypeVar("R")
|
|
255
|
+
S = TypeVar("S")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# The decorator was wrapped in a class to support the `final` attribute.
|
|
259
|
+
# In this form, the `final` attribute should play nicely with IDE autocompletion,
|
|
260
|
+
# and type checking tools.
|
|
261
|
+
# In addition, we'll be able to surface this information in the API Reference.
|
|
262
|
+
class entrypoint(Generic[ContextT]):
|
|
263
|
+
"""Define a CocoGraph workflow using the `entrypoint` decorator.
|
|
264
|
+
|
|
265
|
+
### Function signature
|
|
266
|
+
|
|
267
|
+
The decorated function must accept a **single parameter**, which serves as the input
|
|
268
|
+
to the function. This input parameter can be of any type. Use a dictionary
|
|
269
|
+
to pass **multiple parameters** to the function.
|
|
270
|
+
|
|
271
|
+
### Injectable parameters
|
|
272
|
+
|
|
273
|
+
The decorated function can request access to additional parameters
|
|
274
|
+
that will be injected automatically at run time. These parameters include:
|
|
275
|
+
|
|
276
|
+
| Parameter | Description |
|
|
277
|
+
|------------------|------------------------------------------------------------------------------------------------------|
|
|
278
|
+
| **`config`** | A configuration object (aka `RunnableConfig`) that holds run-time configuration values. |
|
|
279
|
+
| **`previous`** | The previous return value for the given thread (available only when a checkpointer is provided). |
|
|
280
|
+
| **`runtime`** | A `Runtime` object that contains information about the current run, including context, store, writer |
|
|
281
|
+
|
|
282
|
+
The entrypoint decorator can be applied to sync functions or async functions.
|
|
283
|
+
|
|
284
|
+
### State management
|
|
285
|
+
|
|
286
|
+
The **`previous`** parameter can be used to access the return value of the previous
|
|
287
|
+
invocation of the entrypoint on the same thread id. This value is only available
|
|
288
|
+
when a checkpointer is provided.
|
|
289
|
+
|
|
290
|
+
If you want **`previous`** to be different from the return value, you can use the
|
|
291
|
+
`entrypoint.final` object to return a value while saving a different value to the
|
|
292
|
+
checkpoint.
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
checkpointer: Specify a checkpointer to create a workflow that can persist
|
|
296
|
+
its state across runs.
|
|
297
|
+
store: A generalized key-value store. Some implementations may support
|
|
298
|
+
semantic search capabilities through an optional `index` configuration.
|
|
299
|
+
cache: A cache to use for caching the results of the workflow.
|
|
300
|
+
context_schema: Specifies the schema for the context object that will be
|
|
301
|
+
passed to the workflow.
|
|
302
|
+
cache_policy: A cache policy to use for caching the results of the workflow.
|
|
303
|
+
retry_policy: A retry policy (or list of policies) to use for the workflow in case of a failure.
|
|
304
|
+
timeout: Timeout for each workflow attempt. A number or `timedelta` is a
|
|
305
|
+
hard wall-clock cap and is not refreshed. Use `TimeoutPolicy` to
|
|
306
|
+
configure both a wall-clock `run_timeout` and an `idle_timeout`
|
|
307
|
+
refreshed by progress signals. For long-running work that doesn't
|
|
308
|
+
naturally emit progress, call `runtime.heartbeat()` from inside the
|
|
309
|
+
workflow. When the timeout fires, `NodeTimeoutError` is raised and
|
|
310
|
+
the retry policy (if any) decides whether to retry. Supported only
|
|
311
|
+
for async workflows; sync workflows cannot be safely cancelled
|
|
312
|
+
in-process.
|
|
313
|
+
|
|
314
|
+
!!! warning "`config_schema` Deprecated"
|
|
315
|
+
The `config_schema` parameter is deprecated in v0.6.0 and support will be removed in v2.0.0.
|
|
316
|
+
Please use `context_schema` instead to specify the schema for run-scoped context.
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
Example: Using entrypoint and tasks
|
|
320
|
+
```python
|
|
321
|
+
import time
|
|
322
|
+
|
|
323
|
+
from coco_graph.func import entrypoint, task
|
|
324
|
+
from coco_graph.types import interrupt, Command
|
|
325
|
+
from coco_graph.checkpoint.memory import InMemorySaver
|
|
326
|
+
|
|
327
|
+
@task
|
|
328
|
+
def compose_essay(topic: str) -> str:
|
|
329
|
+
time.sleep(1.0) # Simulate slow operation
|
|
330
|
+
return f"An essay about {topic}"
|
|
331
|
+
|
|
332
|
+
@entrypoint(checkpointer=InMemorySaver())
|
|
333
|
+
def review_workflow(topic: str) -> dict:
|
|
334
|
+
\"\"\"Manages the workflow for generating and reviewing an essay.
|
|
335
|
+
|
|
336
|
+
The workflow includes:
|
|
337
|
+
1. Generating an essay about the given topic.
|
|
338
|
+
2. Interrupting the workflow for human review of the generated essay.
|
|
339
|
+
|
|
340
|
+
Upon resuming the workflow, compose_essay task will not be re-executed
|
|
341
|
+
as its result is cached by the checkpointer.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
topic: The subject of the essay.
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
dict: A dictionary containing the generated essay and the human review.
|
|
348
|
+
\"\"\"
|
|
349
|
+
essay_future = compose_essay(topic)
|
|
350
|
+
essay = essay_future.result()
|
|
351
|
+
human_review = interrupt({
|
|
352
|
+
\"question\": \"Please provide a review\",
|
|
353
|
+
\"essay\": essay
|
|
354
|
+
})
|
|
355
|
+
return {
|
|
356
|
+
\"essay\": essay,
|
|
357
|
+
\"review\": human_review,
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
# Example configuration for the workflow
|
|
361
|
+
config = {
|
|
362
|
+
\"configurable\": {
|
|
363
|
+
\"thread_id\": \"some_thread\"
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
# Topic for the essay
|
|
368
|
+
topic = \"cats\"
|
|
369
|
+
|
|
370
|
+
# Stream the workflow to generate the essay and await human review
|
|
371
|
+
for result in review_workflow.stream(topic, config):
|
|
372
|
+
print(result)
|
|
373
|
+
|
|
374
|
+
# Example human review provided after the interrupt
|
|
375
|
+
human_review = \"This essay is great.\"
|
|
376
|
+
|
|
377
|
+
# Resume the workflow with the provided human review
|
|
378
|
+
for result in review_workflow.stream(Command(resume=human_review), config):
|
|
379
|
+
print(result)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Example: Accessing the previous return value
|
|
383
|
+
When a checkpointer is enabled the function can access the previous return value
|
|
384
|
+
of the previous invocation on the same thread id.
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from typing import Optional
|
|
388
|
+
|
|
389
|
+
from coco_graph.checkpoint.memory import MemorySaver
|
|
390
|
+
|
|
391
|
+
from coco_graph.func import entrypoint
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@entrypoint(checkpointer=InMemorySaver())
|
|
395
|
+
def my_workflow(input_data: str, previous: Optional[str] = None) -> str:
|
|
396
|
+
return "world"
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
config = {"configurable": {"thread_id": "some_thread"}}
|
|
400
|
+
my_workflow.invoke("hello", config)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Example: Using `entrypoint.final` to save a value
|
|
404
|
+
The `entrypoint.final` object allows you to return a value while saving
|
|
405
|
+
a different value to the checkpoint. This value will be accessible
|
|
406
|
+
in the next invocation of the entrypoint via the `previous` parameter, as
|
|
407
|
+
long as the same thread id is used.
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
from typing import Any
|
|
411
|
+
|
|
412
|
+
from coco_graph.checkpoint.memory import MemorySaver
|
|
413
|
+
|
|
414
|
+
from coco_graph.func import entrypoint
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@entrypoint(checkpointer=InMemorySaver())
|
|
418
|
+
def my_workflow(
|
|
419
|
+
number: int,
|
|
420
|
+
*,
|
|
421
|
+
previous: Any = None,
|
|
422
|
+
) -> entrypoint.final[int, int]:
|
|
423
|
+
previous = previous or 0
|
|
424
|
+
# This will return the previous value to the caller, saving
|
|
425
|
+
# 2 * number to the checkpoint, which will be used in the next invocation
|
|
426
|
+
# for the `previous` parameter.
|
|
427
|
+
return entrypoint.final(value=previous, save=2 * number)
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
config = {"configurable": {"thread_id": "some_thread"}}
|
|
431
|
+
|
|
432
|
+
my_workflow.invoke(3, config) # 0 (previous was None)
|
|
433
|
+
my_workflow.invoke(1, config) # 6 (previous was 3 * 2 from the previous invocation)
|
|
434
|
+
```
|
|
435
|
+
"""
|
|
436
|
+
|
|
437
|
+
def __init__(
|
|
438
|
+
self,
|
|
439
|
+
checkpointer: BaseCheckpointSaver | None = None,
|
|
440
|
+
store: BaseStore | None = None,
|
|
441
|
+
cache: BaseCache | None = None,
|
|
442
|
+
context_schema: type[ContextT] | None = None,
|
|
443
|
+
cache_policy: CachePolicy | None = None,
|
|
444
|
+
retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
|
|
445
|
+
timeout: float | timedelta | TimeoutPolicy | None = None,
|
|
446
|
+
**kwargs: Unpack[DeprecatedKwargs],
|
|
447
|
+
) -> None:
|
|
448
|
+
"""Initialize the entrypoint decorator."""
|
|
449
|
+
if (config_schema := kwargs.get("config_schema", MISSING)) is not MISSING:
|
|
450
|
+
warnings.warn(
|
|
451
|
+
"`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
|
|
452
|
+
category=CocoGraphDeprecatedSinceV10,
|
|
453
|
+
stacklevel=2,
|
|
454
|
+
)
|
|
455
|
+
if context_schema is None:
|
|
456
|
+
context_schema = cast(type[ContextT], config_schema)
|
|
457
|
+
|
|
458
|
+
if (retry := kwargs.get("retry", MISSING)) is not MISSING:
|
|
459
|
+
warnings.warn(
|
|
460
|
+
"`retry` is deprecated and will be removed. Please use `retry_policy` instead.",
|
|
461
|
+
category=CocoGraphDeprecatedSinceV05,
|
|
462
|
+
stacklevel=2,
|
|
463
|
+
)
|
|
464
|
+
if retry_policy is None:
|
|
465
|
+
retry_policy = cast("RetryPolicy | Sequence[RetryPolicy]", retry)
|
|
466
|
+
|
|
467
|
+
self.checkpointer = checkpointer
|
|
468
|
+
self.store = store
|
|
469
|
+
self.cache = cache
|
|
470
|
+
self.cache_policy = cache_policy
|
|
471
|
+
self.retry_policy = retry_policy
|
|
472
|
+
self.timeout = coerce_timeout_policy(timeout)
|
|
473
|
+
self.context_schema = context_schema
|
|
474
|
+
|
|
475
|
+
@dataclass(**_DC_KWARGS)
|
|
476
|
+
class final(Generic[R, S]):
|
|
477
|
+
"""A primitive that can be returned from an entrypoint.
|
|
478
|
+
|
|
479
|
+
This primitive allows to save a value to the checkpointer distinct from the
|
|
480
|
+
return value from the entrypoint.
|
|
481
|
+
|
|
482
|
+
Example: Decoupling the return value and the save value
|
|
483
|
+
```python
|
|
484
|
+
from coco_graph.checkpoint.memory import InMemorySaver
|
|
485
|
+
from coco_graph.func import entrypoint
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@entrypoint(checkpointer=InMemorySaver())
|
|
489
|
+
def my_workflow(
|
|
490
|
+
number: int,
|
|
491
|
+
*,
|
|
492
|
+
previous: Any = None,
|
|
493
|
+
) -> entrypoint.final[int, int]:
|
|
494
|
+
previous = previous or 0
|
|
495
|
+
# This will return the previous value to the caller, saving
|
|
496
|
+
# 2 * number to the checkpoint, which will be used in the next invocation
|
|
497
|
+
# for the `previous` parameter.
|
|
498
|
+
return entrypoint.final(value=previous, save=2 * number)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
config = {"configurable": {"thread_id": "1"}}
|
|
502
|
+
|
|
503
|
+
my_workflow.invoke(3, config) # 0 (previous was None)
|
|
504
|
+
my_workflow.invoke(1, config) # 6 (previous was 3 * 2 from the previous invocation)
|
|
505
|
+
```
|
|
506
|
+
"""
|
|
507
|
+
|
|
508
|
+
value: R
|
|
509
|
+
"""Value to return. A value will always be returned even if it is `None`."""
|
|
510
|
+
save: S
|
|
511
|
+
"""The value for the state for the next checkpoint.
|
|
512
|
+
|
|
513
|
+
A value will always be saved even if it is `None`.
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
def __call__(self, func: Callable[..., Any]) -> Pregel:
|
|
517
|
+
"""Convert a function into a Pregel graph.
|
|
518
|
+
|
|
519
|
+
Args:
|
|
520
|
+
func: The function to convert. Support both sync and async functions.
|
|
521
|
+
|
|
522
|
+
Returns:
|
|
523
|
+
A Pregel graph.
|
|
524
|
+
"""
|
|
525
|
+
# wrap generators in a function that writes to StreamWriter
|
|
526
|
+
if inspect.isgeneratorfunction(func) or inspect.isasyncgenfunction(func):
|
|
527
|
+
raise NotImplementedError(
|
|
528
|
+
"Generators are not supported in the Functional API."
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
bound = get_runnable_for_entrypoint(func)
|
|
532
|
+
stream_mode: StreamMode = "updates"
|
|
533
|
+
|
|
534
|
+
# get input and output types
|
|
535
|
+
sig = inspect.signature(func)
|
|
536
|
+
first_parameter_name = next(iter(sig.parameters.keys()), None)
|
|
537
|
+
if not first_parameter_name:
|
|
538
|
+
raise ValueError("Entrypoint function must have at least one parameter")
|
|
539
|
+
input_type = (
|
|
540
|
+
sig.parameters[first_parameter_name].annotation
|
|
541
|
+
if sig.parameters[first_parameter_name].annotation
|
|
542
|
+
is not inspect.Signature.empty
|
|
543
|
+
else Any
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
def _pluck_return_value(value: Any) -> Any:
|
|
547
|
+
"""Extract the return_ value the entrypoint.final object or passthrough."""
|
|
548
|
+
return value.value if isinstance(value, entrypoint.final) else value
|
|
549
|
+
|
|
550
|
+
def _pluck_save_value(value: Any) -> Any:
|
|
551
|
+
"""Get save value from the entrypoint.final object or passthrough."""
|
|
552
|
+
return value.save if isinstance(value, entrypoint.final) else value
|
|
553
|
+
|
|
554
|
+
output_type, save_type = Any, Any
|
|
555
|
+
if sig.return_annotation is not inspect.Signature.empty:
|
|
556
|
+
# User does not parameterize entrypoint.final properly
|
|
557
|
+
if (
|
|
558
|
+
sig.return_annotation is entrypoint.final
|
|
559
|
+
): # Un-parameterized entrypoint.final
|
|
560
|
+
output_type = save_type = Any
|
|
561
|
+
else:
|
|
562
|
+
origin = get_origin(sig.return_annotation)
|
|
563
|
+
if origin is entrypoint.final:
|
|
564
|
+
type_annotations = get_args(sig.return_annotation)
|
|
565
|
+
if len(type_annotations) != 2:
|
|
566
|
+
raise TypeError(
|
|
567
|
+
"Please an annotation for both the return_ and "
|
|
568
|
+
"the save values."
|
|
569
|
+
"For example, `-> entrypoint.final[int, str]` would assign a "
|
|
570
|
+
"return_ a type of `int` and save the type `str`."
|
|
571
|
+
)
|
|
572
|
+
output_type, save_type = get_args(sig.return_annotation)
|
|
573
|
+
else:
|
|
574
|
+
output_type = save_type = sig.return_annotation
|
|
575
|
+
|
|
576
|
+
graph: Pregel[Any, ContextT, Any, Any] = Pregel(
|
|
577
|
+
nodes={
|
|
578
|
+
func.__name__: PregelNode(
|
|
579
|
+
bound=bound,
|
|
580
|
+
triggers=[START],
|
|
581
|
+
channels=START,
|
|
582
|
+
timeout=self.timeout,
|
|
583
|
+
writers=[
|
|
584
|
+
ChannelWrite(
|
|
585
|
+
[
|
|
586
|
+
ChannelWriteEntry(END, mapper=_pluck_return_value),
|
|
587
|
+
ChannelWriteEntry(PREVIOUS, mapper=_pluck_save_value),
|
|
588
|
+
]
|
|
589
|
+
)
|
|
590
|
+
],
|
|
591
|
+
)
|
|
592
|
+
},
|
|
593
|
+
channels={
|
|
594
|
+
START: EphemeralValue(input_type),
|
|
595
|
+
END: LastValue(output_type, END),
|
|
596
|
+
PREVIOUS: LastValue(save_type, PREVIOUS),
|
|
597
|
+
},
|
|
598
|
+
input_channels=START,
|
|
599
|
+
output_channels=END,
|
|
600
|
+
stream_channels=END,
|
|
601
|
+
stream_mode=stream_mode,
|
|
602
|
+
stream_eager=True,
|
|
603
|
+
checkpointer=self.checkpointer,
|
|
604
|
+
store=self.store,
|
|
605
|
+
cache=self.cache,
|
|
606
|
+
cache_policy=self.cache_policy,
|
|
607
|
+
retry_policy=self.retry_policy or (),
|
|
608
|
+
context_schema=self.context_schema,
|
|
609
|
+
)
|
|
610
|
+
if _serde.STRICT_MSGPACK_ENABLED:
|
|
611
|
+
serde_allowlist = _serde.build_serde_allowlist(
|
|
612
|
+
schemas=[input_type, output_type, save_type]
|
|
613
|
+
+ ([self.context_schema] if self.context_schema is not None else []),
|
|
614
|
+
channels=graph.channels,
|
|
615
|
+
)
|
|
616
|
+
graph._serde_allowlist = serde_allowlist
|
|
617
|
+
graph.checkpointer = _serde.apply_checkpointer_allowlist(
|
|
618
|
+
graph.checkpointer, serde_allowlist
|
|
619
|
+
)
|
|
620
|
+
return graph
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from coco_graph.constants import END, START
|
|
2
|
+
from coco_graph.graph.message import MessageGraph, MessagesState, add_messages
|
|
3
|
+
from coco_graph.graph.state import StateGraph
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
"END",
|
|
7
|
+
"START",
|
|
8
|
+
"StateGraph",
|
|
9
|
+
"add_messages",
|
|
10
|
+
"MessagesState",
|
|
11
|
+
"MessageGraph",
|
|
12
|
+
)
|