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,4 @@
1
+ """Internal modules for CocoGraph.
2
+
3
+ This module is not part of the public API, and thus stability is not guaranteed.
4
+ """
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Hashable, Mapping, Sequence
4
+ from typing import Any
5
+
6
+
7
+ def _freeze(obj: Any, depth: int = 10) -> Hashable:
8
+ if isinstance(obj, Hashable) or depth <= 0:
9
+ # already hashable, no need to freeze
10
+ return obj
11
+ elif isinstance(obj, Mapping):
12
+ # sort keys so {"a":1,"b":2} == {"b":2,"a":1}
13
+ return tuple(sorted((k, _freeze(v, depth - 1)) for k, v in obj.items()))
14
+ elif isinstance(obj, Sequence):
15
+ return tuple(_freeze(x, depth - 1) for x in obj)
16
+ # numpy / pandas etc. can provide their own .tobytes()
17
+ elif hasattr(obj, "tobytes"):
18
+ return (
19
+ type(obj).__name__,
20
+ obj.tobytes(),
21
+ obj.shape if hasattr(obj, "shape") else None,
22
+ )
23
+ return obj # strings, ints, dataclasses with frozen=True, etc.
24
+
25
+
26
+ def default_cache_key(*args: Any, **kwargs: Any) -> str | bytes:
27
+ """Default cache key function that uses the arguments and keyword arguments to generate a hashable key."""
28
+ import pickle
29
+
30
+ # protocol 5 strikes a good balance between speed and size
31
+ return pickle.dumps((_freeze(args), _freeze(kwargs)), protocol=5, fix_imports=False)
@@ -0,0 +1,474 @@
1
+ from __future__ import annotations
2
+
3
+ from collections import ChainMap
4
+ from collections.abc import Mapping, Sequence
5
+ from os import getenv
6
+ from typing import Any, cast
7
+
8
+ from coco_core.callbacks import (
9
+ AsyncCallbackManager,
10
+ BaseCallbackManager,
11
+ CallbackManager,
12
+ Callbacks,
13
+ )
14
+ from coco_core.runnables import RunnableConfig
15
+ from coco_core.runnables.config import (
16
+ CONFIG_KEYS,
17
+ COPIABLE_KEYS,
18
+ var_child_runnable_config,
19
+ )
20
+ from coco_graph.checkpoint.base import CheckpointMetadata
21
+
22
+ from coco_graph._internal._constants import (
23
+ _CHECKPOINT_COORDINATE_KEYS,
24
+ CONF,
25
+ CONFIG_KEY_CHECKPOINT_ID,
26
+ CONFIG_KEY_CHECKPOINT_MAP,
27
+ CONFIG_KEY_CHECKPOINT_NS,
28
+ NS_END,
29
+ NS_SEP,
30
+ )
31
+
32
+ DEFAULT_RECURSION_LIMIT = int(getenv("COCO_GRAPH_DEFAULT_RECURSION_LIMIT", "10007"))
33
+ DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT = int(
34
+ getenv("COCO_GRAPH_DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT", "5000")
35
+ )
36
+
37
+
38
+ def recast_checkpoint_ns(ns: str) -> str:
39
+ """Remove task IDs from checkpoint namespace.
40
+
41
+ Args:
42
+ ns: The checkpoint namespace with task IDs.
43
+
44
+ Returns:
45
+ str: The checkpoint namespace without task IDs.
46
+ """
47
+ return NS_SEP.join(
48
+ part.split(NS_END)[0] for part in ns.split(NS_SEP) if not part.isdigit()
49
+ )
50
+
51
+
52
+ def patch_configurable(
53
+ config: RunnableConfig | None, patch: dict[str, Any]
54
+ ) -> RunnableConfig:
55
+ if config is None:
56
+ return {CONF: patch}
57
+ elif CONF not in config:
58
+ return {**config, CONF: patch}
59
+ else:
60
+ return {**config, CONF: {**config[CONF], **patch}}
61
+
62
+
63
+ def patch_checkpoint_map(
64
+ config: RunnableConfig | None, metadata: CheckpointMetadata | None
65
+ ) -> RunnableConfig:
66
+ if config is None:
67
+ return config
68
+ elif parents := (metadata.get("parents") if metadata else None):
69
+ conf = config[CONF]
70
+ return patch_configurable(
71
+ config,
72
+ {
73
+ CONFIG_KEY_CHECKPOINT_MAP: {
74
+ **parents,
75
+ conf[CONFIG_KEY_CHECKPOINT_NS]: conf[CONFIG_KEY_CHECKPOINT_ID],
76
+ },
77
+ },
78
+ )
79
+ else:
80
+ return config
81
+
82
+
83
+ def _copy_mapping_value(value: Any) -> Any:
84
+ return dict(value) if isinstance(value, Mapping) else value
85
+
86
+
87
+ def _merge_metadata(
88
+ base: Mapping[str, Any] | None, new: Mapping[str, Any] | None
89
+ ) -> dict[str, Any]:
90
+ """Merge metadata without mutating inputs.
91
+
92
+ Top-level keys merge with newer values winning. `lc_versions` is the only
93
+ mapping-valued key that merges one level deeper, so independent Coco
94
+ packages can contribute package versions without changing generic metadata
95
+ semantics. Mapping values are copied one level, so deeper nested objects
96
+ remain shared. `None` inputs are treated as empty metadata.
97
+
98
+ Mirrors `coco_core.runnables.config._merge_metadata_dicts` so configs
99
+ that pass through CocoGraph's merge keep the same `lc_versions` semantics;
100
+ keep the two in sync. Unlike lc-core, this copies mapping values one level
101
+ (intentionally more defensive — do not "simplify" back to a shared ref).
102
+ """
103
+ merged = {key: _copy_mapping_value(value) for key, value in (base or {}).items()}
104
+ for key, value in (new or {}).items():
105
+ if (
106
+ key == "lc_versions"
107
+ and isinstance(merged.get(key), Mapping)
108
+ and isinstance(value, Mapping)
109
+ ):
110
+ merged[key] = {
111
+ **cast(Mapping[str, Any], merged[key]),
112
+ **value,
113
+ }
114
+ else:
115
+ merged[key] = _copy_mapping_value(value)
116
+ return merged
117
+
118
+
119
+ def _merge_callbacks(base: Callbacks, new: Callbacks) -> Callbacks:
120
+ """Merge two callbacks values (None / list / BaseCallbackManager).
121
+
122
+ Six cases total (3 base types x 2 non-None new types).
123
+ """
124
+ if new is None:
125
+ return base
126
+ if base is None:
127
+ return new.copy() if isinstance(new, (list, BaseCallbackManager)) else new
128
+ if isinstance(new, list):
129
+ if isinstance(base, list):
130
+ return base + new
131
+ if isinstance(base, BaseCallbackManager):
132
+ mngr = base.copy()
133
+ for cb in new:
134
+ mngr.add_handler(cb, inherit=True)
135
+ return mngr
136
+ elif isinstance(new, BaseCallbackManager):
137
+ if isinstance(base, list):
138
+ mngr = new.copy()
139
+ for cb in base:
140
+ mngr.add_handler(cb, inherit=True)
141
+ return mngr
142
+ if isinstance(base, BaseCallbackManager):
143
+ return base.merge(new)
144
+ raise NotImplementedError(f"Unsupported callback types: {type(base)}, {type(new)}")
145
+
146
+
147
+ def merge_configs(*configs: RunnableConfig | None) -> RunnableConfig:
148
+ """Merge multiple configs into one.
149
+
150
+ Args:
151
+ *configs: The configs to merge.
152
+
153
+ Returns:
154
+ RunnableConfig: The merged config.
155
+ """
156
+ base: RunnableConfig = {}
157
+ # Even though the keys aren't literals, this is correct
158
+ # because both dicts are the same type
159
+ for config in configs:
160
+ if config is None:
161
+ continue
162
+ for key, value in config.items():
163
+ if not value:
164
+ continue
165
+ if key == "metadata":
166
+ base[key] = _merge_metadata(
167
+ cast(Mapping[str, Any] | None, base.get(key)),
168
+ cast(Mapping[str, Any], value),
169
+ )
170
+ elif key == "tags":
171
+ if base_value := base.get(key):
172
+ base[key] = [*base_value, *value] # type: ignore
173
+ else:
174
+ base[key] = value # type: ignore[literal-required]
175
+ elif key == CONF:
176
+ if base_value := base.get(key):
177
+ base[key] = {**base_value, **value} # type: ignore[dict-item]
178
+ else:
179
+ base[key] = value
180
+ elif key == "callbacks":
181
+ base["callbacks"] = _merge_callbacks(
182
+ base.get("callbacks"), cast(Callbacks, value)
183
+ )
184
+ elif key == "recursion_limit":
185
+ if config["recursion_limit"] != DEFAULT_RECURSION_LIMIT:
186
+ base["recursion_limit"] = config["recursion_limit"]
187
+ else:
188
+ base[key] = config[key] # type: ignore[literal-required]
189
+ if CONF not in base:
190
+ base[CONF] = {}
191
+ return base
192
+
193
+
194
+ def patch_config(
195
+ config: RunnableConfig | None,
196
+ *,
197
+ callbacks: Callbacks = None,
198
+ recursion_limit: int | None = None,
199
+ max_concurrency: int | None = None,
200
+ run_name: str | None = None,
201
+ configurable: dict[str, Any] | None = None,
202
+ ) -> RunnableConfig:
203
+ """Patch a config with new values.
204
+
205
+ Args:
206
+ config: The config to patch.
207
+ callbacks: The callbacks to set.
208
+ recursion_limit: The recursion limit to set.
209
+ max_concurrency: The max number of concurrent steps to run, which also applies to parallelized steps.
210
+ run_name: The run name to set.
211
+ configurable: The configurable to set.
212
+
213
+ Returns:
214
+ RunnableConfig: The patched config.
215
+ """
216
+ config = config.copy() if config is not None else {}
217
+ if callbacks is not None:
218
+ # If we're replacing callbacks, we need to unset run_name
219
+ # As that should apply only to the same run as the original callbacks
220
+ config["callbacks"] = callbacks
221
+ if "run_name" in config:
222
+ del config["run_name"]
223
+ if "run_id" in config:
224
+ del config["run_id"]
225
+ if recursion_limit is not None:
226
+ config["recursion_limit"] = recursion_limit
227
+ if max_concurrency is not None:
228
+ config["max_concurrency"] = max_concurrency
229
+ if run_name is not None:
230
+ config["run_name"] = run_name
231
+ if configurable is not None:
232
+ config[CONF] = {**config.get(CONF, {}), **configurable}
233
+ return config
234
+
235
+
236
+ def get_callback_manager_for_config(
237
+ config: RunnableConfig, tags: Sequence[str] | None = None
238
+ ) -> CallbackManager:
239
+ """Get a callback manager for a config.
240
+
241
+ Args:
242
+ config: The config.
243
+
244
+ Returns:
245
+ CallbackManager: The callback manager.
246
+ """
247
+ from coco_core.callbacks.manager import CallbackManager
248
+
249
+ # merge tags
250
+ all_tags = config.get("tags")
251
+ if all_tags is not None and tags is not None:
252
+ all_tags = [*all_tags, *tags]
253
+ elif tags is not None:
254
+ all_tags = list(tags)
255
+ # use existing callbacks if they exist
256
+ if (callbacks := config.get("callbacks")) and isinstance(
257
+ callbacks, CallbackManager
258
+ ):
259
+ if all_tags:
260
+ callbacks.add_tags(all_tags)
261
+ if metadata := config.get("metadata"):
262
+ callbacks.add_metadata(metadata)
263
+ manager = callbacks
264
+ else:
265
+ # otherwise create a new manager
266
+ manager = CallbackManager.configure(
267
+ inheritable_callbacks=config.get("callbacks"),
268
+ inheritable_tags=all_tags,
269
+ inheritable_metadata=config.get("metadata"),
270
+ langsmith_inheritable_metadata=_get_tracing_metadata_defaults(config),
271
+ )
272
+ return manager
273
+
274
+
275
+ def get_async_callback_manager_for_config(
276
+ config: RunnableConfig,
277
+ tags: Sequence[str] | None = None,
278
+ ) -> AsyncCallbackManager:
279
+ """Get an async callback manager for a config.
280
+
281
+ Args:
282
+ config: The config.
283
+
284
+ Returns:
285
+ AsyncCallbackManager: The async callback manager.
286
+ """
287
+ from coco_core.callbacks.manager import AsyncCallbackManager
288
+
289
+ # merge tags
290
+ all_tags = config.get("tags")
291
+ if all_tags is not None and tags is not None:
292
+ all_tags = [*all_tags, *tags]
293
+ elif tags is not None:
294
+ all_tags = list(tags)
295
+ # use existing callbacks if they exist
296
+ if (callbacks := config.get("callbacks")) and isinstance(
297
+ callbacks, AsyncCallbackManager
298
+ ):
299
+ if all_tags:
300
+ callbacks.add_tags(all_tags)
301
+ if metadata := config.get("metadata"):
302
+ callbacks.add_metadata(metadata)
303
+ manager = callbacks
304
+ else:
305
+ # otherwise create a new manager
306
+ manager = AsyncCallbackManager.configure(
307
+ inheritable_callbacks=config.get("callbacks"),
308
+ inheritable_tags=all_tags,
309
+ inheritable_metadata=config.get("metadata"),
310
+ langsmith_inheritable_metadata=_get_tracing_metadata_defaults(config),
311
+ )
312
+ return manager
313
+
314
+
315
+ def _is_not_empty(value: Any) -> bool:
316
+ if isinstance(value, (list, tuple, dict)):
317
+ return len(value) > 0
318
+ else:
319
+ return value is not None
320
+
321
+
322
+ def ensure_config(*configs: RunnableConfig | None) -> RunnableConfig:
323
+ """Return a config with all keys, merging any provided configs.
324
+
325
+ Args:
326
+ *configs: Configs to merge before ensuring defaults.
327
+
328
+ Returns:
329
+ RunnableConfig: The merged and ensured config.
330
+ """
331
+ empty = RunnableConfig(
332
+ tags=[],
333
+ metadata=ChainMap(),
334
+ callbacks=None,
335
+ recursion_limit=DEFAULT_RECURSION_LIMIT,
336
+ configurable={},
337
+ )
338
+ if var_config := var_child_runnable_config.get():
339
+ empty.update(
340
+ {
341
+ k: v.copy() if k in COPIABLE_KEYS else v # type: ignore[attr-defined]
342
+ for k, v in var_config.items()
343
+ if _is_not_empty(v)
344
+ },
345
+ )
346
+ # An explicit config that supplies its own checkpoint coordinate (a
347
+ # thread_id, or any checkpoint_ns/checkpoint_id/checkpoint_map) is addressing
348
+ # its own checkpoint lineage, so drop the inherited ambient configurable
349
+ # rather than merging over it: a child graph invoked inside a parent node
350
+ # would otherwise write its checkpoints under the parent's namespace and
351
+ # never find them again. An explicit thread_id resets even when it equals the
352
+ # ambient one, since a child reusing the parent's thread id still addresses
353
+ # its own root namespace, not the parent task's. Configs that only refine
354
+ # other keys keep the ambient and shallow-merge over it below.
355
+ if empty.get(CONF):
356
+ for config in configs:
357
+ if config is None:
358
+ continue
359
+ explicit_configurable = config.get(CONF)
360
+ if not explicit_configurable:
361
+ continue
362
+ if any(
363
+ _is_not_empty(explicit_configurable.get(k))
364
+ for k in _CHECKPOINT_COORDINATE_KEYS
365
+ ):
366
+ empty[CONF] = {}
367
+ break
368
+ for config in configs:
369
+ if config is None:
370
+ continue
371
+ for k, v in config.items():
372
+ if _is_not_empty(v) and k in CONFIG_KEYS:
373
+ if k == CONF:
374
+ # Shallow-merge configurable dicts across configs so values
375
+ # bound via with_config(...) (e.g. ls_agent_type) are
376
+ # preserved when later configs (e.g. invoke-time) only
377
+ # specify a subset of keys like thread_id.
378
+ existing = empty.get(k)
379
+ empty[k] = (
380
+ {**cast(dict, existing), **cast(dict, v)}
381
+ if existing
382
+ else cast(dict, v).copy()
383
+ )
384
+ elif k == "callbacks":
385
+ empty["callbacks"] = _merge_callbacks(
386
+ empty.get("callbacks"), cast(Callbacks, v)
387
+ )
388
+ elif k == "metadata":
389
+ # Matches merge_configs: top-level metadata keys merge, and
390
+ # only `lc_versions` merges one level deeper.
391
+ empty["metadata"] = _merge_metadata(
392
+ cast(Mapping[str, Any] | None, empty.get("metadata")),
393
+ cast(Mapping[str, Any], v),
394
+ )
395
+ elif k == "tags":
396
+ # Concatenate tags across configs so values bound via
397
+ # with_config(...) are preserved when later configs
398
+ # supply additional tags. Matches merge_configs.
399
+ existing_tags: list[str] | None = empty.get("tags")
400
+ empty["tags"] = (
401
+ [*existing_tags, *cast(list, v)]
402
+ if existing_tags
403
+ else list(cast(list, v))
404
+ )
405
+ else:
406
+ empty[k] = v # type: ignore[literal-required]
407
+ for k, v in config.items():
408
+ if _is_not_empty(v) and k not in CONFIG_KEYS:
409
+ empty[CONF][k] = v
410
+
411
+ configurable = empty.get("configurable")
412
+ metadata = empty.get("metadata")
413
+ if configurable and metadata is not None:
414
+ for key in _PROPAGATE_TO_METADATA:
415
+ if key in metadata:
416
+ continue
417
+ value = configurable.get(key)
418
+ if value:
419
+ metadata[key] = value
420
+ return empty
421
+
422
+
423
+ _OMIT = ("key", "token", "secret", "password", "auth")
424
+
425
+
426
+ def _exclude_as_metadata(key: str, value: Any) -> bool:
427
+ key_lower = key.casefold()
428
+ return (
429
+ key.startswith("__")
430
+ or not isinstance(value, (str, int, float, bool))
431
+ or any(substr in key_lower for substr in _OMIT)
432
+ )
433
+
434
+
435
+ def _get_tracing_metadata_defaults(
436
+ config: RunnableConfig,
437
+ ) -> dict[str, Any] | None:
438
+ """Get tracer-only metadata defaults from configurable values."""
439
+ configurable = config.get("configurable")
440
+ if not configurable:
441
+ return None
442
+ metadata: dict[str, Any] = {}
443
+ for key, value in configurable.items():
444
+ if _exclude_as_metadata(key, value):
445
+ continue
446
+ metadata[key] = value
447
+ return metadata or None
448
+
449
+
450
+ _PROPAGATE_TO_METADATA = frozenset(
451
+ (
452
+ "thread_id",
453
+ "checkpoint_id",
454
+ "checkpoint_ns",
455
+ "task_id",
456
+ "run_id",
457
+ "assistant_id",
458
+ "graph_id",
459
+ )
460
+ )
461
+
462
+
463
+ def filter_to_user_tags(tags: Sequence[str] | None) -> list[str] | None:
464
+ """Drop coco_graph's internal `seq:step:*` bookkeeping tags.
465
+
466
+ `seq:step:N` tags are added internally to mark sequence steps; everything
467
+ else (user-supplied tags and any other framework tags) is kept. Returns the
468
+ surviving tags, or `None` if none remain. Shared by the `messages` and
469
+ `tasks` stream handlers so both surface the same tag set on their metadata.
470
+ """
471
+ if not tags:
472
+ return None
473
+ filtered = [t for t in tags if not t.startswith("seq:step")]
474
+ return filtered or None
@@ -0,0 +1,140 @@
1
+ """Constants used for Pregel operations."""
2
+
3
+ import sys
4
+ from typing import Literal, cast
5
+
6
+ # --- Reserved write keys ---
7
+ INPUT = sys.intern("__input__")
8
+ # for values passed as input to the graph
9
+ INTERRUPT = sys.intern("__interrupt__")
10
+ # for dynamic interrupts raised by nodes
11
+ RESUME = sys.intern("__resume__")
12
+ # for values passed to resume a node after an interrupt
13
+ ERROR = sys.intern("__error__")
14
+ # for errors raised by nodes
15
+ ERROR_SOURCE_NODE = sys.intern("__error_source_node__")
16
+ # failed source node name for node-level error handlers
17
+ # value format in pending writes: `(task_id, ERROR_SOURCE_NODE, node_name: str)`
18
+ NO_WRITES = sys.intern("__no_writes__")
19
+ # marker to signal node didn't write anything
20
+ TASKS = sys.intern("__pregel_tasks")
21
+ # for Send objects returned by nodes/edges, corresponds to PUSH below
22
+ RETURN = sys.intern("__return__")
23
+ # for writes of a task where we simply record the return value
24
+ PREVIOUS = sys.intern("__previous__")
25
+ # the implicit branch that handles each node's Control values
26
+
27
+
28
+ # --- Reserved cache namespaces ---
29
+ CACHE_NS_WRITES = sys.intern("__pregel_ns_writes")
30
+ # cache namespace for node writes
31
+
32
+ # --- Reserved config.configurable keys ---
33
+ CONFIG_KEY_SEND = sys.intern("__pregel_send")
34
+ # holds the `write` function that accepts writes to state/edges/reserved keys
35
+ CONFIG_KEY_READ = sys.intern("__pregel_read")
36
+ # holds the `read` function that returns a copy of the current state
37
+ CONFIG_KEY_CALL = sys.intern("__pregel_call")
38
+ # holds the `call` function that accepts a node/func, args and returns a future
39
+ CONFIG_KEY_CHECKPOINTER = sys.intern("__pregel_checkpointer")
40
+ # holds a `BaseCheckpointSaver` passed from parent graph to child graphs
41
+ CONFIG_KEY_STREAM = sys.intern("__pregel_stream")
42
+ # holds a `StreamProtocol` passed from parent graph to child graphs
43
+ CONFIG_KEY_CACHE = sys.intern("__pregel_cache")
44
+ # holds a `BaseCache` made available to subgraphs
45
+ CONFIG_KEY_RESUMING = sys.intern("__pregel_resuming")
46
+ # holds a boolean indicating if subgraphs should resume from a previous checkpoint
47
+ CONFIG_KEY_REPLAY_STATE = sys.intern("__pregel_replay_state")
48
+ # holds a ReplayState tracking the parent checkpoint_id upper bound and which
49
+ # subgraph namespaces have already loaded their pre-replay checkpoint
50
+ CONFIG_KEY_TASK_ID = sys.intern("__pregel_task_id")
51
+ # holds the task ID for the current task
52
+ CONFIG_KEY_THREAD_ID = sys.intern("thread_id")
53
+ # holds the thread ID for the current invocation
54
+ CONFIG_KEY_CHECKPOINT_MAP = sys.intern("checkpoint_map")
55
+ # holds a mapping of checkpoint_ns -> checkpoint_id for parent graphs
56
+ CONFIG_KEY_CHECKPOINT_ID = sys.intern("checkpoint_id")
57
+ # holds the current checkpoint_id, if any
58
+ CONFIG_KEY_CHECKPOINT_NS = sys.intern("checkpoint_ns")
59
+ # holds the current checkpoint_ns, "" for root graph
60
+ CONFIG_KEY_NODE_FINISHED = sys.intern("__pregel_node_finished")
61
+ # holds a callback to be called when a node is finished
62
+ CONFIG_KEY_TIMED_ATTEMPT_OBSERVER = sys.intern("__pregel_timed_attempt_observer")
63
+ # holds a callback to be called when an idle-timed node attempt starts or finishes
64
+ CONFIG_KEY_SCRATCHPAD = sys.intern("__pregel_scratchpad")
65
+ # holds a mutable dict for temporary storage scoped to the current task
66
+ CONFIG_KEY_RUNNER_SUBMIT = sys.intern("__pregel_runner_submit")
67
+ # holds a function that receives tasks from runner, executes them and returns results
68
+ CONFIG_KEY_DURABILITY = sys.intern("__pregel_durability")
69
+ # holds the durability mode, one of "sync", "async", or "exit"
70
+ CONFIG_KEY_RUNTIME = sys.intern("__pregel_runtime")
71
+ # holds a `Runtime` instance with context, store, stream writer, etc.
72
+ CONFIG_KEY_RESUME_MAP = sys.intern("__pregel_resume_map")
73
+ # holds a mapping of task ns -> resume value for resuming tasks
74
+ CONFIG_KEY_STREAM_MESSAGES_V2 = sys.intern("__pregel_stream_messages_v2")
75
+ # when True, attach StreamMessagesHandlerV2 so content-block (v2) events
76
+ # flow through stream_mode="messages"; set by StreamingHandler only.
77
+ CONFIG_KEY_NODE_ERROR = sys.intern("__pregel_node_error")
78
+ # holds a `NodeError` (failed source node + exception) for the current
79
+ # node-level error handler invocation, injected when handler signature
80
+ # requests `error: NodeError`
81
+
82
+ # --- Other constants ---
83
+ PUSH = sys.intern("__pregel_push")
84
+ # denotes push-style tasks, ie. those created by Send objects
85
+ PULL = sys.intern("__pregel_pull")
86
+ # denotes pull-style tasks, ie. those triggered by edges
87
+ NS_SEP = sys.intern("|")
88
+ # for checkpoint_ns, separates each level (ie. graph|subgraph|subsubgraph)
89
+ NS_END = sys.intern(":")
90
+ # for checkpoint_ns, for each level, separates the namespace from the task_id
91
+ CONF = cast(Literal["configurable"], sys.intern("configurable"))
92
+ # key for the configurable dict in RunnableConfig
93
+ NULL_TASK_ID = sys.intern("00000000-0000-0000-0000-000000000000")
94
+ # the task_id to use for writes that are not associated with a task
95
+ OVERWRITE = sys.intern("__overwrite__")
96
+ # dict key for the overwrite value, used as `{'__overwrite__': value}`
97
+
98
+ # Checkpoint coordinate keys: when any of these appear in an explicit
99
+ # configurable, the caller is addressing its own checkpoint lineage.
100
+ _CHECKPOINT_COORDINATE_KEYS = (
101
+ CONFIG_KEY_THREAD_ID,
102
+ CONFIG_KEY_CHECKPOINT_NS,
103
+ CONFIG_KEY_CHECKPOINT_ID,
104
+ CONFIG_KEY_CHECKPOINT_MAP,
105
+ )
106
+
107
+ # redefined to avoid circular import with coco_graph.constants
108
+ _TAG_HIDDEN = sys.intern("langsmith:hidden")
109
+
110
+ RESERVED = {
111
+ _TAG_HIDDEN,
112
+ # reserved write keys
113
+ INPUT,
114
+ INTERRUPT,
115
+ RESUME,
116
+ ERROR,
117
+ ERROR_SOURCE_NODE,
118
+ NO_WRITES,
119
+ # reserved config.configurable keys
120
+ CONFIG_KEY_SEND,
121
+ CONFIG_KEY_READ,
122
+ CONFIG_KEY_CHECKPOINTER,
123
+ CONFIG_KEY_STREAM,
124
+ CONFIG_KEY_CHECKPOINT_MAP,
125
+ CONFIG_KEY_RESUMING,
126
+ CONFIG_KEY_REPLAY_STATE,
127
+ CONFIG_KEY_TASK_ID,
128
+ CONFIG_KEY_CHECKPOINT_MAP,
129
+ CONFIG_KEY_CHECKPOINT_ID,
130
+ CONFIG_KEY_CHECKPOINT_NS,
131
+ CONFIG_KEY_TIMED_ATTEMPT_OBSERVER,
132
+ CONFIG_KEY_RESUME_MAP,
133
+ CONFIG_KEY_STREAM_MESSAGES_V2,
134
+ # other constants
135
+ PUSH,
136
+ PULL,
137
+ NS_SEP,
138
+ NS_END,
139
+ CONF,
140
+ }