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,123 @@
1
+ """Callback handler that prints to std out."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from typing_extensions import override
8
+
9
+ from coco_core.callbacks.base import BaseCallbackHandler
10
+ from coco_core.utils import print_text
11
+
12
+ if TYPE_CHECKING:
13
+ from coco_core.agents import AgentAction, AgentFinish
14
+
15
+
16
+ class StdOutCallbackHandler(BaseCallbackHandler):
17
+ """Callback handler that prints to std out."""
18
+
19
+ def __init__(self, color: str | None = None) -> None:
20
+ """Initialize callback handler.
21
+
22
+ Args:
23
+ color: The color to use for the text.
24
+ """
25
+ self.color = color
26
+
27
+ @override
28
+ def on_chain_start(
29
+ self, serialized: dict[str, Any], inputs: dict[str, Any], **kwargs: Any
30
+ ) -> None:
31
+ """Print out that we are entering a chain.
32
+
33
+ Args:
34
+ serialized: The serialized chain.
35
+ inputs: The inputs to the chain.
36
+ **kwargs: Additional keyword arguments.
37
+ """
38
+ if "name" in kwargs:
39
+ name = kwargs["name"]
40
+ elif serialized:
41
+ name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
42
+ else:
43
+ name = "<unknown>"
44
+ print(f"\n\n\033[1m> Entering new {name} chain...\033[0m") # noqa: T201
45
+
46
+ @override
47
+ def on_chain_end(self, outputs: dict[str, Any], **kwargs: Any) -> None:
48
+ """Print out that we finished a chain.
49
+
50
+ Args:
51
+ outputs: The outputs of the chain.
52
+ **kwargs: Additional keyword arguments.
53
+ """
54
+ print("\n\033[1m> Finished chain.\033[0m") # noqa: T201
55
+
56
+ @override
57
+ def on_agent_action(
58
+ self, action: AgentAction, color: str | None = None, **kwargs: Any
59
+ ) -> Any:
60
+ """Run on agent action.
61
+
62
+ Args:
63
+ action: The agent action.
64
+ color: The color to use for the text.
65
+ **kwargs: Additional keyword arguments.
66
+ """
67
+ print_text(action.log, color=color or self.color)
68
+
69
+ @override
70
+ def on_tool_end(
71
+ self,
72
+ output: Any,
73
+ color: str | None = None,
74
+ observation_prefix: str | None = None,
75
+ llm_prefix: str | None = None,
76
+ **kwargs: Any,
77
+ ) -> None:
78
+ """If not the final action, print out observation.
79
+
80
+ Args:
81
+ output: The output to print.
82
+ color: The color to use for the text.
83
+ observation_prefix: The observation prefix.
84
+ llm_prefix: The LLM prefix.
85
+ **kwargs: Additional keyword arguments.
86
+ """
87
+ output = str(output)
88
+ if observation_prefix is not None:
89
+ print_text(f"\n{observation_prefix}")
90
+ print_text(output, color=color or self.color)
91
+ if llm_prefix is not None:
92
+ print_text(f"\n{llm_prefix}")
93
+
94
+ @override
95
+ def on_text(
96
+ self,
97
+ text: str,
98
+ color: str | None = None,
99
+ end: str = "",
100
+ **kwargs: Any,
101
+ ) -> None:
102
+ """Run when the agent ends.
103
+
104
+ Args:
105
+ text: The text to print.
106
+ color: The color to use for the text.
107
+ end: The end character to use.
108
+ **kwargs: Additional keyword arguments.
109
+ """
110
+ print_text(text, color=color or self.color, end=end)
111
+
112
+ @override
113
+ def on_agent_finish(
114
+ self, finish: AgentFinish, color: str | None = None, **kwargs: Any
115
+ ) -> None:
116
+ """Run on the agent end.
117
+
118
+ Args:
119
+ finish: The agent finish.
120
+ color: The color to use for the text.
121
+ **kwargs: Additional keyword arguments.
122
+ """
123
+ print_text(finish.log, color=color or self.color, end="\n")
@@ -0,0 +1,154 @@
1
+ """Callback Handler streams to stdout on new llm token."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from typing_extensions import override
9
+
10
+ from coco_core.callbacks.base import BaseCallbackHandler
11
+
12
+ if TYPE_CHECKING:
13
+ from coco_core.agents import AgentAction, AgentFinish
14
+ from coco_core.messages import BaseMessage
15
+ from coco_core.outputs import LLMResult
16
+
17
+
18
+ class StreamingStdOutCallbackHandler(BaseCallbackHandler):
19
+ """Callback handler for streaming.
20
+
21
+ !!! warning "Only works with LLMs that support streaming."
22
+ """
23
+
24
+ def on_llm_start(
25
+ self, serialized: dict[str, Any], prompts: list[str], **kwargs: Any
26
+ ) -> None:
27
+ """Run when LLM starts running.
28
+
29
+ Args:
30
+ serialized: The serialized LLM.
31
+ prompts: The prompts to run.
32
+ **kwargs: Additional keyword arguments.
33
+ """
34
+
35
+ def on_chat_model_start(
36
+ self,
37
+ serialized: dict[str, Any],
38
+ messages: list[list[BaseMessage]],
39
+ **kwargs: Any,
40
+ ) -> None:
41
+ """Run when LLM starts running.
42
+
43
+ Args:
44
+ serialized: The serialized LLM.
45
+ messages: The messages to run.
46
+ **kwargs: Additional keyword arguments.
47
+ """
48
+
49
+ @override
50
+ def on_llm_new_token(
51
+ self, token: str | list[str | dict[str, Any]], **kwargs: Any
52
+ ) -> None:
53
+ """Run on new LLM token. Only available when streaming is enabled.
54
+
55
+ Args:
56
+ token: The new token, or a list of content blocks.
57
+ **kwargs: Additional keyword arguments.
58
+ """
59
+ sys.stdout.write(str(token))
60
+ sys.stdout.flush()
61
+
62
+ def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
63
+ """Run when LLM ends running.
64
+
65
+ Args:
66
+ response: The response from the LLM.
67
+ **kwargs: Additional keyword arguments.
68
+ """
69
+
70
+ def on_llm_error(self, error: BaseException, **kwargs: Any) -> None:
71
+ """Run when LLM errors.
72
+
73
+ Args:
74
+ error: The error that occurred.
75
+ **kwargs: Additional keyword arguments.
76
+ """
77
+
78
+ def on_chain_start(
79
+ self, serialized: dict[str, Any], inputs: dict[str, Any], **kwargs: Any
80
+ ) -> None:
81
+ """Run when a chain starts running.
82
+
83
+ Args:
84
+ serialized: The serialized chain.
85
+ inputs: The inputs to the chain.
86
+ **kwargs: Additional keyword arguments.
87
+ """
88
+
89
+ def on_chain_end(self, outputs: dict[str, Any], **kwargs: Any) -> None:
90
+ """Run when a chain ends running.
91
+
92
+ Args:
93
+ outputs: The outputs of the chain.
94
+ **kwargs: Additional keyword arguments.
95
+ """
96
+
97
+ def on_chain_error(self, error: BaseException, **kwargs: Any) -> None:
98
+ """Run when chain errors.
99
+
100
+ Args:
101
+ error: The error that occurred.
102
+ **kwargs: Additional keyword arguments.
103
+ """
104
+
105
+ def on_tool_start(
106
+ self, serialized: dict[str, Any], input_str: str, **kwargs: Any
107
+ ) -> None:
108
+ """Run when the tool starts running.
109
+
110
+ Args:
111
+ serialized: The serialized tool.
112
+ input_str: The input string.
113
+ **kwargs: Additional keyword arguments.
114
+ """
115
+
116
+ def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:
117
+ """Run on agent action.
118
+
119
+ Args:
120
+ action: The agent action.
121
+ **kwargs: Additional keyword arguments.
122
+ """
123
+
124
+ def on_tool_end(self, output: Any, **kwargs: Any) -> None:
125
+ """Run when tool ends running.
126
+
127
+ Args:
128
+ output: The output of the tool.
129
+ **kwargs: Additional keyword arguments.
130
+ """
131
+
132
+ def on_tool_error(self, error: BaseException, **kwargs: Any) -> None:
133
+ """Run when tool errors.
134
+
135
+ Args:
136
+ error: The error that occurred.
137
+ **kwargs: Additional keyword arguments.
138
+ """
139
+
140
+ def on_text(self, text: str, **kwargs: Any) -> None:
141
+ """Run on an arbitrary text.
142
+
143
+ Args:
144
+ text: The text to print.
145
+ **kwargs: Additional keyword arguments.
146
+ """
147
+
148
+ def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:
149
+ """Run on the agent end.
150
+
151
+ Args:
152
+ finish: The agent finish.
153
+ **kwargs: Additional keyword arguments.
154
+ """
@@ -0,0 +1,124 @@
1
+ """Callback Handler that tracks `AIMessage.usage_metadata`."""
2
+
3
+ import threading
4
+ from collections.abc import Generator
5
+ from contextlib import contextmanager
6
+ from contextvars import ContextVar
7
+ from typing import Any
8
+
9
+ from typing_extensions import override
10
+
11
+ from coco_core.callbacks import BaseCallbackHandler
12
+ from coco_core.messages import AIMessage
13
+ from coco_core.messages.ai import UsageMetadata, add_usage
14
+ from coco_core.outputs import ChatGeneration, LLMResult
15
+ from coco_core.tracers.context import register_configure_hook
16
+
17
+
18
+ class UsageMetadataCallbackHandler(BaseCallbackHandler):
19
+ """Callback Handler that tracks `AIMessage.usage_metadata`.
20
+
21
+ Example:
22
+ ```python
23
+ from coco.chat_models import init_chat_model
24
+ from coco_core.callbacks import UsageMetadataCallbackHandler
25
+
26
+ llm_1 = init_chat_model(model="openai:gpt-5.5")
27
+ llm_2 = init_chat_model(model="anthropic:claude-haiku-4-5-20251001")
28
+
29
+ callback = UsageMetadataCallbackHandler()
30
+ result_1 = llm_1.invoke("Hello", config={"callbacks": [callback]})
31
+ result_2 = llm_2.invoke("Hello", config={"callbacks": [callback]})
32
+ callback.usage_metadata
33
+ ```
34
+
35
+ !!! version-added "Added in `trustcoco-core` 0.3.49"
36
+
37
+ """
38
+
39
+ def __init__(self) -> None:
40
+ """Initialize the `UsageMetadataCallbackHandler`."""
41
+ super().__init__()
42
+ self._lock = threading.Lock()
43
+ self.usage_metadata: dict[str, UsageMetadata] = {}
44
+
45
+ @override
46
+ def __repr__(self) -> str:
47
+ return str(self.usage_metadata)
48
+
49
+ @override
50
+ def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
51
+ """Collect token usage."""
52
+ # Check for usage_metadata (trustcoco-core >= 0.2.2)
53
+ try:
54
+ generation = response.generations[0][0]
55
+ except IndexError:
56
+ generation = None
57
+
58
+ usage_metadata = None
59
+ model_name = None
60
+ if isinstance(generation, ChatGeneration):
61
+ try:
62
+ message = generation.message
63
+ if isinstance(message, AIMessage):
64
+ usage_metadata = message.usage_metadata
65
+ model_name = message.response_metadata.get("model_name")
66
+ except AttributeError:
67
+ pass
68
+
69
+ # update shared state behind lock
70
+ if usage_metadata and model_name:
71
+ with self._lock:
72
+ if model_name not in self.usage_metadata:
73
+ self.usage_metadata[model_name] = usage_metadata
74
+ else:
75
+ self.usage_metadata[model_name] = add_usage(
76
+ self.usage_metadata[model_name], usage_metadata
77
+ )
78
+
79
+
80
+ @contextmanager
81
+ def get_usage_metadata_callback(
82
+ name: str = "usage_metadata_callback",
83
+ ) -> Generator[UsageMetadataCallbackHandler, None, None]:
84
+ """Get usage metadata callback.
85
+
86
+ Get context manager for tracking usage metadata across chat model calls using
87
+ [`AIMessage.usage_metadata`][coco.messages.AIMessage.usage_metadata].
88
+
89
+ Args:
90
+ name: The name of the context variable.
91
+
92
+ Yields:
93
+ The usage metadata callback.
94
+
95
+ Example:
96
+ ```python
97
+ from coco.chat_models import init_chat_model
98
+ from coco_core.callbacks import get_usage_metadata_callback
99
+
100
+ llm_1 = init_chat_model(model="openai:gpt-5.5")
101
+ llm_2 = init_chat_model(model="anthropic:claude-haiku-4-5-20251001")
102
+
103
+ with get_usage_metadata_callback() as cb:
104
+ llm_1.invoke("Hello")
105
+ llm_2.invoke("Hello")
106
+ print(cb.usage_metadata)
107
+ ```
108
+
109
+ !!! version-added "Added in `trustcoco-core` 0.3.49"
110
+
111
+ """
112
+ usage_metadata_callback_var: ContextVar[UsageMetadataCallbackHandler | None] = (
113
+ ContextVar(name, default=None)
114
+ )
115
+ register_configure_hook(usage_metadata_callback_var, inheritable=True)
116
+ cb = UsageMetadataCallbackHandler()
117
+ token = usage_metadata_callback_var.set(cb)
118
+ try:
119
+ yield cb
120
+ finally:
121
+ # Always clear the context var, including when the with-block raises.
122
+ # Without finally, post-block model calls keep accumulating into cb
123
+ # (see #38989).
124
+ usage_metadata_callback_var.reset(token)
@@ -0,0 +1,267 @@
1
+ """Chat message history stores a history of the message interactions in a chat."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from pydantic import BaseModel, Field
9
+
10
+ from coco_core._api import deprecated
11
+ from coco_core.messages import (
12
+ AIMessage,
13
+ BaseMessage,
14
+ HumanMessage,
15
+ get_buffer_string,
16
+ )
17
+ from coco_core.runnables.config import run_in_executor
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Sequence
21
+
22
+
23
+ @deprecated(
24
+ since="1.6.4",
25
+ removal="2.0.0",
26
+ addendum=(
27
+ "See the short-term memory documentation for recommended alternatives: "
28
+ "https://docs.langchain.com/oss/python/langchain/short-term-memory"
29
+ ),
30
+ )
31
+ class BaseChatMessageHistory(ABC):
32
+ """Abstract base class for storing chat message history.
33
+
34
+ Implementations guidelines:
35
+
36
+ Implementations are expected to over-ride all or some of the following methods:
37
+
38
+ * `add_messages`: sync variant for bulk addition of messages
39
+ * `aadd_messages`: async variant for bulk addition of messages
40
+ * `messages`: sync variant for getting messages
41
+ * `aget_messages`: async variant for getting messages
42
+ * `clear`: sync variant for clearing messages
43
+ * `aclear`: async variant for clearing messages
44
+
45
+ `add_messages` contains a default implementation that calls `add_message`
46
+ for each message in the sequence. This is provided for backwards compatibility
47
+ with existing implementations which only had `add_message`.
48
+
49
+ Async variants all have default implementations that call the sync variants.
50
+ Implementers can choose to override the async implementations to provide
51
+ truly async implementations.
52
+
53
+ Usage guidelines:
54
+
55
+ When used for updating history, users should favor usage of `add_messages`
56
+ over `add_message` or other variants like `add_user_message` and `add_ai_message`
57
+ to avoid unnecessary round-trips to the underlying persistence layer.
58
+
59
+ Example:
60
+ ```python
61
+ import json
62
+ import os
63
+ from coco_core.messages import messages_from_dict, message_to_dict
64
+
65
+
66
+ class FileChatMessageHistory(BaseChatMessageHistory):
67
+ storage_path: str
68
+ session_id: str
69
+
70
+ @property
71
+ def messages(self) -> list[BaseMessage]:
72
+ try:
73
+ with open(
74
+ os.path.join(self.storage_path, self.session_id),
75
+ "r",
76
+ encoding="utf-8",
77
+ ) as f:
78
+ messages_data = json.load(f)
79
+ return messages_from_dict(messages_data)
80
+ except FileNotFoundError:
81
+ return []
82
+
83
+ def add_messages(self, messages: Sequence[BaseMessage]) -> None:
84
+ all_messages = list(self.messages) # Existing messages
85
+ all_messages.extend(messages) # Add new messages
86
+
87
+ serialized = [message_to_dict(message) for message in all_messages]
88
+ file_path = os.path.join(self.storage_path, self.session_id)
89
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
90
+ with open(file_path, "w", encoding="utf-8") as f:
91
+ json.dump(serialized, f)
92
+
93
+ def clear(self) -> None:
94
+ file_path = os.path.join(self.storage_path, self.session_id)
95
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
96
+ with open(file_path, "w", encoding="utf-8") as f:
97
+ json.dump([], f)
98
+ ```
99
+ """
100
+
101
+ messages: list[BaseMessage]
102
+ """A property or attribute that returns a list of messages.
103
+
104
+ In general, getting the messages may involve IO to the underlying persistence
105
+ layer, so this operation is expected to incur some latency.
106
+ """
107
+
108
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
109
+ """Initialize cooperatively to preserve multiple inheritance."""
110
+ super().__init__(*args, **kwargs)
111
+
112
+ async def aget_messages(self) -> list[BaseMessage]:
113
+ """Async version of getting messages.
114
+
115
+ Can over-ride this method to provide an efficient async implementation.
116
+
117
+ In general, fetching messages may involve IO to the underlying persistence
118
+ layer.
119
+
120
+ Returns:
121
+ The messages.
122
+ """
123
+ return await run_in_executor(None, lambda: self.messages)
124
+
125
+ def add_user_message(self, message: HumanMessage | str) -> None:
126
+ """Convenience method for adding a human message string to the store.
127
+
128
+ !!! note
129
+
130
+ This is a convenience method. Code should favor the bulk `add_messages`
131
+ interface instead to save on round-trips to the persistence layer.
132
+
133
+ This method may be deprecated in a future release.
134
+
135
+ Args:
136
+ message: The `HumanMessage` to add to the store.
137
+ """
138
+ if isinstance(message, HumanMessage):
139
+ self.add_message(message)
140
+ else:
141
+ self.add_message(HumanMessage(content=message))
142
+
143
+ def add_ai_message(self, message: AIMessage | str) -> None:
144
+ """Convenience method for adding an `AIMessage` string to the store.
145
+
146
+ !!! note
147
+
148
+ This is a convenience method. Code should favor the bulk `add_messages`
149
+ interface instead to save on round-trips to the persistence layer.
150
+
151
+ This method may be deprecated in a future release.
152
+
153
+ Args:
154
+ message: The `AIMessage` to add.
155
+ """
156
+ if isinstance(message, AIMessage):
157
+ self.add_message(message)
158
+ else:
159
+ self.add_message(AIMessage(content=message))
160
+
161
+ def add_message(self, message: BaseMessage) -> None:
162
+ """Add a Message object to the store.
163
+
164
+ Args:
165
+ message: A `BaseMessage` object to store.
166
+
167
+ Raises:
168
+ NotImplementedError: If the sub-class has not implemented an efficient
169
+ `add_messages` method.
170
+ """
171
+ if type(self).add_messages != BaseChatMessageHistory.add_messages:
172
+ # This means that the sub-class has implemented an efficient add_messages
173
+ # method, so we should use it.
174
+ self.add_messages([message])
175
+ else:
176
+ msg = (
177
+ "add_message is not implemented for this class. "
178
+ "Please implement add_message or add_messages."
179
+ )
180
+ raise NotImplementedError(msg)
181
+
182
+ def add_messages(self, messages: Sequence[BaseMessage]) -> None:
183
+ """Add a list of messages.
184
+
185
+ Implementations should over-ride this method to handle bulk addition of messages
186
+ in an efficient manner to avoid unnecessary round-trips to the underlying store.
187
+
188
+ Args:
189
+ messages: A sequence of `BaseMessage` objects to store.
190
+ """
191
+ for message in messages:
192
+ self.add_message(message)
193
+
194
+ async def aadd_messages(self, messages: Sequence[BaseMessage]) -> None:
195
+ """Async add a list of messages.
196
+
197
+ Args:
198
+ messages: A sequence of `BaseMessage` objects to store.
199
+ """
200
+ await run_in_executor(None, self.add_messages, messages)
201
+
202
+ @abstractmethod
203
+ def clear(self) -> None:
204
+ """Remove all messages from the store."""
205
+
206
+ async def aclear(self) -> None:
207
+ """Async remove all messages from the store."""
208
+ await run_in_executor(None, self.clear)
209
+
210
+ def __str__(self) -> str:
211
+ """Return a string representation of the chat history."""
212
+ return get_buffer_string(self.messages)
213
+
214
+
215
+ @deprecated(
216
+ since="1.6.4",
217
+ removal="2.0.0",
218
+ addendum=(
219
+ "See the short-term memory documentation for recommended alternatives: "
220
+ "https://docs.langchain.com/oss/python/langchain/short-term-memory"
221
+ ),
222
+ )
223
+ class InMemoryChatMessageHistory(BaseChatMessageHistory, BaseModel):
224
+ """In memory implementation of chat message history.
225
+
226
+ Stores messages in a memory list.
227
+ """
228
+
229
+ messages: list[BaseMessage] = Field(default_factory=list)
230
+ """A list of messages stored in memory."""
231
+
232
+ async def aget_messages(self) -> list[BaseMessage]:
233
+ """Async version of getting messages.
234
+
235
+ Can over-ride this method to provide an efficient async implementation.
236
+
237
+ In general, fetching messages may involve IO to the underlying persistence
238
+ layer.
239
+
240
+ Returns:
241
+ List of messages.
242
+ """
243
+ return self.messages
244
+
245
+ def add_message(self, message: BaseMessage) -> None:
246
+ """Add a self-created message to the store.
247
+
248
+ Args:
249
+ message: The message to add.
250
+ """
251
+ self.messages.append(message)
252
+
253
+ async def aadd_messages(self, messages: Sequence[BaseMessage]) -> None:
254
+ """Async add messages to the store.
255
+
256
+ Args:
257
+ messages: The messages to add.
258
+ """
259
+ self.add_messages(messages)
260
+
261
+ def clear(self) -> None:
262
+ """Clear all messages from the store."""
263
+ self.messages = []
264
+
265
+ async def aclear(self) -> None:
266
+ """Async clear all messages from the store."""
267
+ self.clear()
@@ -0,0 +1,26 @@
1
+ """Chat loaders."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from collections.abc import Iterator
5
+
6
+ from coco_core.chat_sessions import ChatSession
7
+
8
+
9
+ class BaseChatLoader(ABC):
10
+ """Base class for chat loaders."""
11
+
12
+ @abstractmethod
13
+ def lazy_load(self) -> Iterator[ChatSession]:
14
+ """Lazy load the chat sessions.
15
+
16
+ Returns:
17
+ An iterator of chat sessions.
18
+ """
19
+
20
+ def load(self) -> list[ChatSession]:
21
+ """Eagerly load the chat sessions into memory.
22
+
23
+ Returns:
24
+ A list of chat sessions.
25
+ """
26
+ return list(self.lazy_load())