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.
Files changed (400) hide show
  1. coco/__init__.py +3 -0
  2. coco/agents/__init__.py +9 -0
  3. coco/agents/_subagent_transformer.py +307 -0
  4. coco/agents/factory.py +2164 -0
  5. coco/agents/middleware/__init__.py +100 -0
  6. coco/agents/middleware/_execution.py +385 -0
  7. coco/agents/middleware/_redaction.py +454 -0
  8. coco/agents/middleware/_retry.py +134 -0
  9. coco/agents/middleware/_trace_policy.py +61 -0
  10. coco/agents/middleware/context_editing.py +306 -0
  11. coco/agents/middleware/file_search.py +433 -0
  12. coco/agents/middleware/human_in_the_loop.py +680 -0
  13. coco/agents/middleware/internal_call_transformer.py +108 -0
  14. coco/agents/middleware/model_call_limit.py +267 -0
  15. coco/agents/middleware/model_fallback.py +417 -0
  16. coco/agents/middleware/model_retry.py +327 -0
  17. coco/agents/middleware/pii.py +878 -0
  18. coco/agents/middleware/provider_tool_search.py +307 -0
  19. coco/agents/middleware/shell_tool.py +949 -0
  20. coco/agents/middleware/summarization.py +910 -0
  21. coco/agents/middleware/todo.py +357 -0
  22. coco/agents/middleware/tool_call_limit.py +495 -0
  23. coco/agents/middleware/tool_emulator.py +251 -0
  24. coco/agents/middleware/tool_error.py +209 -0
  25. coco/agents/middleware/tool_retry.py +421 -0
  26. coco/agents/middleware/tool_selection.py +515 -0
  27. coco/agents/middleware/types.py +2201 -0
  28. coco/agents/structured_output.py +472 -0
  29. coco/chat_models/__init__.py +7 -0
  30. coco/chat_models/base.py +1082 -0
  31. coco/embeddings/__init__.py +18 -0
  32. coco/embeddings/base.py +279 -0
  33. coco/mcp/__init__.py +36 -0
  34. coco/mcp/adapter.py +245 -0
  35. coco/mcp/elicitation.py +394 -0
  36. coco/mcp/tools.py +307 -0
  37. coco/messages/__init__.py +73 -0
  38. coco/py.typed +0 -0
  39. coco/rate_limiters/__init__.py +13 -0
  40. coco/tools/__init__.py +22 -0
  41. coco/tools/tool_node.py +20 -0
  42. coco_anthropic/__init__.py +15 -0
  43. coco_anthropic/_client_utils.py +81 -0
  44. coco_anthropic/_compat.py +228 -0
  45. coco_anthropic/_sdk_compat.py +124 -0
  46. coco_anthropic/_version.py +3 -0
  47. coco_anthropic/chat_models.py +3349 -0
  48. coco_anthropic/data/__init__.py +1 -0
  49. coco_anthropic/data/_profiles.py +491 -0
  50. coco_anthropic/data/profile_augmentations.toml +69 -0
  51. coco_anthropic/experimental.py +140 -0
  52. coco_anthropic/llms.py +428 -0
  53. coco_anthropic/middleware/__init__.py +25 -0
  54. coco_anthropic/middleware/anthropic_tools.py +1197 -0
  55. coco_anthropic/middleware/bash.py +84 -0
  56. coco_anthropic/middleware/file_search.py +360 -0
  57. coco_anthropic/middleware/prompt_caching.py +276 -0
  58. coco_anthropic/output_parsers.py +93 -0
  59. coco_anthropic/py.typed +0 -0
  60. coco_core/__init__.py +20 -0
  61. coco_core/_api/__init__.py +87 -0
  62. coco_core/_api/beta_decorator.py +266 -0
  63. coco_core/_api/deprecation.py +637 -0
  64. coco_core/_api/internal.py +23 -0
  65. coco_core/_api/path.py +50 -0
  66. coco_core/_import_utils.py +41 -0
  67. coco_core/_protocol.py +625 -0
  68. coco_core/_security/__init__.py +36 -0
  69. coco_core/_security/_exceptions.py +9 -0
  70. coco_core/_security/_policy.py +313 -0
  71. coco_core/_security/_ssrf_protection.py +155 -0
  72. coco_core/_security/_transport.py +254 -0
  73. coco_core/agents.py +258 -0
  74. coco_core/caches.py +272 -0
  75. coco_core/callbacks/__init__.py +132 -0
  76. coco_core/callbacks/base.py +1229 -0
  77. coco_core/callbacks/file.py +266 -0
  78. coco_core/callbacks/manager.py +2826 -0
  79. coco_core/callbacks/stdout.py +123 -0
  80. coco_core/callbacks/streaming_stdout.py +154 -0
  81. coco_core/callbacks/usage.py +124 -0
  82. coco_core/chat_history.py +267 -0
  83. coco_core/chat_loaders.py +26 -0
  84. coco_core/chat_sessions.py +19 -0
  85. coco_core/cross_encoders.py +18 -0
  86. coco_core/document_loaders/__init__.py +36 -0
  87. coco_core/document_loaders/base.py +155 -0
  88. coco_core/document_loaders/blob_loaders.py +38 -0
  89. coco_core/documents/__init__.py +55 -0
  90. coco_core/documents/base.py +347 -0
  91. coco_core/documents/compressor.py +74 -0
  92. coco_core/documents/transformers.py +79 -0
  93. coco_core/embeddings/__init__.py +31 -0
  94. coco_core/embeddings/embeddings.py +78 -0
  95. coco_core/embeddings/fake.py +129 -0
  96. coco_core/env.py +22 -0
  97. coco_core/example_selectors/__init__.py +47 -0
  98. coco_core/example_selectors/base.py +60 -0
  99. coco_core/example_selectors/length_based.py +131 -0
  100. coco_core/example_selectors/semantic_similarity.py +366 -0
  101. coco_core/exceptions.py +166 -0
  102. coco_core/globals.py +72 -0
  103. coco_core/indexing/__init__.py +53 -0
  104. coco_core/indexing/api.py +954 -0
  105. coco_core/indexing/base.py +661 -0
  106. coco_core/indexing/in_memory.py +104 -0
  107. coco_core/language_models/__init__.py +116 -0
  108. coco_core/language_models/_compat_bridge.py +844 -0
  109. coco_core/language_models/_utils.py +343 -0
  110. coco_core/language_models/base.py +500 -0
  111. coco_core/language_models/chat_model_stream.py +1525 -0
  112. coco_core/language_models/chat_models.py +2748 -0
  113. coco_core/language_models/fake.py +137 -0
  114. coco_core/language_models/fake_chat_models.py +396 -0
  115. coco_core/language_models/llms.py +1569 -0
  116. coco_core/language_models/model_profile.py +183 -0
  117. coco_core/load/__init__.py +44 -0
  118. coco_core/load/_validation.py +191 -0
  119. coco_core/load/dump.py +120 -0
  120. coco_core/load/load.py +828 -0
  121. coco_core/load/mapping.py +1097 -0
  122. coco_core/load/serializable.py +406 -0
  123. coco_core/messages/__init__.py +198 -0
  124. coco_core/messages/ai.py +854 -0
  125. coco_core/messages/base.py +518 -0
  126. coco_core/messages/block_translators/__init__.py +112 -0
  127. coco_core/messages/block_translators/anthropic.py +534 -0
  128. coco_core/messages/block_translators/bedrock.py +108 -0
  129. coco_core/messages/block_translators/bedrock_converse.py +329 -0
  130. coco_core/messages/block_translators/coco_v0.py +303 -0
  131. coco_core/messages/block_translators/google_genai.py +610 -0
  132. coco_core/messages/block_translators/google_vertexai.py +21 -0
  133. coco_core/messages/block_translators/groq.py +157 -0
  134. coco_core/messages/block_translators/openai.py +1089 -0
  135. coco_core/messages/chat.py +64 -0
  136. coco_core/messages/content.py +1488 -0
  137. coco_core/messages/function.py +62 -0
  138. coco_core/messages/human.py +70 -0
  139. coco_core/messages/modifier.py +33 -0
  140. coco_core/messages/system.py +70 -0
  141. coco_core/messages/tool.py +418 -0
  142. coco_core/messages/utils.py +2442 -0
  143. coco_core/output_parsers/__init__.py +101 -0
  144. coco_core/output_parsers/base.py +361 -0
  145. coco_core/output_parsers/format_instructions.py +16 -0
  146. coco_core/output_parsers/json.py +139 -0
  147. coco_core/output_parsers/list.py +249 -0
  148. coco_core/output_parsers/openai_functions.py +324 -0
  149. coco_core/output_parsers/openai_tools.py +383 -0
  150. coco_core/output_parsers/pydantic.py +141 -0
  151. coco_core/output_parsers/string.py +63 -0
  152. coco_core/output_parsers/transform.py +175 -0
  153. coco_core/output_parsers/xml.py +301 -0
  154. coco_core/outputs/__init__.py +66 -0
  155. coco_core/outputs/chat_generation.py +147 -0
  156. coco_core/outputs/chat_result.py +39 -0
  157. coco_core/outputs/generation.py +80 -0
  158. coco_core/outputs/llm_result.py +112 -0
  159. coco_core/outputs/run_info.py +22 -0
  160. coco_core/prompt_values.py +161 -0
  161. coco_core/prompts/__init__.py +101 -0
  162. coco_core/prompts/base.py +508 -0
  163. coco_core/prompts/chat.py +1495 -0
  164. coco_core/prompts/dict.py +177 -0
  165. coco_core/prompts/few_shot.py +483 -0
  166. coco_core/prompts/few_shot_with_templates.py +239 -0
  167. coco_core/prompts/image.py +177 -0
  168. coco_core/prompts/loading.py +296 -0
  169. coco_core/prompts/message.py +97 -0
  170. coco_core/prompts/prompt.py +312 -0
  171. coco_core/prompts/string.py +399 -0
  172. coco_core/prompts/structured.py +214 -0
  173. coco_core/py.typed +0 -0
  174. coco_core/rate_limiters.py +254 -0
  175. coco_core/retrievers.py +328 -0
  176. coco_core/runnables/__init__.py +136 -0
  177. coco_core/runnables/base.py +6725 -0
  178. coco_core/runnables/branch.py +457 -0
  179. coco_core/runnables/config.py +712 -0
  180. coco_core/runnables/configurable.py +710 -0
  181. coco_core/runnables/fallbacks.py +663 -0
  182. coco_core/runnables/graph.py +741 -0
  183. coco_core/runnables/graph_ascii.py +366 -0
  184. coco_core/runnables/graph_mermaid.py +503 -0
  185. coco_core/runnables/graph_png.py +215 -0
  186. coco_core/runnables/history.py +631 -0
  187. coco_core/runnables/passthrough.py +849 -0
  188. coco_core/runnables/retry.py +379 -0
  189. coco_core/runnables/router.py +239 -0
  190. coco_core/runnables/schema.py +188 -0
  191. coco_core/runnables/utils.py +798 -0
  192. coco_core/stores.py +291 -0
  193. coco_core/structured_query.py +203 -0
  194. coco_core/sys_info.py +154 -0
  195. coco_core/tools/__init__.py +95 -0
  196. coco_core/tools/base.py +1948 -0
  197. coco_core/tools/convert.py +497 -0
  198. coco_core/tools/render.py +67 -0
  199. coco_core/tools/retriever.py +94 -0
  200. coco_core/tools/simple.py +208 -0
  201. coco_core/tools/structured.py +322 -0
  202. coco_core/tracers/__init__.py +47 -0
  203. coco_core/tracers/_compat.py +95 -0
  204. coco_core/tracers/_context.py +337 -0
  205. coco_core/tracers/_streaming.py +53 -0
  206. coco_core/tracers/base.py +955 -0
  207. coco_core/tracers/coco.py +279 -0
  208. coco_core/tracers/context.py +205 -0
  209. coco_core/tracers/core.py +766 -0
  210. coco_core/tracers/event_stream.py +1101 -0
  211. coco_core/tracers/log_stream.py +765 -0
  212. coco_core/tracers/memory_stream.py +200 -0
  213. coco_core/tracers/root_listeners.py +130 -0
  214. coco_core/tracers/run_collector.py +40 -0
  215. coco_core/tracers/schemas.py +14 -0
  216. coco_core/tracers/stdout.py +205 -0
  217. coco_core/utils/__init__.py +111 -0
  218. coco_core/utils/_gateway.py +274 -0
  219. coco_core/utils/_merge.py +218 -0
  220. coco_core/utils/aiter.py +357 -0
  221. coco_core/utils/env.py +86 -0
  222. coco_core/utils/formatting.py +80 -0
  223. coco_core/utils/function_calling.py +869 -0
  224. coco_core/utils/html.py +132 -0
  225. coco_core/utils/image.py +15 -0
  226. coco_core/utils/input.py +82 -0
  227. coco_core/utils/interactive_env.py +12 -0
  228. coco_core/utils/iter.py +229 -0
  229. coco_core/utils/json.py +230 -0
  230. coco_core/utils/json_schema.py +273 -0
  231. coco_core/utils/mustache.py +706 -0
  232. coco_core/utils/pydantic.py +631 -0
  233. coco_core/utils/strings.py +69 -0
  234. coco_core/utils/usage.py +61 -0
  235. coco_core/utils/utils.py +528 -0
  236. coco_core/utils/uuid.py +57 -0
  237. coco_core/vectorstores/__init__.py +53 -0
  238. coco_core/vectorstores/base.py +1111 -0
  239. coco_core/vectorstores/in_memory.py +546 -0
  240. coco_core/vectorstores/utils.py +163 -0
  241. coco_core/version.py +3 -0
  242. coco_framework-0.1.0.dist-info/METADATA +184 -0
  243. coco_framework-0.1.0.dist-info/RECORD +400 -0
  244. coco_framework-0.1.0.dist-info/WHEEL +4 -0
  245. coco_framework-0.1.0.dist-info/licenses/LICENSE +24 -0
  246. coco_framework-0.1.0.dist-info/licenses/NOTICE +15 -0
  247. coco_graph/_internal/__init__.py +4 -0
  248. coco_graph/_internal/_cache.py +31 -0
  249. coco_graph/_internal/_config.py +474 -0
  250. coco_graph/_internal/_constants.py +140 -0
  251. coco_graph/_internal/_fields.py +213 -0
  252. coco_graph/_internal/_future.py +220 -0
  253. coco_graph/_internal/_pydantic.py +275 -0
  254. coco_graph/_internal/_queue.py +124 -0
  255. coco_graph/_internal/_replay.py +90 -0
  256. coco_graph/_internal/_retry.py +29 -0
  257. coco_graph/_internal/_runnable.py +969 -0
  258. coco_graph/_internal/_scratchpad.py +19 -0
  259. coco_graph/_internal/_serde.py +253 -0
  260. coco_graph/_internal/_timeout.py +25 -0
  261. coco_graph/_internal/_typing.py +54 -0
  262. coco_graph/cache/base/__init__.py +48 -0
  263. coco_graph/cache/base/py.typed +0 -0
  264. coco_graph/cache/memory/__init__.py +73 -0
  265. coco_graph/cache/redis/__init__.py +144 -0
  266. coco_graph/cache/sqlite/__init__.py +120 -0
  267. coco_graph/callbacks.py +394 -0
  268. coco_graph/channels/__init__.py +29 -0
  269. coco_graph/channels/any_value.py +72 -0
  270. coco_graph/channels/base.py +121 -0
  271. coco_graph/channels/binop.py +155 -0
  272. coco_graph/channels/delta.py +202 -0
  273. coco_graph/channels/ephemeral_value.py +79 -0
  274. coco_graph/channels/last_value.py +151 -0
  275. coco_graph/channels/named_barrier_value.py +167 -0
  276. coco_graph/channels/topic.py +94 -0
  277. coco_graph/channels/untracked_value.py +73 -0
  278. coco_graph/checkpoint/base/__init__.py +861 -0
  279. coco_graph/checkpoint/base/id.py +109 -0
  280. coco_graph/checkpoint/base/py.typed +0 -0
  281. coco_graph/checkpoint/memory/__init__.py +698 -0
  282. coco_graph/checkpoint/memory/py.typed +0 -0
  283. coco_graph/checkpoint/postgres/__init__.py +602 -0
  284. coco_graph/checkpoint/postgres/_ainternal.py +23 -0
  285. coco_graph/checkpoint/postgres/_internal.py +21 -0
  286. coco_graph/checkpoint/postgres/aio.py +691 -0
  287. coco_graph/checkpoint/postgres/base.py +666 -0
  288. coco_graph/checkpoint/postgres/py.typed +0 -0
  289. coco_graph/checkpoint/postgres/shallow.py +967 -0
  290. coco_graph/checkpoint/serde/__init__.py +0 -0
  291. coco_graph/checkpoint/serde/_msgpack.py +97 -0
  292. coco_graph/checkpoint/serde/base.py +64 -0
  293. coco_graph/checkpoint/serde/encrypted.py +80 -0
  294. coco_graph/checkpoint/serde/event_hooks.py +52 -0
  295. coco_graph/checkpoint/serde/jsonplus.py +883 -0
  296. coco_graph/checkpoint/serde/py.typed +0 -0
  297. coco_graph/checkpoint/serde/types.py +68 -0
  298. coco_graph/checkpoint/sqlite/__init__.py +645 -0
  299. coco_graph/checkpoint/sqlite/_delta.py +172 -0
  300. coco_graph/checkpoint/sqlite/aio.py +738 -0
  301. coco_graph/checkpoint/sqlite/py.typed +0 -0
  302. coco_graph/checkpoint/sqlite/utils.py +116 -0
  303. coco_graph/config.py +196 -0
  304. coco_graph/constants.py +64 -0
  305. coco_graph/errors.py +241 -0
  306. coco_graph/func/__init__.py +620 -0
  307. coco_graph/graph/__init__.py +12 -0
  308. coco_graph/graph/_branch.py +225 -0
  309. coco_graph/graph/_node.py +103 -0
  310. coco_graph/graph/message.py +437 -0
  311. coco_graph/graph/state.py +1978 -0
  312. coco_graph/graph/ui.py +227 -0
  313. coco_graph/managed/__init__.py +3 -0
  314. coco_graph/managed/base.py +31 -0
  315. coco_graph/managed/is_last_step.py +24 -0
  316. coco_graph/prebuilt/__init__.py +23 -0
  317. coco_graph/prebuilt/_tool_call_stream.py +117 -0
  318. coco_graph/prebuilt/_tool_call_transformer.py +165 -0
  319. coco_graph/prebuilt/chat_agent_executor.py +1015 -0
  320. coco_graph/prebuilt/interrupt.py +105 -0
  321. coco_graph/prebuilt/py.typed +0 -0
  322. coco_graph/prebuilt/tool_node.py +2030 -0
  323. coco_graph/prebuilt/tool_validator.py +221 -0
  324. coco_graph/pregel/__init__.py +3 -0
  325. coco_graph/pregel/_algo.py +1460 -0
  326. coco_graph/pregel/_call.py +298 -0
  327. coco_graph/pregel/_checkpoint.py +331 -0
  328. coco_graph/pregel/_config.py +0 -0
  329. coco_graph/pregel/_draw.py +294 -0
  330. coco_graph/pregel/_executor.py +223 -0
  331. coco_graph/pregel/_io.py +174 -0
  332. coco_graph/pregel/_log.py +3 -0
  333. coco_graph/pregel/_loop.py +1988 -0
  334. coco_graph/pregel/_messages.py +461 -0
  335. coco_graph/pregel/_read.py +312 -0
  336. coco_graph/pregel/_retry.py +854 -0
  337. coco_graph/pregel/_runner.py +941 -0
  338. coco_graph/pregel/_tools.py +268 -0
  339. coco_graph/pregel/_utils.py +221 -0
  340. coco_graph/pregel/_validate.py +120 -0
  341. coco_graph/pregel/_write.py +192 -0
  342. coco_graph/pregel/debug.py +302 -0
  343. coco_graph/pregel/main.py +4364 -0
  344. coco_graph/pregel/protocol.py +288 -0
  345. coco_graph/pregel/types.py +38 -0
  346. coco_graph/py.typed +0 -0
  347. coco_graph/runtime.py +350 -0
  348. coco_graph/store/base/__init__.py +1322 -0
  349. coco_graph/store/base/batch.py +371 -0
  350. coco_graph/store/base/embed.py +436 -0
  351. coco_graph/store/base/py.typed +0 -0
  352. coco_graph/store/memory/__init__.py +592 -0
  353. coco_graph/store/memory/py.typed +0 -0
  354. coco_graph/store/postgres/__init__.py +4 -0
  355. coco_graph/store/postgres/aio.py +592 -0
  356. coco_graph/store/postgres/base.py +1480 -0
  357. coco_graph/store/postgres/py.typed +0 -0
  358. coco_graph/store/sqlite/__init__.py +4 -0
  359. coco_graph/store/sqlite/aio.py +632 -0
  360. coco_graph/store/sqlite/base.py +1514 -0
  361. coco_graph/stream/__init__.py +45 -0
  362. coco_graph/stream/_convert.py +32 -0
  363. coco_graph/stream/_mux.py +523 -0
  364. coco_graph/stream/_types.py +330 -0
  365. coco_graph/stream/run_stream.py +735 -0
  366. coco_graph/stream/stream_channel.py +341 -0
  367. coco_graph/stream/transformers.py +1039 -0
  368. coco_graph/types.py +1079 -0
  369. coco_graph/typing.py +48 -0
  370. coco_graph/utils/__init__.py +1 -0
  371. coco_graph/utils/config.py +4 -0
  372. coco_graph/utils/runnable.py +3 -0
  373. coco_graph/version.py +13 -0
  374. coco_graph/warnings.py +69 -0
  375. coco_openai/__init__.py +20 -0
  376. coco_openai/_compat.py +45 -0
  377. coco_openai/_version.py +3 -0
  378. coco_openai/chat_models/__init__.py +6 -0
  379. coco_openai/chat_models/_client_utils.py +684 -0
  380. coco_openai/chat_models/_compat.py +525 -0
  381. coco_openai/chat_models/azure.py +1227 -0
  382. coco_openai/chat_models/base.py +5654 -0
  383. coco_openai/chat_models/codex.py +557 -0
  384. coco_openai/chatgpt_oauth.py +1063 -0
  385. coco_openai/data/__init__.py +1 -0
  386. coco_openai/data/_profiles.py +1655 -0
  387. coco_openai/data/profile_augmentations.toml +127 -0
  388. coco_openai/embeddings/__init__.py +6 -0
  389. coco_openai/embeddings/azure.py +240 -0
  390. coco_openai/embeddings/base.py +820 -0
  391. coco_openai/llms/__init__.py +6 -0
  392. coco_openai/llms/azure.py +249 -0
  393. coco_openai/llms/base.py +919 -0
  394. coco_openai/middleware/__init__.py +11 -0
  395. coco_openai/middleware/openai_moderation.py +484 -0
  396. coco_openai/output_parsers/__init__.py +9 -0
  397. coco_openai/output_parsers/tools.py +9 -0
  398. coco_openai/py.typed +0 -0
  399. coco_openai/tools/__init__.py +5 -0
  400. 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)