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,101 @@
1
+ """`OutputParser` classes parse the output of an LLM call into structured data.
2
+
3
+ !!! tip "Structured output"
4
+
5
+ Output parsers emerged as an early solution to the challenge of obtaining structured
6
+ output from LLMs.
7
+
8
+ Today, most LLMs support [structured output](https://docs.langchain.com/oss/python/langchain/models#structured-outputs)
9
+ natively. In such cases, using output parsers may be unnecessary, and you should
10
+ leverage the model's built-in capabilities for structured output. Refer to the
11
+ [documentation of your chosen model](https://docs.langchain.com/oss/python/integrations/providers/overview)
12
+ for guidance on how to achieve structured output directly.
13
+
14
+ Output parsers remain valuable when working with models that do not support
15
+ structured output natively, or when you require additional processing or validation
16
+ of the model's output beyond its inherent capabilities.
17
+ """
18
+
19
+ from typing import TYPE_CHECKING
20
+
21
+ from coco_core._import_utils import import_attr
22
+
23
+ if TYPE_CHECKING:
24
+ from coco_core.output_parsers.base import (
25
+ BaseGenerationOutputParser,
26
+ BaseLLMOutputParser,
27
+ BaseOutputParser,
28
+ )
29
+ from coco_core.output_parsers.json import (
30
+ JsonOutputParser,
31
+ SimpleJsonOutputParser,
32
+ )
33
+ from coco_core.output_parsers.list import (
34
+ CommaSeparatedListOutputParser,
35
+ ListOutputParser,
36
+ MarkdownListOutputParser,
37
+ NumberedListOutputParser,
38
+ )
39
+ from coco_core.output_parsers.openai_tools import (
40
+ JsonOutputKeyToolsParser,
41
+ JsonOutputToolsParser,
42
+ PydanticToolsParser,
43
+ )
44
+ from coco_core.output_parsers.pydantic import PydanticOutputParser
45
+ from coco_core.output_parsers.string import StrOutputParser
46
+ from coco_core.output_parsers.transform import (
47
+ BaseCumulativeTransformOutputParser,
48
+ BaseTransformOutputParser,
49
+ )
50
+ from coco_core.output_parsers.xml import XMLOutputParser
51
+
52
+ __all__ = [
53
+ "BaseCumulativeTransformOutputParser",
54
+ "BaseGenerationOutputParser",
55
+ "BaseLLMOutputParser",
56
+ "BaseOutputParser",
57
+ "BaseTransformOutputParser",
58
+ "CommaSeparatedListOutputParser",
59
+ "JsonOutputKeyToolsParser",
60
+ "JsonOutputParser",
61
+ "JsonOutputToolsParser",
62
+ "ListOutputParser",
63
+ "MarkdownListOutputParser",
64
+ "NumberedListOutputParser",
65
+ "PydanticOutputParser",
66
+ "PydanticToolsParser",
67
+ "SimpleJsonOutputParser",
68
+ "StrOutputParser",
69
+ "XMLOutputParser",
70
+ ]
71
+
72
+ _dynamic_imports = {
73
+ "BaseLLMOutputParser": "base",
74
+ "BaseGenerationOutputParser": "base",
75
+ "BaseOutputParser": "base",
76
+ "JsonOutputParser": "json",
77
+ "SimpleJsonOutputParser": "json",
78
+ "ListOutputParser": "list",
79
+ "CommaSeparatedListOutputParser": "list",
80
+ "MarkdownListOutputParser": "list",
81
+ "NumberedListOutputParser": "list",
82
+ "JsonOutputKeyToolsParser": "openai_tools",
83
+ "JsonOutputToolsParser": "openai_tools",
84
+ "PydanticToolsParser": "openai_tools",
85
+ "PydanticOutputParser": "pydantic",
86
+ "StrOutputParser": "string",
87
+ "BaseTransformOutputParser": "transform",
88
+ "BaseCumulativeTransformOutputParser": "transform",
89
+ "XMLOutputParser": "xml",
90
+ }
91
+
92
+
93
+ def __getattr__(attr_name: str) -> object:
94
+ module_name = _dynamic_imports.get(attr_name)
95
+ result = import_attr(attr_name, module_name, __spec__.parent)
96
+ globals()[attr_name] = result
97
+ return result
98
+
99
+
100
+ def __dir__() -> list[str]:
101
+ return __all__
@@ -0,0 +1,361 @@
1
+ """Base parser for language model outputs."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import builtins
6
+ import contextlib
7
+ from abc import ABC, abstractmethod
8
+ from typing import (
9
+ TYPE_CHECKING,
10
+ Any,
11
+ Generic,
12
+ TypeVar,
13
+ cast,
14
+ )
15
+
16
+ from typing_extensions import override
17
+
18
+ from coco_core._api import deprecated
19
+ from coco_core.language_models import LanguageModelOutput
20
+ from coco_core.messages import AnyMessage, BaseMessage
21
+ from coco_core.outputs import ChatGeneration, Generation
22
+ from coco_core.runnables import Runnable, RunnableConfig, RunnableSerializable
23
+ from coco_core.runnables.config import run_in_executor
24
+
25
+ if TYPE_CHECKING:
26
+ import builtins
27
+
28
+ from coco_core.prompt_values import PromptValue
29
+
30
+ T = TypeVar("T")
31
+ OutputParserLike = Runnable[LanguageModelOutput, T]
32
+
33
+
34
+ class BaseLLMOutputParser(ABC, Generic[T]):
35
+ """Abstract base class for parsing the outputs of a model."""
36
+
37
+ @abstractmethod
38
+ def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
39
+ """Parse a list of candidate model `Generation` objects into a specific format.
40
+
41
+ Args:
42
+ result: A list of `Generation` to be parsed.
43
+
44
+ The `Generation` objects are assumed to be different candidate outputs
45
+ for a single model input.
46
+ partial: Whether to parse the output as a partial result.
47
+
48
+ This is useful for parsers that can parse partial results.
49
+
50
+ Returns:
51
+ Structured output.
52
+ """
53
+
54
+ async def aparse_result(
55
+ self, result: list[Generation], *, partial: bool = False
56
+ ) -> T:
57
+ """Parse a list of candidate model `Generation` objects into a specific format.
58
+
59
+ Args:
60
+ result: A list of `Generation` to be parsed.
61
+
62
+ The Generations are assumed to be different candidate outputs for a
63
+ single model input.
64
+ partial: Whether to parse the output as a partial result.
65
+
66
+ This is useful for parsers that can parse partial results.
67
+
68
+ Returns:
69
+ Structured output.
70
+ """
71
+ return await run_in_executor(None, self.parse_result, result, partial=partial)
72
+
73
+
74
+ class BaseGenerationOutputParser(
75
+ BaseLLMOutputParser[T], RunnableSerializable[LanguageModelOutput, T]
76
+ ):
77
+ """Base class to parse the output of an LLM call."""
78
+
79
+ @property
80
+ @override
81
+ def InputType(self) -> Any:
82
+ """Return the input type for the parser."""
83
+ return str | AnyMessage
84
+
85
+ @property
86
+ @override
87
+ def OutputType(self) -> type[T]:
88
+ """Return the output type for the parser."""
89
+ # even though mypy complains this isn't valid,
90
+ # it is good enough for pydantic to build the schema from
91
+ return cast("type[T]", T) # type: ignore[misc]
92
+
93
+ @override
94
+ def invoke(
95
+ self,
96
+ input: str | BaseMessage,
97
+ config: RunnableConfig | None = None,
98
+ **kwargs: Any,
99
+ ) -> T:
100
+ if isinstance(input, BaseMessage):
101
+ return self._call_with_config(
102
+ lambda inner_input: self.parse_result(
103
+ [ChatGeneration(message=inner_input)]
104
+ ),
105
+ input,
106
+ config,
107
+ run_type="parser",
108
+ )
109
+ return self._call_with_config(
110
+ lambda inner_input: self.parse_result([Generation(text=inner_input)]),
111
+ input,
112
+ config,
113
+ run_type="parser",
114
+ )
115
+
116
+ @override
117
+ async def ainvoke(
118
+ self,
119
+ input: str | BaseMessage,
120
+ config: RunnableConfig | None = None,
121
+ **kwargs: Any | None,
122
+ ) -> T:
123
+ if isinstance(input, BaseMessage):
124
+ return await self._acall_with_config(
125
+ lambda inner_input: self.aparse_result(
126
+ [ChatGeneration(message=inner_input)]
127
+ ),
128
+ input,
129
+ config,
130
+ run_type="parser",
131
+ )
132
+ return await self._acall_with_config(
133
+ lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
134
+ input,
135
+ config,
136
+ run_type="parser",
137
+ )
138
+
139
+
140
+ class BaseOutputParser(
141
+ BaseLLMOutputParser[T], RunnableSerializable[LanguageModelOutput, T]
142
+ ):
143
+ """Base class to parse the output of an LLM call.
144
+
145
+ Output parsers help structure language model responses.
146
+
147
+ Example:
148
+ ```python
149
+ # Implement a simple boolean output parser
150
+
151
+
152
+ class BooleanOutputParser(BaseOutputParser[bool]):
153
+ true_val: str = "YES"
154
+ false_val: str = "NO"
155
+
156
+ def parse(self, text: str) -> bool:
157
+ cleaned_text = text.strip().upper()
158
+ if cleaned_text not in (
159
+ self.true_val.upper(),
160
+ self.false_val.upper(),
161
+ ):
162
+ raise OutputParserException(
163
+ f"BooleanOutputParser expected output value to either be "
164
+ f"{self.true_val} or {self.false_val} (case-insensitive). "
165
+ f"Received {cleaned_text}."
166
+ )
167
+ return cleaned_text == self.true_val.upper()
168
+
169
+ @property
170
+ def _type(self) -> str:
171
+ return "boolean_output_parser"
172
+ ```
173
+ """
174
+
175
+ @property
176
+ @override
177
+ def InputType(self) -> Any:
178
+ """Return the input type for the parser."""
179
+ return str | AnyMessage
180
+
181
+ @property
182
+ @override
183
+ def OutputType(self) -> type[T]:
184
+ """Return the output type for the parser.
185
+
186
+ This property is inferred from the first type argument of the class.
187
+
188
+ Raises:
189
+ TypeError: If the class doesn't have an inferable `OutputType`.
190
+ """
191
+ for base in self.__class__.mro():
192
+ if hasattr(base, "__pydantic_generic_metadata__"):
193
+ metadata = base.__pydantic_generic_metadata__
194
+ if "args" in metadata and len(metadata["args"]) > 0:
195
+ return cast("type[T]", metadata["args"][0])
196
+
197
+ msg = (
198
+ f"Runnable {self.__class__.__name__} doesn't have an inferable OutputType. "
199
+ "Override the OutputType property to specify the output type."
200
+ )
201
+ raise TypeError(msg)
202
+
203
+ @override
204
+ def invoke(
205
+ self,
206
+ input: str | BaseMessage,
207
+ config: RunnableConfig | None = None,
208
+ **kwargs: Any,
209
+ ) -> T:
210
+ if isinstance(input, BaseMessage):
211
+ return self._call_with_config(
212
+ lambda inner_input: self.parse_result(
213
+ [ChatGeneration(message=inner_input)]
214
+ ),
215
+ input,
216
+ config,
217
+ run_type="parser",
218
+ )
219
+ return self._call_with_config(
220
+ lambda inner_input: self.parse_result([Generation(text=inner_input)]),
221
+ input,
222
+ config,
223
+ run_type="parser",
224
+ )
225
+
226
+ @override
227
+ async def ainvoke(
228
+ self,
229
+ input: str | BaseMessage,
230
+ config: RunnableConfig | None = None,
231
+ **kwargs: Any | None,
232
+ ) -> T:
233
+ if isinstance(input, BaseMessage):
234
+ return await self._acall_with_config(
235
+ lambda inner_input: self.aparse_result(
236
+ [ChatGeneration(message=inner_input)]
237
+ ),
238
+ input,
239
+ config,
240
+ run_type="parser",
241
+ )
242
+ return await self._acall_with_config(
243
+ lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
244
+ input,
245
+ config,
246
+ run_type="parser",
247
+ )
248
+
249
+ @override
250
+ def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
251
+ """Parse a list of candidate model `Generation` objects into a specific format.
252
+
253
+ The return value is parsed from only the first `Generation` in the result, which
254
+ is assumed to be the highest-likelihood `Generation`.
255
+
256
+ Args:
257
+ result: A list of `Generation` to be parsed.
258
+
259
+ The `Generation` objects are assumed to be different candidate outputs
260
+ for a single model input.
261
+ partial: Whether to parse the output as a partial result.
262
+
263
+ This is useful for parsers that can parse partial results.
264
+
265
+ Returns:
266
+ Structured output.
267
+ """
268
+ return self.parse(result[0].text)
269
+
270
+ @abstractmethod
271
+ def parse(self, text: str) -> T:
272
+ """Parse a single string model output into some structure.
273
+
274
+ Args:
275
+ text: String output of a language model.
276
+
277
+ Returns:
278
+ Structured output.
279
+ """
280
+
281
+ async def aparse_result(
282
+ self, result: list[Generation], *, partial: bool = False
283
+ ) -> T:
284
+ """Parse a list of candidate model `Generation` objects into a specific format.
285
+
286
+ The return value is parsed from only the first `Generation` in the result, which
287
+ is assumed to be the highest-likelihood `Generation`.
288
+
289
+ Args:
290
+ result: A list of `Generation` to be parsed.
291
+
292
+ The `Generation` objects are assumed to be different candidate outputs
293
+ for a single model input.
294
+ partial: Whether to parse the output as a partial result.
295
+
296
+ This is useful for parsers that can parse partial results.
297
+
298
+ Returns:
299
+ Structured output.
300
+ """
301
+ return await run_in_executor(None, self.parse_result, result, partial=partial)
302
+
303
+ async def aparse(self, text: str) -> T:
304
+ """Async parse a single string model output into some structure.
305
+
306
+ Args:
307
+ text: String output of a language model.
308
+
309
+ Returns:
310
+ Structured output.
311
+ """
312
+ return await run_in_executor(None, self.parse, text)
313
+
314
+ # TODO: rename 'completion' -> 'text'.
315
+ def parse_with_prompt(
316
+ self,
317
+ completion: str,
318
+ prompt: PromptValue, # noqa: ARG002
319
+ ) -> Any:
320
+ """Parse the output of an LLM call with the input prompt for context.
321
+
322
+ The prompt is largely provided in the event the `OutputParser` wants to retry or
323
+ fix the output in some way, and needs information from the prompt to do so.
324
+
325
+ Args:
326
+ completion: String output of a language model.
327
+ prompt: Input `PromptValue`.
328
+
329
+ Returns:
330
+ Structured output.
331
+ """
332
+ return self.parse(completion)
333
+
334
+ def get_format_instructions(self) -> str:
335
+ """Instructions on how the LLM output should be formatted."""
336
+ raise NotImplementedError
337
+
338
+ @property
339
+ def _type(self) -> str:
340
+ """Return the output parser type for serialization."""
341
+ msg = (
342
+ f"_type property is not implemented in class {self.__class__.__name__}."
343
+ " This is required for serialization."
344
+ )
345
+ raise NotImplementedError(msg)
346
+
347
+ @deprecated("1.4.2", alternative="asdict", removal="2.0.0")
348
+ @override
349
+ def dict(self, **kwargs: Any) -> builtins.dict[str, Any]:
350
+ """DEPRECATED - use `asdict()` instead.
351
+
352
+ Return a dictionary representation of the output parser.
353
+ """
354
+ return self.asdict(**kwargs)
355
+
356
+ def asdict(self, **kwargs: Any) -> builtins.dict[str, Any]:
357
+ """Return a dictionary representation of the output parser."""
358
+ output_parser_dict = super().model_dump(**kwargs)
359
+ with contextlib.suppress(NotImplementedError):
360
+ output_parser_dict["_type"] = self._type
361
+ return output_parser_dict
@@ -0,0 +1,16 @@
1
+ """Format instructions."""
2
+
3
+ JSON_FORMAT_INSTRUCTIONS = """STRICT OUTPUT FORMAT:
4
+ - Return only the JSON value that conforms to the schema. Do not include any additional text, explanations, headings, or separators.
5
+ - Do not wrap the JSON in Markdown or code fences (no ``` or ```json).
6
+ - Do not prepend or append any text (e.g., do not write "Here is the JSON:").
7
+ - The response must be a single top-level JSON value exactly as required by the schema (object/array/etc.), with no trailing commas or comments.
8
+
9
+ The output should be formatted as a JSON instance that conforms to the JSON schema below.
10
+
11
+ As an example, for the schema {{"properties": {{"foo": {{"title": "Foo", "description": "a list of strings", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}} the object {{"foo": ["bar", "baz"]}} is a well-formatted instance of the schema. The object {{"properties": {{"foo": ["bar", "baz"]}}}} is not well-formatted.
12
+
13
+ Here is the output schema (shown in a code block for readability only — do not include any backticks or Markdown in your output):
14
+ ```
15
+ {schema}
16
+ ```""" # noqa: E501
@@ -0,0 +1,139 @@
1
+ """Parser for JSON output."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from json import JSONDecodeError
7
+ from typing import Annotated, Any, TypeVar
8
+
9
+ import jsonpatch # type: ignore[import-untyped]
10
+ import pydantic
11
+ from pydantic import SkipValidation
12
+ from pydantic.v1 import BaseModel
13
+ from typing_extensions import override
14
+
15
+ from coco_core.exceptions import OutputParserException
16
+ from coco_core.output_parsers.format_instructions import JSON_FORMAT_INSTRUCTIONS
17
+ from coco_core.output_parsers.transform import BaseCumulativeTransformOutputParser
18
+ from coco_core.outputs import Generation
19
+ from coco_core.utils.json import (
20
+ parse_and_check_json_markdown,
21
+ parse_json_markdown,
22
+ parse_partial_json,
23
+ )
24
+
25
+ # Union type needs to be last assignment to PydanticBaseModel to make mypy happy.
26
+ PydanticBaseModel = BaseModel | pydantic.BaseModel
27
+
28
+ TBaseModel = TypeVar("TBaseModel", bound=PydanticBaseModel)
29
+
30
+
31
+ class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]):
32
+ """Parse the output of an LLM call to a JSON object.
33
+
34
+ Probably the most reliable output parser for getting structured data that does *not*
35
+ use function calling.
36
+
37
+ When used in streaming mode, it will yield partial JSON objects containing all the
38
+ keys that have been returned so far.
39
+
40
+ In streaming, if `diff` is set to `True`, yields `JSONPatch` operations describing
41
+ the difference between the previous and the current object.
42
+ """
43
+
44
+ pydantic_object: Annotated[type[TBaseModel] | None, SkipValidation()] = None # type: ignore[valid-type]
45
+ """The Pydantic object to use for validation.
46
+
47
+ If `None`, no validation is performed.
48
+ """
49
+
50
+ @override
51
+ def _diff(self, prev: Any | None, next: Any) -> Any:
52
+ return jsonpatch.make_patch(prev, next).patch
53
+
54
+ @staticmethod
55
+ def _get_schema(pydantic_object: type[TBaseModel]) -> dict[str, Any]:
56
+ if issubclass(pydantic_object, pydantic.BaseModel):
57
+ return pydantic_object.model_json_schema()
58
+ return pydantic_object.schema()
59
+
60
+ @override
61
+ def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
62
+ """Parse the result of an LLM call to a JSON object.
63
+
64
+ Args:
65
+ result: The result of the LLM call.
66
+ partial: Whether to parse partial JSON objects.
67
+
68
+ If `True`, the output will be a JSON object containing all the keys that
69
+ have been returned so far.
70
+
71
+ If `False`, the output will be the full JSON object.
72
+
73
+ Returns:
74
+ The parsed JSON object.
75
+
76
+ Raises:
77
+ OutputParserException: If the output is not valid JSON.
78
+ """
79
+ text = result[0].text
80
+ text = text.strip()
81
+ if partial:
82
+ try:
83
+ return parse_json_markdown(text)
84
+ except JSONDecodeError:
85
+ return None
86
+ else:
87
+ try:
88
+ return parse_json_markdown(text)
89
+ except JSONDecodeError as e:
90
+ msg = f"Invalid json output: {text}"
91
+ raise OutputParserException(msg, llm_output=text) from e
92
+
93
+ def parse(self, text: str) -> Any:
94
+ """Parse the output of an LLM call to a JSON object.
95
+
96
+ Args:
97
+ text: The output of the LLM call.
98
+
99
+ Returns:
100
+ The parsed JSON object.
101
+ """
102
+ return self.parse_result([Generation(text=text)])
103
+
104
+ def get_format_instructions(self) -> str:
105
+ """Return the format instructions for the JSON output.
106
+
107
+ Returns:
108
+ The format instructions for the JSON output.
109
+ """
110
+ if self.pydantic_object is None:
111
+ return "Return a JSON object."
112
+ # Copy schema to avoid altering original Pydantic schema.
113
+ schema = dict(self._get_schema(self.pydantic_object).items())
114
+
115
+ # Remove extraneous fields.
116
+ reduced_schema = schema
117
+ if "title" in reduced_schema:
118
+ del reduced_schema["title"]
119
+ if "type" in reduced_schema:
120
+ del reduced_schema["type"]
121
+ # Ensure json in context is well-formed with double quotes.
122
+ schema_str = json.dumps(reduced_schema, ensure_ascii=False)
123
+ return JSON_FORMAT_INSTRUCTIONS.format(schema=schema_str)
124
+
125
+ @property
126
+ def _type(self) -> str:
127
+ return "simple_json_output_parser"
128
+
129
+
130
+ # For backwards compatibility
131
+ SimpleJsonOutputParser = JsonOutputParser
132
+
133
+
134
+ __all__ = [
135
+ "JsonOutputParser",
136
+ "SimpleJsonOutputParser", # For backwards compatibility
137
+ "parse_and_check_json_markdown", # For backwards compatibility
138
+ "parse_partial_json", # For backwards compatibility
139
+ ]