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
@@ -0,0 +1,312 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncIterator, Callable, Iterator, Mapping, Sequence
4
+ from datetime import timedelta
5
+ from functools import cached_property
6
+ from typing import (
7
+ Any,
8
+ )
9
+
10
+ from coco_core.runnables import Runnable, RunnableConfig
11
+
12
+ from coco_graph._internal._config import merge_configs
13
+ from coco_graph._internal._constants import CONF, CONFIG_KEY_READ
14
+ from coco_graph._internal._runnable import RunnableCallable, RunnableSeq
15
+ from coco_graph._internal._timeout import coerce_timeout_policy
16
+ from coco_graph.pregel._utils import find_subgraph_pregel
17
+ from coco_graph.pregel._write import ChannelWrite
18
+ from coco_graph.pregel.protocol import PregelProtocol
19
+ from coco_graph.types import CachePolicy, RetryPolicy, TimeoutPolicy, TracePolicy
20
+
21
+ READ_TYPE = Callable[[str | Sequence[str], bool], Any | dict[str, Any]]
22
+ INPUT_CACHE_KEY_TYPE = tuple[Callable[..., Any], tuple[str, ...]]
23
+
24
+
25
+ class ChannelRead(RunnableCallable):
26
+ """Implements the logic for reading state from CONFIG_KEY_READ.
27
+ Usable both as a runnable as well as a static method to call imperatively."""
28
+
29
+ channel: str | list[str]
30
+
31
+ fresh: bool = False
32
+
33
+ mapper: Callable[[Any], Any] | None = None
34
+
35
+ def __init__(
36
+ self,
37
+ channel: str | list[str],
38
+ *,
39
+ fresh: bool = False,
40
+ mapper: Callable[[Any], Any] | None = None,
41
+ tags: list[str] | None = None,
42
+ ) -> None:
43
+ super().__init__(
44
+ func=self._read,
45
+ afunc=self._aread,
46
+ tags=tags,
47
+ name=None,
48
+ trace=False,
49
+ )
50
+ self.fresh = fresh
51
+ self.mapper = mapper
52
+ self.channel = channel
53
+
54
+ def get_name(self, suffix: str | None = None, *, name: str | None = None) -> str:
55
+ if name:
56
+ pass
57
+ elif isinstance(self.channel, str):
58
+ name = f"ChannelRead<{self.channel}>"
59
+ else:
60
+ name = f"ChannelRead<{','.join(self.channel)}>"
61
+ return super().get_name(suffix, name=name)
62
+
63
+ def _read(self, _: Any, config: RunnableConfig) -> Any:
64
+ return self.do_read(
65
+ config, select=self.channel, fresh=self.fresh, mapper=self.mapper
66
+ )
67
+
68
+ async def _aread(self, _: Any, config: RunnableConfig) -> Any:
69
+ return self.do_read(
70
+ config, select=self.channel, fresh=self.fresh, mapper=self.mapper
71
+ )
72
+
73
+ @staticmethod
74
+ def do_read(
75
+ config: RunnableConfig,
76
+ *,
77
+ select: str | list[str],
78
+ fresh: bool = False,
79
+ mapper: Callable[[Any], Any] | None = None,
80
+ ) -> Any:
81
+ try:
82
+ read: READ_TYPE = config[CONF][CONFIG_KEY_READ]
83
+ except KeyError:
84
+ raise RuntimeError(
85
+ "Not configured with a read function"
86
+ "Make sure to call in the context of a Pregel process"
87
+ )
88
+ if mapper:
89
+ return mapper(read(select, fresh))
90
+ else:
91
+ return read(select, fresh)
92
+
93
+
94
+ DEFAULT_BOUND = RunnableCallable(lambda input: input)
95
+
96
+
97
+ class PregelNode:
98
+ """A node in a Pregel graph. This won't be invoked as a runnable by the graph
99
+ itself, but instead acts as a container for the components necessary to make
100
+ a PregelExecutableTask for a node."""
101
+
102
+ channels: str | list[str]
103
+ """The channels that will be passed as input to `bound`.
104
+ If a str, the node will be invoked with its value if it isn't empty.
105
+ If a list, the node will be invoked with a dict of those channels' values."""
106
+
107
+ triggers: list[str]
108
+ """If any of these channels is written to, this node will be triggered in
109
+ the next step."""
110
+
111
+ mapper: Callable[[Any], Any] | None
112
+ """A function to transform the input before passing it to `bound`."""
113
+
114
+ writers: list[Runnable]
115
+ """A list of writers that will be executed after `bound`, responsible for
116
+ taking the output of `bound` and writing it to the appropriate channels."""
117
+
118
+ bound: Runnable[Any, Any]
119
+ """The main logic of the node. This will be invoked with the input from
120
+ `channels`."""
121
+
122
+ retry_policy: Sequence[RetryPolicy] | None
123
+ """The retry policies to use when invoking the node."""
124
+
125
+ cache_policy: CachePolicy | None
126
+ """The cache policy to use when invoking the node."""
127
+
128
+ timeout: TimeoutPolicy | None
129
+ """Timeout policy for a single invocation.
130
+
131
+ If exceeded, `NodeTimeoutError` is raised and the retry policy (if any)
132
+ decides whether to retry. Supported only for async nodes.
133
+ """
134
+
135
+ tags: Sequence[str] | None
136
+ """Tags to attach to the node for tracing."""
137
+
138
+ metadata: Mapping[str, Any] | None
139
+ """Metadata to attach to the node for tracing."""
140
+
141
+ trace_policy: TracePolicy | None
142
+ """Optional policy controlling what this node records on its trace run."""
143
+
144
+ is_error_handler: bool
145
+ """Whether this node is registered as an error handler node."""
146
+
147
+ error_handler_node: str | None
148
+ """Optional handler node name for failures from this node."""
149
+
150
+ subgraphs: Sequence[PregelProtocol]
151
+ """Subgraphs used by the node."""
152
+
153
+ def __init__(
154
+ self,
155
+ *,
156
+ channels: str | list[str],
157
+ triggers: Sequence[str],
158
+ mapper: Callable[[Any], Any] | None = None,
159
+ writers: list[Runnable] | None = None,
160
+ tags: list[str] | None = None,
161
+ metadata: Mapping[str, Any] | None = None,
162
+ trace_policy: TracePolicy | None = None,
163
+ bound: Runnable[Any, Any] | None = None,
164
+ retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
165
+ cache_policy: CachePolicy | None = None,
166
+ is_error_handler: bool = False,
167
+ error_handler_node: str | None = None,
168
+ subgraphs: Sequence[PregelProtocol] | None = None,
169
+ timeout: float | timedelta | TimeoutPolicy | None = None,
170
+ ) -> None:
171
+ self.channels = channels
172
+ self.triggers = list(triggers)
173
+ self.mapper = mapper
174
+ self.writers = writers or []
175
+ self.bound = bound if bound is not None else DEFAULT_BOUND
176
+ self.cache_policy = cache_policy
177
+ if isinstance(retry_policy, RetryPolicy):
178
+ self.retry_policy = (retry_policy,)
179
+ else:
180
+ self.retry_policy = retry_policy
181
+ self.timeout = coerce_timeout_policy(timeout)
182
+ self.tags = tags
183
+ self.metadata = metadata
184
+ self.trace_policy = trace_policy
185
+ self.is_error_handler = is_error_handler
186
+ self.error_handler_node = error_handler_node
187
+ if subgraphs is not None:
188
+ self.subgraphs = subgraphs
189
+ elif self.bound is not DEFAULT_BOUND:
190
+ try:
191
+ subgraph = find_subgraph_pregel(self.bound)
192
+ except Exception:
193
+ subgraph = None
194
+ if subgraph:
195
+ self.subgraphs = [subgraph]
196
+ else:
197
+ self.subgraphs = []
198
+ else:
199
+ self.subgraphs = []
200
+
201
+ def copy(self, update: dict[str, Any]) -> PregelNode:
202
+ attrs = {**self.__dict__, **update}
203
+ # Drop the cached properties
204
+ attrs.pop("flat_writers", None)
205
+ attrs.pop("node", None)
206
+ attrs.pop("input_cache_key", None)
207
+ return PregelNode(**attrs)
208
+
209
+ @cached_property
210
+ def flat_writers(self) -> list[Runnable]:
211
+ """Get writers with optimizations applied. Dedupes consecutive ChannelWrites."""
212
+ writers = self.writers.copy()
213
+ while (
214
+ len(writers) > 1
215
+ and isinstance(writers[-1], ChannelWrite)
216
+ and isinstance(writers[-2], ChannelWrite)
217
+ ):
218
+ # we can combine writes if they are consecutive
219
+ # careful to not modify the original writers list or ChannelWrite
220
+ writers[-2] = ChannelWrite(
221
+ writes=writers[-2].writes + writers[-1].writes,
222
+ )
223
+ writers.pop()
224
+ return writers
225
+
226
+ @cached_property
227
+ def node(self) -> Runnable[Any, Any] | None:
228
+ """Get a runnable that combines `bound` and `writers`."""
229
+ writers = self.flat_writers
230
+ trace_inputs = self.trace_policy.process_inputs if self.trace_policy else None
231
+ trace_outputs = self.trace_policy.process_outputs if self.trace_policy else None
232
+ if self.bound is DEFAULT_BOUND and not writers:
233
+ return None
234
+ elif self.bound is DEFAULT_BOUND and len(writers) == 1:
235
+ return writers[0]
236
+ elif self.bound is DEFAULT_BOUND:
237
+ return RunnableSeq(
238
+ *writers, trace_inputs=trace_inputs, trace_outputs=trace_outputs
239
+ )
240
+ elif writers:
241
+ return RunnableSeq(
242
+ self.bound,
243
+ *writers,
244
+ trace_inputs=trace_inputs,
245
+ trace_outputs=trace_outputs,
246
+ )
247
+ else:
248
+ return self.bound
249
+
250
+ @cached_property
251
+ def input_cache_key(self) -> INPUT_CACHE_KEY_TYPE:
252
+ """Get a cache key for the input to the node.
253
+ This is used to avoid calculating the same input multiple times."""
254
+ return (
255
+ self.mapper,
256
+ tuple(self.channels)
257
+ if isinstance(self.channels, list)
258
+ else (self.channels,),
259
+ )
260
+
261
+ def invoke(
262
+ self,
263
+ input: Any,
264
+ config: RunnableConfig | None = None,
265
+ **kwargs: Any | None,
266
+ ) -> Any:
267
+ self_config: RunnableConfig = {"metadata": self.metadata, "tags": self.tags}
268
+ return self.bound.invoke(
269
+ input,
270
+ merge_configs(self_config, config),
271
+ **kwargs,
272
+ )
273
+
274
+ async def ainvoke(
275
+ self,
276
+ input: Any,
277
+ config: RunnableConfig | None = None,
278
+ **kwargs: Any | None,
279
+ ) -> Any:
280
+ self_config: RunnableConfig = {"metadata": self.metadata, "tags": self.tags}
281
+ return await self.bound.ainvoke(
282
+ input,
283
+ merge_configs(self_config, config),
284
+ **kwargs,
285
+ )
286
+
287
+ def stream(
288
+ self,
289
+ input: Any,
290
+ config: RunnableConfig | None = None,
291
+ **kwargs: Any | None,
292
+ ) -> Iterator[Any]:
293
+ self_config: RunnableConfig = {"metadata": self.metadata, "tags": self.tags}
294
+ yield from self.bound.stream(
295
+ input,
296
+ merge_configs(self_config, config),
297
+ **kwargs,
298
+ )
299
+
300
+ async def astream(
301
+ self,
302
+ input: Any,
303
+ config: RunnableConfig | None = None,
304
+ **kwargs: Any | None,
305
+ ) -> AsyncIterator[Any]:
306
+ self_config: RunnableConfig = {"metadata": self.metadata, "tags": self.tags}
307
+ async for item in self.bound.astream(
308
+ input,
309
+ merge_configs(self_config, config),
310
+ **kwargs,
311
+ ):
312
+ yield item