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,406 @@
1
+ """Serializable base class."""
2
+
3
+ import contextlib
4
+ import logging
5
+ from abc import ABC
6
+ from typing import (
7
+ Any,
8
+ Literal,
9
+ TypedDict,
10
+ cast,
11
+ )
12
+
13
+ from pydantic import BaseModel, ConfigDict
14
+ from pydantic.fields import FieldInfo
15
+ from pydantic_core import PydanticUndefined
16
+ from typing_extensions import NotRequired, override
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class BaseSerialized(TypedDict):
22
+ """Base class for serialized objects."""
23
+
24
+ lc: int
25
+ """The version of the serialization format."""
26
+ id: list[str]
27
+ """The unique identifier of the object."""
28
+ name: NotRequired[str]
29
+ """The name of the object."""
30
+ graph: NotRequired[dict[str, Any]]
31
+ """The graph of the object."""
32
+
33
+
34
+ class SerializedConstructor(BaseSerialized):
35
+ """Serialized constructor."""
36
+
37
+ type: Literal["constructor"]
38
+ """The type of the object. Must be `'constructor'`."""
39
+ kwargs: dict[str, Any]
40
+ """The constructor arguments."""
41
+
42
+
43
+ class SerializedSecret(BaseSerialized):
44
+ """Serialized secret."""
45
+
46
+ type: Literal["secret"]
47
+ """The type of the object. Must be `'secret'`."""
48
+
49
+
50
+ class SerializedNotImplemented(BaseSerialized):
51
+ """Serialized not implemented."""
52
+
53
+ type: Literal["not_implemented"]
54
+ """The type of the object. Must be `'not_implemented'`."""
55
+ repr: str | None
56
+ """The representation of the object."""
57
+
58
+
59
+ def try_neq_default(value: Any, key: str, model: BaseModel) -> bool:
60
+ """Try to determine if a value is different from the default.
61
+
62
+ Args:
63
+ value: The value.
64
+ key: The key.
65
+ model: The Pydantic model.
66
+
67
+ Returns:
68
+ Whether the value is different from the default.
69
+ """
70
+ field = type(model).model_fields[key]
71
+ return _try_neq_default(value, field)
72
+
73
+
74
+ def _get_field_default(field: FieldInfo) -> Any:
75
+ # Pydantic 2.14+ returns ``PydanticUndefined`` (rather than ``None``) from
76
+ # ``get_default()`` for an un-called ``default_factory``. Restore the historical
77
+ # ``None`` so a factory-defaulted field at its default is still treated as
78
+ # unchanged. The factory is intentionally not called: ``get_default()`` keeps
79
+ # ``call_default_factory=False`` precisely because factories may have side effects.
80
+ default = field.get_default()
81
+ if default is PydanticUndefined and field.default_factory is not None:
82
+ return None
83
+ return default
84
+
85
+
86
+ def _try_neq_default(value: Any, field: FieldInfo) -> bool:
87
+ # Handle edge case: inequality of two objects does not evaluate to a bool (e.g. two
88
+ # Pandas DataFrames).
89
+ try:
90
+ default = _get_field_default(field)
91
+ except Exception as _:
92
+ # A raising default_factory means we cannot compare; treat as non-default.
93
+ return True
94
+ try:
95
+ return bool(default != value)
96
+ except Exception as _:
97
+ try:
98
+ return all(default != value)
99
+ except Exception as _:
100
+ try:
101
+ return value is not field.default
102
+ except Exception as _:
103
+ return False
104
+
105
+
106
+ class Serializable(BaseModel, ABC):
107
+ """Serializable base class.
108
+
109
+ This class is used to serialize objects to JSON.
110
+
111
+ It relies on the following methods and properties:
112
+
113
+ - [`is_lc_serializable`][coco_core.load.serializable.Serializable.is_lc_serializable]: Is this class serializable?
114
+
115
+ By design, even if a class inherits from `Serializable`, it is not serializable
116
+ by default. This is to prevent accidental serialization of objects that should
117
+ not be serialized.
118
+ - [`get_lc_namespace`][coco_core.load.serializable.Serializable.get_lc_namespace]: Get the namespace of the Coco object.
119
+
120
+ During deserialization, this namespace is used to identify
121
+ the correct class to instantiate.
122
+
123
+ Please see the `Reviver` class in `coco_core.load.load` for more details.
124
+
125
+ During deserialization an additional mapping is handle classes that have moved
126
+ or been renamed across package versions.
127
+
128
+ - [`lc_secrets`][coco_core.load.serializable.Serializable.lc_secrets]: A map of constructor argument names to secret ids.
129
+ - [`lc_attributes`][coco_core.load.serializable.Serializable.lc_attributes]: List of additional attribute names that should be included
130
+ as part of the serialized representation.
131
+ """ # noqa: E501
132
+
133
+ # Remove default BaseModel init docstring.
134
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
135
+ """""" # noqa: D419 # Intentional blank docstring
136
+ super().__init__(*args, **kwargs)
137
+
138
+ @classmethod
139
+ def is_lc_serializable(cls) -> bool:
140
+ """Is this class serializable?
141
+
142
+ By design, even if a class inherits from `Serializable`, it is not serializable
143
+ by default. This is to prevent accidental serialization of objects that should
144
+ not be serialized.
145
+
146
+ Returns:
147
+ Whether the class is serializable. Default is `False`.
148
+ """
149
+ return False
150
+
151
+ @classmethod
152
+ def get_lc_namespace(cls) -> list[str]:
153
+ """Get the namespace of the Coco object.
154
+
155
+ The default implementation splits `cls.__module__` on `'.'`, e.g.
156
+ `coco_openai.chat_models` becomes
157
+ `["coco_openai", "chat_models"]`. This value is used by `lc_id` to
158
+ build the serialization identifier.
159
+
160
+ New partner packages should **not** override this method. The default
161
+ behavior is correct for any class whose module path already reflects
162
+ its package name. Some older packages (e.g. `trustcoco-openai`,
163
+ `trustcoco-anthropic`) override it to return a legacy-style namespace
164
+ like `["coco", "chat_models", "openai"]`, matching the module
165
+ paths that existed before those integrations were split out of the
166
+ main `coco` package. Those overrides are kept for
167
+ backwards-compatible deserialization; new packages should not copy them.
168
+
169
+ Deserialization mapping is handled separately by
170
+ `SERIALIZABLE_MAPPING` in `coco_core.load.mapping`.
171
+
172
+ Returns:
173
+ The namespace.
174
+ """
175
+ return cls.__module__.split(".")
176
+
177
+ @property
178
+ def lc_secrets(self) -> dict[str, str]:
179
+ """A map of constructor argument names to secret ids.
180
+
181
+ For example, `{"openai_api_key": "OPENAI_API_KEY"}`
182
+ """
183
+ return {}
184
+
185
+ @property
186
+ def lc_attributes(self) -> dict[str, Any]:
187
+ """List of attribute names that should be included in the serialized kwargs.
188
+
189
+ These attributes must be accepted by the constructor.
190
+
191
+ Default is an empty dictionary.
192
+ """
193
+ return {}
194
+
195
+ @classmethod
196
+ def lc_id(cls) -> list[str]:
197
+ """Return a unique identifier for this class for serialization purposes.
198
+
199
+ The unique identifier is a list of strings that describes the path
200
+ to the object.
201
+
202
+ For example, for the class `coco.llms.openai.OpenAI`, the id is
203
+ `["coco", "llms", "openai", "OpenAI"]`.
204
+ """
205
+ # Pydantic generics change the class name. So we need to do the following
206
+ if (
207
+ "origin" in cls.__pydantic_generic_metadata__
208
+ and cls.__pydantic_generic_metadata__["origin"] is not None
209
+ ):
210
+ original_name = cls.__pydantic_generic_metadata__["origin"].__name__
211
+ else:
212
+ original_name = cls.__name__
213
+ return [*cls.get_lc_namespace(), original_name]
214
+
215
+ model_config = ConfigDict(
216
+ extra="ignore",
217
+ )
218
+
219
+ @override
220
+ def __repr_args__(self) -> Any:
221
+ return [
222
+ (k, v)
223
+ for k, v in super().__repr_args__()
224
+ if (k not in type(self).model_fields or try_neq_default(v, k, self))
225
+ ]
226
+
227
+ def to_json(self) -> SerializedConstructor | SerializedNotImplemented:
228
+ """Serialize the object to JSON.
229
+
230
+ Raises:
231
+ ValueError: If the class has deprecated attributes.
232
+
233
+ Returns:
234
+ A JSON serializable object or a `SerializedNotImplemented` object.
235
+ """
236
+ if not self.is_lc_serializable():
237
+ return self.to_json_not_implemented()
238
+
239
+ model_fields = type(self).model_fields
240
+ secrets = {}
241
+ # Get latest values for kwargs if there is an attribute with same name
242
+ lc_kwargs = {}
243
+ for k, v in self:
244
+ if not _is_field_useful(self, k, v):
245
+ continue
246
+ # Do nothing if the field is excluded
247
+ if k in model_fields and model_fields[k].exclude:
248
+ continue
249
+
250
+ lc_kwargs[k] = getattr(self, k, v)
251
+
252
+ # Merge the lc_secrets and lc_attributes from every class in the MRO
253
+ for cls in [None, *self.__class__.mro()]:
254
+ # Once we get to Serializable, we're done
255
+ if cls is Serializable:
256
+ break
257
+
258
+ if cls:
259
+ deprecated_attributes = [
260
+ "lc_namespace",
261
+ "lc_serializable",
262
+ ]
263
+
264
+ for attr in deprecated_attributes:
265
+ if hasattr(cls, attr):
266
+ msg = (
267
+ f"Class {self.__class__} has a deprecated "
268
+ f"attribute {attr}. Please use the corresponding "
269
+ f"classmethod instead."
270
+ )
271
+ raise ValueError(msg)
272
+
273
+ # Get a reference to self bound to each class in the MRO
274
+ this = cast("Serializable", self if cls is None else super(cls, self))
275
+
276
+ secrets.update(this.lc_secrets)
277
+ # Now also add the aliases for the secrets
278
+ # This ensures known secret aliases are hidden.
279
+ # Note: this does NOT hide any other extra kwargs
280
+ # that are not present in the fields.
281
+ for key in list(secrets):
282
+ value = secrets[key]
283
+ if (key in model_fields) and (
284
+ alias := model_fields[key].alias
285
+ ) is not None:
286
+ secrets[alias] = value
287
+ lc_kwargs.update(this.lc_attributes)
288
+
289
+ # include all secrets, even if not specified in kwargs
290
+ # as these secrets may be passed as an environment variable instead
291
+ for key in secrets:
292
+ secret_value = getattr(self, key, None) or lc_kwargs.get(key)
293
+ if secret_value is not None:
294
+ lc_kwargs.update({key: secret_value})
295
+
296
+ return {
297
+ "lc": 1,
298
+ "type": "constructor",
299
+ "id": self.lc_id(),
300
+ "kwargs": lc_kwargs
301
+ if not secrets
302
+ else _replace_secrets(lc_kwargs, secrets),
303
+ }
304
+
305
+ def to_json_not_implemented(self) -> SerializedNotImplemented:
306
+ """Serialize a "not implemented" object.
307
+
308
+ Returns:
309
+ `SerializedNotImplemented`.
310
+ """
311
+ return to_json_not_implemented(self)
312
+
313
+
314
+ def _is_field_useful(inst: Serializable, key: str, value: Any) -> bool:
315
+ """Check if a field is useful as a constructor argument.
316
+
317
+ Args:
318
+ inst: The instance.
319
+ key: The key.
320
+ value: The value.
321
+
322
+ Returns:
323
+ Whether the field is useful. If the field is required, it is useful.
324
+ If the field is not required, it is useful if the value is not `None`.
325
+ If the field is not required and the value is `None`, it is useful if the
326
+ default value is different from the value.
327
+ """
328
+ field = type(inst).model_fields.get(key)
329
+ if not field:
330
+ return False
331
+
332
+ if field.is_required():
333
+ return True
334
+
335
+ # Handle edge case: a value cannot be converted to a boolean (e.g. a
336
+ # Pandas DataFrame).
337
+ try:
338
+ value_is_truthy = bool(value)
339
+ except Exception as _:
340
+ value_is_truthy = False
341
+
342
+ if value_is_truthy:
343
+ return True
344
+
345
+ # Value is still falsy here!
346
+ if field.default_factory is dict and isinstance(value, dict):
347
+ return False
348
+
349
+ # Value is still falsy here!
350
+ if field.default_factory is list and isinstance(value, list):
351
+ return False
352
+
353
+ value_neq_default = _try_neq_default(value, field)
354
+
355
+ # If value is falsy and does not match the default
356
+ return value_is_truthy or value_neq_default
357
+
358
+
359
+ def _replace_secrets(
360
+ root: dict[Any, Any], secrets_map: dict[str, str]
361
+ ) -> dict[Any, Any]:
362
+ result = root.copy()
363
+ for path, secret_id in secrets_map.items():
364
+ [*parts, last] = path.split(".")
365
+ current = result
366
+ for part in parts:
367
+ if part not in current:
368
+ break
369
+ current[part] = current[part].copy()
370
+ current = current[part]
371
+ if last in current:
372
+ current[last] = {
373
+ "lc": 1,
374
+ "type": "secret",
375
+ "id": [secret_id],
376
+ }
377
+ return result
378
+
379
+
380
+ def to_json_not_implemented(obj: object) -> SerializedNotImplemented:
381
+ """Serialize a "not implemented" object.
382
+
383
+ Args:
384
+ obj: Object to serialize.
385
+
386
+ Returns:
387
+ `SerializedNotImplemented`
388
+ """
389
+ id_: list[str] = []
390
+ try:
391
+ if hasattr(obj, "__name__"):
392
+ id_ = [*obj.__module__.split("."), obj.__name__]
393
+ elif hasattr(obj, "__class__"):
394
+ id_ = [*obj.__class__.__module__.split("."), obj.__class__.__name__]
395
+ except Exception:
396
+ logger.debug("Failed to serialize object", exc_info=True)
397
+
398
+ result: SerializedNotImplemented = {
399
+ "lc": 1,
400
+ "type": "not_implemented",
401
+ "id": id_,
402
+ "repr": None,
403
+ }
404
+ with contextlib.suppress(Exception):
405
+ result["repr"] = repr(obj)
406
+ return result
@@ -0,0 +1,198 @@
1
+ """**Messages** are objects used in prompts and chat conversations."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from coco_core._import_utils import import_attr
6
+ from coco_core.utils.utils import LC_AUTO_PREFIX, LC_ID_PREFIX, ensure_id
7
+
8
+ if TYPE_CHECKING:
9
+ from coco_core.messages.ai import (
10
+ AIMessage,
11
+ AIMessageChunk,
12
+ InputTokenDetails,
13
+ OutputTokenDetails,
14
+ UsageMetadata,
15
+ )
16
+ from coco_core.messages.base import (
17
+ BaseMessage,
18
+ BaseMessageChunk,
19
+ merge_content,
20
+ message_to_dict,
21
+ messages_to_dict,
22
+ )
23
+ from coco_core.messages.block_translators.openai import (
24
+ convert_to_openai_data_block,
25
+ convert_to_openai_image_block,
26
+ )
27
+ from coco_core.messages.chat import ChatMessage, ChatMessageChunk
28
+ from coco_core.messages.content import (
29
+ Annotation,
30
+ AudioContentBlock,
31
+ Citation,
32
+ ContentBlock,
33
+ DataContentBlock,
34
+ FileContentBlock,
35
+ ImageContentBlock,
36
+ InvalidToolCall,
37
+ NonStandardAnnotation,
38
+ NonStandardContentBlock,
39
+ PlainTextContentBlock,
40
+ ReasoningContentBlock,
41
+ ServerToolCall,
42
+ ServerToolCallChunk,
43
+ ServerToolResult,
44
+ TextContentBlock,
45
+ VideoContentBlock,
46
+ is_data_content_block,
47
+ )
48
+ from coco_core.messages.function import FunctionMessage, FunctionMessageChunk
49
+ from coco_core.messages.human import HumanMessage, HumanMessageChunk
50
+ from coco_core.messages.modifier import RemoveMessage
51
+ from coco_core.messages.system import SystemMessage, SystemMessageChunk
52
+ from coco_core.messages.tool import (
53
+ ToolCall,
54
+ ToolCallChunk,
55
+ ToolMessage,
56
+ ToolMessageChunk,
57
+ )
58
+ from coco_core.messages.utils import (
59
+ AnyMessage,
60
+ MessageLikeRepresentation,
61
+ _message_from_dict,
62
+ convert_to_messages,
63
+ convert_to_openai_messages,
64
+ filter_messages,
65
+ get_buffer_string,
66
+ merge_message_runs,
67
+ message_chunk_to_message,
68
+ messages_from_dict,
69
+ trim_messages,
70
+ )
71
+
72
+ __all__ = (
73
+ "LC_AUTO_PREFIX",
74
+ "LC_ID_PREFIX",
75
+ "AIMessage",
76
+ "AIMessageChunk",
77
+ "Annotation",
78
+ "AnyMessage",
79
+ "AudioContentBlock",
80
+ "BaseMessage",
81
+ "BaseMessageChunk",
82
+ "ChatMessage",
83
+ "ChatMessageChunk",
84
+ "Citation",
85
+ "ContentBlock",
86
+ "DataContentBlock",
87
+ "FileContentBlock",
88
+ "FunctionMessage",
89
+ "FunctionMessageChunk",
90
+ "HumanMessage",
91
+ "HumanMessageChunk",
92
+ "ImageContentBlock",
93
+ "InputTokenDetails",
94
+ "InvalidToolCall",
95
+ "MessageLikeRepresentation",
96
+ "NonStandardAnnotation",
97
+ "NonStandardContentBlock",
98
+ "OutputTokenDetails",
99
+ "PlainTextContentBlock",
100
+ "ReasoningContentBlock",
101
+ "RemoveMessage",
102
+ "ServerToolCall",
103
+ "ServerToolCallChunk",
104
+ "ServerToolResult",
105
+ "SystemMessage",
106
+ "SystemMessageChunk",
107
+ "TextContentBlock",
108
+ "ToolCall",
109
+ "ToolCallChunk",
110
+ "ToolMessage",
111
+ "ToolMessageChunk",
112
+ "UsageMetadata",
113
+ "VideoContentBlock",
114
+ "_message_from_dict",
115
+ "convert_to_messages",
116
+ "convert_to_openai_data_block",
117
+ "convert_to_openai_image_block",
118
+ "convert_to_openai_messages",
119
+ "ensure_id",
120
+ "filter_messages",
121
+ "get_buffer_string",
122
+ "is_data_content_block",
123
+ "merge_content",
124
+ "merge_message_runs",
125
+ "message_chunk_to_message",
126
+ "message_to_dict",
127
+ "messages_from_dict",
128
+ "messages_to_dict",
129
+ "trim_messages",
130
+ )
131
+
132
+ _dynamic_imports = {
133
+ "AIMessage": "ai",
134
+ "AIMessageChunk": "ai",
135
+ "Annotation": "content",
136
+ "AudioContentBlock": "content",
137
+ "BaseMessage": "base",
138
+ "BaseMessageChunk": "base",
139
+ "merge_content": "base",
140
+ "message_to_dict": "base",
141
+ "messages_to_dict": "base",
142
+ "Citation": "content",
143
+ "ContentBlock": "content",
144
+ "ChatMessage": "chat",
145
+ "ChatMessageChunk": "chat",
146
+ "DataContentBlock": "content",
147
+ "FileContentBlock": "content",
148
+ "FunctionMessage": "function",
149
+ "FunctionMessageChunk": "function",
150
+ "HumanMessage": "human",
151
+ "HumanMessageChunk": "human",
152
+ "NonStandardAnnotation": "content",
153
+ "NonStandardContentBlock": "content",
154
+ "OutputTokenDetails": "ai",
155
+ "PlainTextContentBlock": "content",
156
+ "ReasoningContentBlock": "content",
157
+ "RemoveMessage": "modifier",
158
+ "ServerToolCall": "content",
159
+ "ServerToolCallChunk": "content",
160
+ "ServerToolResult": "content",
161
+ "SystemMessage": "system",
162
+ "SystemMessageChunk": "system",
163
+ "ImageContentBlock": "content",
164
+ "InputTokenDetails": "ai",
165
+ "InvalidToolCall": "tool",
166
+ "TextContentBlock": "content",
167
+ "ToolCall": "tool",
168
+ "ToolCallChunk": "tool",
169
+ "ToolMessage": "tool",
170
+ "ToolMessageChunk": "tool",
171
+ "UsageMetadata": "ai",
172
+ "VideoContentBlock": "content",
173
+ "AnyMessage": "utils",
174
+ "MessageLikeRepresentation": "utils",
175
+ "_message_from_dict": "utils",
176
+ "convert_to_messages": "utils",
177
+ "convert_to_openai_data_block": "block_translators.openai",
178
+ "convert_to_openai_image_block": "block_translators.openai",
179
+ "convert_to_openai_messages": "utils",
180
+ "filter_messages": "utils",
181
+ "get_buffer_string": "utils",
182
+ "is_data_content_block": "content",
183
+ "merge_message_runs": "utils",
184
+ "message_chunk_to_message": "utils",
185
+ "messages_from_dict": "utils",
186
+ "trim_messages": "utils",
187
+ }
188
+
189
+
190
+ def __getattr__(attr_name: str) -> object:
191
+ module_name = _dynamic_imports.get(attr_name)
192
+ result = import_attr(attr_name, module_name, __spec__.parent)
193
+ globals()[attr_name] = result
194
+ return result
195
+
196
+
197
+ def __dir__() -> list[str]:
198
+ return list(__all__)