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
|
File without changes
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Msgpack deserialization safety controls.
|
|
2
|
+
|
|
3
|
+
Set ``COCO_GRAPH_STRICT_MSGPACK=true`` to restrict checkpoint deserialization
|
|
4
|
+
to the types listed in ``SAFE_MSGPACK_TYPES``. Without this, any Python
|
|
5
|
+
callable stored in checkpoint data will be imported and executed on load.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from collections.abc import Iterable
|
|
10
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
STRICT_MSGPACK_ENABLED = os.getenv("COCO_GRAPH_STRICT_MSGPACK", "false").lower() in (
|
|
13
|
+
"1",
|
|
14
|
+
"true",
|
|
15
|
+
"yes",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_SENTINEL = cast(None, object())
|
|
20
|
+
|
|
21
|
+
SAFE_MSGPACK_TYPES: frozenset[tuple[str, ...]] = frozenset(
|
|
22
|
+
{
|
|
23
|
+
# datetime types
|
|
24
|
+
("datetime", "datetime"),
|
|
25
|
+
("datetime", "date"),
|
|
26
|
+
("datetime", "time"),
|
|
27
|
+
("datetime", "timedelta"),
|
|
28
|
+
("datetime", "timezone"),
|
|
29
|
+
# uuid
|
|
30
|
+
("uuid", "UUID"),
|
|
31
|
+
# numeric
|
|
32
|
+
("decimal", "Decimal"),
|
|
33
|
+
# collections
|
|
34
|
+
("builtins", "set"),
|
|
35
|
+
("builtins", "frozenset"),
|
|
36
|
+
("collections", "deque"),
|
|
37
|
+
# ip addresses
|
|
38
|
+
("ipaddress", "IPv4Address"),
|
|
39
|
+
("ipaddress", "IPv4Interface"),
|
|
40
|
+
("ipaddress", "IPv4Network"),
|
|
41
|
+
("ipaddress", "IPv6Address"),
|
|
42
|
+
("ipaddress", "IPv6Interface"),
|
|
43
|
+
("ipaddress", "IPv6Network"),
|
|
44
|
+
# pathlib
|
|
45
|
+
("pathlib", "Path"),
|
|
46
|
+
("pathlib", "PosixPath"),
|
|
47
|
+
("pathlib", "WindowsPath"),
|
|
48
|
+
# pathlib in Python 3.13+
|
|
49
|
+
("pathlib._local", "Path"),
|
|
50
|
+
("pathlib._local", "PosixPath"),
|
|
51
|
+
("pathlib._local", "WindowsPath"),
|
|
52
|
+
# zoneinfo
|
|
53
|
+
("zoneinfo", "ZoneInfo"),
|
|
54
|
+
# regex
|
|
55
|
+
("re", "compile"),
|
|
56
|
+
# trustcoco-core messages (safe container types used by graph state)
|
|
57
|
+
("coco_core.messages.base", "BaseMessage"),
|
|
58
|
+
("coco_core.messages.base", "BaseMessageChunk"),
|
|
59
|
+
("coco_core.messages.human", "HumanMessage"),
|
|
60
|
+
("coco_core.messages.human", "HumanMessageChunk"),
|
|
61
|
+
("coco_core.messages.ai", "AIMessage"),
|
|
62
|
+
("coco_core.messages.ai", "AIMessageChunk"),
|
|
63
|
+
("coco_core.messages.system", "SystemMessage"),
|
|
64
|
+
("coco_core.messages.system", "SystemMessageChunk"),
|
|
65
|
+
("coco_core.messages.chat", "ChatMessage"),
|
|
66
|
+
("coco_core.messages.chat", "ChatMessageChunk"),
|
|
67
|
+
("coco_core.messages.tool", "ToolMessage"),
|
|
68
|
+
("coco_core.messages.tool", "ToolMessageChunk"),
|
|
69
|
+
("coco_core.messages.function", "FunctionMessage"),
|
|
70
|
+
("coco_core.messages.function", "FunctionMessageChunk"),
|
|
71
|
+
("coco_core.messages.modifier", "RemoveMessage"),
|
|
72
|
+
# trustcoco-core document model
|
|
73
|
+
("coco_core.documents.base", "Document"),
|
|
74
|
+
# coco_graph
|
|
75
|
+
("coco_graph.types", "Send"),
|
|
76
|
+
("coco_graph.types", "TimeoutPolicy"),
|
|
77
|
+
("coco_graph.types", "Interrupt"),
|
|
78
|
+
("coco_graph.types", "Command"),
|
|
79
|
+
("coco_graph.types", "StateSnapshot"),
|
|
80
|
+
("coco_graph.types", "PregelTask"),
|
|
81
|
+
("coco_graph.types", "Overwrite"),
|
|
82
|
+
("coco_graph.store.base", "Item"),
|
|
83
|
+
("coco_graph.store.base", "GetOp"),
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Allowed (module, name, method) triples for EXT_METHOD_SINGLE_ARG.
|
|
88
|
+
# Only these specific method invocations are permitted during deserialization.
|
|
89
|
+
# This is separate from SAFE_MSGPACK_TYPES which only governs construction.
|
|
90
|
+
SAFE_MSGPACK_METHODS: frozenset[tuple[str, str, str]] = frozenset(
|
|
91
|
+
{
|
|
92
|
+
("datetime", "datetime", "fromisoformat"),
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
AllowedMsgpackModules = Iterable[tuple[str, ...] | type]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Protocol, runtime_checkable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UntypedSerializerProtocol(Protocol):
|
|
7
|
+
"""Protocol for serialization and deserialization of objects."""
|
|
8
|
+
|
|
9
|
+
def dumps(self, obj: Any) -> bytes: ...
|
|
10
|
+
|
|
11
|
+
def loads(self, data: bytes) -> Any: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class SerializerProtocol(Protocol):
|
|
16
|
+
"""Protocol for serialization and deserialization of objects.
|
|
17
|
+
|
|
18
|
+
- `dumps_typed`: Serialize an object to a tuple `(type, bytes)`.
|
|
19
|
+
- `loads_typed`: Deserialize an object from a tuple `(type, bytes)`.
|
|
20
|
+
|
|
21
|
+
Valid implementations include the `pickle`, `json` and `orjson` modules.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def dumps_typed(self, obj: Any) -> tuple[str, bytes]: ...
|
|
25
|
+
|
|
26
|
+
def loads_typed(self, data: tuple[str, bytes]) -> Any: ...
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SerializerCompat(SerializerProtocol):
|
|
30
|
+
def __init__(self, serde: UntypedSerializerProtocol) -> None:
|
|
31
|
+
self.serde = serde
|
|
32
|
+
|
|
33
|
+
def dumps_typed(self, obj: Any) -> tuple[str, bytes]:
|
|
34
|
+
return type(obj).__name__, self.serde.dumps(obj)
|
|
35
|
+
|
|
36
|
+
def loads_typed(self, data: tuple[str, bytes]) -> Any:
|
|
37
|
+
return self.serde.loads(data[1])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def maybe_add_typed_methods(
|
|
41
|
+
serde: SerializerProtocol | UntypedSerializerProtocol,
|
|
42
|
+
) -> SerializerProtocol:
|
|
43
|
+
"""Wrap serde old serde implementations in a class with loads_typed and dumps_typed for backwards compatibility."""
|
|
44
|
+
|
|
45
|
+
if not isinstance(serde, SerializerProtocol):
|
|
46
|
+
return SerializerCompat(serde)
|
|
47
|
+
|
|
48
|
+
return serde
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class CipherProtocol(Protocol):
|
|
52
|
+
"""Protocol for encryption and decryption of data.
|
|
53
|
+
|
|
54
|
+
- `encrypt`: Encrypt plaintext.
|
|
55
|
+
- `decrypt`: Decrypt ciphertext.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def encrypt(self, plaintext: bytes) -> tuple[str, bytes]:
|
|
59
|
+
"""Encrypt plaintext. Returns a tuple `(cipher name, ciphertext)`."""
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
def decrypt(self, ciphername: str, ciphertext: bytes) -> bytes:
|
|
63
|
+
"""Decrypt ciphertext. Returns the plaintext."""
|
|
64
|
+
...
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from coco_graph.checkpoint.serde.base import CipherProtocol, SerializerProtocol
|
|
5
|
+
from coco_graph.checkpoint.serde.jsonplus import JsonPlusSerializer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EncryptedSerializer(SerializerProtocol):
|
|
9
|
+
"""Serializer that encrypts and decrypts data using an encryption protocol."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self, cipher: CipherProtocol, serde: SerializerProtocol = JsonPlusSerializer()
|
|
13
|
+
) -> None:
|
|
14
|
+
self.cipher = cipher
|
|
15
|
+
self.serde = serde
|
|
16
|
+
|
|
17
|
+
def dumps_typed(self, obj: Any) -> tuple[str, bytes]:
|
|
18
|
+
"""Serialize an object to a tuple `(type, bytes)` and encrypt the bytes."""
|
|
19
|
+
# serialize data
|
|
20
|
+
typ, data = self.serde.dumps_typed(obj)
|
|
21
|
+
# encrypt data
|
|
22
|
+
ciphername, ciphertext = self.cipher.encrypt(data)
|
|
23
|
+
# add cipher name to type
|
|
24
|
+
return f"{typ}+{ciphername}", ciphertext
|
|
25
|
+
|
|
26
|
+
def loads_typed(self, data: tuple[str, bytes]) -> Any:
|
|
27
|
+
enc_cipher, ciphertext = data
|
|
28
|
+
# unencrypted data
|
|
29
|
+
if "+" not in enc_cipher:
|
|
30
|
+
return self.serde.loads_typed(data)
|
|
31
|
+
# extract cipher name
|
|
32
|
+
typ, ciphername = enc_cipher.split("+", 1)
|
|
33
|
+
# decrypt data
|
|
34
|
+
decrypted_data = self.cipher.decrypt(ciphername, ciphertext)
|
|
35
|
+
# deserialize data
|
|
36
|
+
return self.serde.loads_typed((typ, decrypted_data))
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_pycryptodome_aes(
|
|
40
|
+
cls, serde: SerializerProtocol = JsonPlusSerializer(), **kwargs: Any
|
|
41
|
+
) -> "EncryptedSerializer":
|
|
42
|
+
"""Create an `EncryptedSerializer` using AES encryption."""
|
|
43
|
+
try:
|
|
44
|
+
from Crypto.Cipher import AES
|
|
45
|
+
except ImportError:
|
|
46
|
+
raise ImportError(
|
|
47
|
+
"Pycryptodome is not installed. Please install it with `pip install pycryptodome`."
|
|
48
|
+
) from None
|
|
49
|
+
|
|
50
|
+
# check if AES key is provided
|
|
51
|
+
if "key" in kwargs:
|
|
52
|
+
key: bytes = kwargs.pop("key")
|
|
53
|
+
else:
|
|
54
|
+
key_str = os.getenv("COCO_GRAPH_AES_KEY")
|
|
55
|
+
if key_str is None:
|
|
56
|
+
raise ValueError("COCO_GRAPH_AES_KEY environment variable is not set.")
|
|
57
|
+
key = key_str.encode()
|
|
58
|
+
if len(key) not in (16, 24, 32):
|
|
59
|
+
raise ValueError("COCO_GRAPH_AES_KEY must be 16, 24, or 32 bytes long.")
|
|
60
|
+
|
|
61
|
+
# set default mode to EAX if not provided
|
|
62
|
+
if kwargs.get("mode") is None:
|
|
63
|
+
kwargs["mode"] = AES.MODE_EAX
|
|
64
|
+
|
|
65
|
+
class PycryptodomeAesCipher(CipherProtocol):
|
|
66
|
+
def encrypt(self, plaintext: bytes) -> tuple[str, bytes]:
|
|
67
|
+
cipher = AES.new(key, **kwargs)
|
|
68
|
+
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
|
|
69
|
+
return "aes", cipher.nonce + tag + ciphertext
|
|
70
|
+
|
|
71
|
+
def decrypt(self, ciphername: str, ciphertext: bytes) -> bytes:
|
|
72
|
+
assert ciphername == "aes", f"Unsupported cipher: {ciphername}"
|
|
73
|
+
nonce = ciphertext[:16]
|
|
74
|
+
tag = ciphertext[16:32]
|
|
75
|
+
actual_ciphertext = ciphertext[32:]
|
|
76
|
+
|
|
77
|
+
cipher = AES.new(key, **kwargs, nonce=nonce)
|
|
78
|
+
return cipher.decrypt_and_verify(actual_ciphertext, tag)
|
|
79
|
+
|
|
80
|
+
return cls(PycryptodomeAesCipher(), serde)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from threading import Lock
|
|
6
|
+
from typing import TypedDict
|
|
7
|
+
|
|
8
|
+
from typing_extensions import NotRequired
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SerdeEvent(TypedDict):
|
|
14
|
+
kind: str
|
|
15
|
+
module: str
|
|
16
|
+
name: str
|
|
17
|
+
method: NotRequired[str]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
SerdeEventListener = Callable[[SerdeEvent], None]
|
|
21
|
+
|
|
22
|
+
_listeners: list[SerdeEventListener] = []
|
|
23
|
+
_listeners_lock = Lock()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def register_serde_event_listener(listener: SerdeEventListener) -> Callable[[], None]:
|
|
27
|
+
"""Register a listener for serde allowlist events."""
|
|
28
|
+
with _listeners_lock:
|
|
29
|
+
_listeners.append(listener)
|
|
30
|
+
|
|
31
|
+
def unregister() -> None:
|
|
32
|
+
with _listeners_lock:
|
|
33
|
+
try:
|
|
34
|
+
_listeners.remove(listener)
|
|
35
|
+
except ValueError:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
return unregister
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def emit_serde_event(event: SerdeEvent) -> None:
|
|
42
|
+
"""Emit a serde event to all listeners.
|
|
43
|
+
|
|
44
|
+
Listener failures are isolated and logged.
|
|
45
|
+
"""
|
|
46
|
+
with _listeners_lock:
|
|
47
|
+
listeners = tuple(_listeners)
|
|
48
|
+
for listener in listeners:
|
|
49
|
+
try:
|
|
50
|
+
listener(event)
|
|
51
|
+
except Exception:
|
|
52
|
+
logger.warning("Serde listener failed", exc_info=True)
|