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,1229 @@
1
+ """Base callback handler for Coco."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Sequence
10
+ from uuid import UUID
11
+
12
+ from coco_core._protocol import MessagesData
13
+ from tenacity import RetryCallState
14
+ from typing_extensions import Self
15
+
16
+ from coco_core.agents import AgentAction, AgentFinish
17
+ from coco_core.documents import Document
18
+ from coco_core.messages import BaseMessage
19
+ from coco_core.outputs import ChatGenerationChunk, GenerationChunk, LLMResult
20
+
21
+ _LOGGER = logging.getLogger(__name__)
22
+
23
+
24
+ class RetrieverManagerMixin:
25
+ """Mixin for `Retriever` callbacks."""
26
+
27
+ def on_retriever_error(
28
+ self,
29
+ error: BaseException,
30
+ *,
31
+ run_id: UUID,
32
+ parent_run_id: UUID | None = None,
33
+ **kwargs: Any,
34
+ ) -> Any:
35
+ """Run when `Retriever` errors.
36
+
37
+ Args:
38
+ error: The error that occurred.
39
+ run_id: The ID of the current run.
40
+ parent_run_id: The ID of the parent run.
41
+ **kwargs: Additional keyword arguments.
42
+ """
43
+
44
+ def on_retriever_end(
45
+ self,
46
+ documents: Sequence[Document],
47
+ *,
48
+ run_id: UUID,
49
+ parent_run_id: UUID | None = None,
50
+ **kwargs: Any,
51
+ ) -> Any:
52
+ """Run when `Retriever` ends running.
53
+
54
+ Args:
55
+ documents: The documents retrieved.
56
+ run_id: The ID of the current run.
57
+ parent_run_id: The ID of the parent run.
58
+ **kwargs: Additional keyword arguments.
59
+ """
60
+
61
+
62
+ class LLMManagerMixin:
63
+ """Mixin for LLM callbacks."""
64
+
65
+ def on_llm_new_token(
66
+ self,
67
+ token: str | list[str | dict[str, Any]],
68
+ *,
69
+ chunk: GenerationChunk | ChatGenerationChunk | None = None,
70
+ run_id: UUID,
71
+ parent_run_id: UUID | None = None,
72
+ tags: list[str] | None = None,
73
+ **kwargs: Any,
74
+ ) -> Any:
75
+ """Run on new output token.
76
+
77
+ Only available when streaming is enabled.
78
+
79
+ For both chat models and non-chat models (legacy text completion LLMs).
80
+
81
+ Args:
82
+ token: The new token, or a list of content blocks.
83
+ chunk: The new generated chunk, containing content and other information.
84
+ run_id: The ID of the current run.
85
+ parent_run_id: The ID of the parent run.
86
+ tags: The tags.
87
+ **kwargs: Additional keyword arguments.
88
+ """
89
+
90
+ def on_llm_end(
91
+ self,
92
+ response: LLMResult,
93
+ *,
94
+ run_id: UUID,
95
+ parent_run_id: UUID | None = None,
96
+ tags: list[str] | None = None,
97
+ **kwargs: Any,
98
+ ) -> Any:
99
+ """Run when LLM ends running.
100
+
101
+ Args:
102
+ response: The response which was generated.
103
+ run_id: The ID of the current run.
104
+ parent_run_id: The ID of the parent run.
105
+ tags: The tags.
106
+ **kwargs: Additional keyword arguments.
107
+ """
108
+
109
+ def on_llm_error(
110
+ self,
111
+ error: BaseException,
112
+ *,
113
+ run_id: UUID,
114
+ parent_run_id: UUID | None = None,
115
+ tags: list[str] | None = None,
116
+ **kwargs: Any,
117
+ ) -> Any:
118
+ """Run when LLM errors.
119
+
120
+ Args:
121
+ error: The error that occurred.
122
+ run_id: The ID of the current run.
123
+ parent_run_id: The ID of the parent run.
124
+ tags: The tags.
125
+ **kwargs: Additional keyword arguments.
126
+ """
127
+
128
+ def on_stream_event(
129
+ self,
130
+ event: MessagesData,
131
+ *,
132
+ run_id: UUID,
133
+ parent_run_id: UUID | None = None,
134
+ tags: list[str] | None = None,
135
+ **kwargs: Any,
136
+ ) -> Any:
137
+ """Run on each protocol event from `stream_events(version="v3")`.
138
+
139
+ Also fires for the async equivalent
140
+ (`astream_events(version="v3")`).
141
+
142
+ Fires once per `MessagesData` event — `message-start`, per-block
143
+ `content-block-start` / `content-block-delta` /
144
+ `content-block-finish`, and `message-finish`. Analogous to
145
+ `on_llm_new_token` in v1 streaming, but at event granularity rather
146
+ than chunk: a single chunk can map to multiple events (e.g. a
147
+ `content-block-start` plus its first `content-block-delta`), and
148
+ lifecycle boundaries are explicit.
149
+
150
+ Fires uniformly whether the provider emits events natively via
151
+ `_stream_chat_model_events` or goes through the chunk-to-event
152
+ compat bridge. Observers see the same event stream regardless of
153
+ how the underlying model produces output.
154
+
155
+ Not fired from v1 `stream()` / `astream()`; for those, keep using
156
+ `on_llm_new_token`. Purely additive — `on_chat_model_start`,
157
+ `on_llm_end`, and `on_llm_error` still fire around a v2 call as
158
+ they do around a v1 call.
159
+
160
+ Args:
161
+ event: The protocol event.
162
+ run_id: The ID of the current run.
163
+ parent_run_id: The ID of the parent run.
164
+ tags: The tags.
165
+ **kwargs: Additional keyword arguments.
166
+ """
167
+
168
+
169
+ class ChainManagerMixin:
170
+ """Mixin for chain callbacks."""
171
+
172
+ def on_chain_end(
173
+ self,
174
+ outputs: dict[str, Any],
175
+ *,
176
+ run_id: UUID,
177
+ parent_run_id: UUID | None = None,
178
+ **kwargs: Any,
179
+ ) -> Any:
180
+ """Run when chain ends running.
181
+
182
+ Args:
183
+ outputs: The outputs of the chain.
184
+ run_id: The ID of the current run.
185
+ parent_run_id: The ID of the parent run.
186
+ **kwargs: Additional keyword arguments.
187
+ """
188
+
189
+ def on_chain_error(
190
+ self,
191
+ error: BaseException,
192
+ *,
193
+ run_id: UUID,
194
+ parent_run_id: UUID | None = None,
195
+ **kwargs: Any,
196
+ ) -> Any:
197
+ """Run when chain errors.
198
+
199
+ Args:
200
+ error: The error that occurred.
201
+ run_id: The ID of the current run.
202
+ parent_run_id: The ID of the parent run.
203
+ **kwargs: Additional keyword arguments.
204
+ """
205
+
206
+ def on_agent_action(
207
+ self,
208
+ action: AgentAction,
209
+ *,
210
+ run_id: UUID,
211
+ parent_run_id: UUID | None = None,
212
+ **kwargs: Any,
213
+ ) -> Any:
214
+ """Run on agent action.
215
+
216
+ Args:
217
+ action: The agent action.
218
+ run_id: The ID of the current run.
219
+ parent_run_id: The ID of the parent run.
220
+ **kwargs: Additional keyword arguments.
221
+ """
222
+
223
+ def on_agent_finish(
224
+ self,
225
+ finish: AgentFinish,
226
+ *,
227
+ run_id: UUID,
228
+ parent_run_id: UUID | None = None,
229
+ **kwargs: Any,
230
+ ) -> Any:
231
+ """Run on the agent end.
232
+
233
+ Args:
234
+ finish: The agent finish.
235
+ run_id: The ID of the current run.
236
+ parent_run_id: The ID of the parent run.
237
+ **kwargs: Additional keyword arguments.
238
+ """
239
+
240
+
241
+ class ToolManagerMixin:
242
+ """Mixin for tool callbacks."""
243
+
244
+ def on_tool_end(
245
+ self,
246
+ output: Any,
247
+ *,
248
+ run_id: UUID,
249
+ parent_run_id: UUID | None = None,
250
+ **kwargs: Any,
251
+ ) -> Any:
252
+ """Run when the tool ends running.
253
+
254
+ Args:
255
+ output: The output of the tool.
256
+ run_id: The ID of the current run.
257
+ parent_run_id: The ID of the parent run.
258
+ **kwargs: Additional keyword arguments.
259
+ """
260
+
261
+ def on_tool_error(
262
+ self,
263
+ error: BaseException,
264
+ *,
265
+ run_id: UUID,
266
+ parent_run_id: UUID | None = None,
267
+ **kwargs: Any,
268
+ ) -> Any:
269
+ """Run when tool errors.
270
+
271
+ Args:
272
+ error: The error that occurred.
273
+ run_id: The ID of the current run.
274
+ parent_run_id: The ID of the parent run.
275
+ **kwargs: Additional keyword arguments.
276
+ """
277
+
278
+
279
+ class CallbackManagerMixin:
280
+ """Mixin for callback manager."""
281
+
282
+ def on_llm_start(
283
+ self,
284
+ serialized: dict[str, Any],
285
+ prompts: list[str],
286
+ *,
287
+ run_id: UUID,
288
+ parent_run_id: UUID | None = None,
289
+ tags: list[str] | None = None,
290
+ metadata: dict[str, Any] | None = None,
291
+ **kwargs: Any,
292
+ ) -> Any:
293
+ """Run when LLM starts running.
294
+
295
+ !!! warning
296
+
297
+ This method is called for non-chat models (regular text completion LLMs). If
298
+ you're implementing a handler for a chat model, you should use
299
+ `on_chat_model_start` instead.
300
+
301
+ Args:
302
+ serialized: The serialized LLM.
303
+ prompts: The prompts.
304
+ run_id: The ID of the current run.
305
+ parent_run_id: The ID of the parent run.
306
+ tags: The tags.
307
+ metadata: The metadata.
308
+ **kwargs: Additional keyword arguments.
309
+ """
310
+
311
+ def on_chat_model_start(
312
+ self,
313
+ serialized: dict[str, Any],
314
+ messages: list[list[BaseMessage]],
315
+ *,
316
+ run_id: UUID,
317
+ parent_run_id: UUID | None = None,
318
+ tags: list[str] | None = None,
319
+ metadata: dict[str, Any] | None = None,
320
+ **kwargs: Any,
321
+ ) -> Any:
322
+ """Run when a chat model starts running.
323
+
324
+ !!! warning
325
+
326
+ This method is called for chat models. If you're implementing a handler for
327
+ a non-chat model, you should use `on_llm_start` instead.
328
+
329
+ !!! note
330
+
331
+ When overriding this method, the signature **must** include the two
332
+ required positional arguments `serialized` and `messages`. Avoid
333
+ using `*args` in your override — doing so causes an `IndexError`
334
+ in the fallback path when the callback system converts `messages`
335
+ to prompt strings for `on_llm_start`. Always declare the
336
+ signature explicitly:
337
+
338
+ .. code-block:: python
339
+
340
+ def on_chat_model_start(
341
+ self,
342
+ serialized: dict[str, Any],
343
+ messages: list[list[BaseMessage]],
344
+ **kwargs: Any,
345
+ ) -> None:
346
+ raise NotImplementedError # triggers fallback to on_llm_start
347
+
348
+ Args:
349
+ serialized: The serialized chat model.
350
+ messages: The messages. Must be a list of message lists — this is a
351
+ required positional argument and must be present in any override.
352
+ run_id: The ID of the current run.
353
+ parent_run_id: The ID of the parent run.
354
+ tags: The tags.
355
+ metadata: The metadata.
356
+ **kwargs: Additional keyword arguments.
357
+ """
358
+ # NotImplementedError is thrown intentionally
359
+ # Callback handler will fall back to on_llm_start if this exception is thrown
360
+ msg = f"{self.__class__.__name__} does not implement `on_chat_model_start`"
361
+ raise NotImplementedError(msg)
362
+
363
+ def on_retriever_start(
364
+ self,
365
+ serialized: dict[str, Any],
366
+ query: str,
367
+ *,
368
+ run_id: UUID,
369
+ parent_run_id: UUID | None = None,
370
+ tags: list[str] | None = None,
371
+ metadata: dict[str, Any] | None = None,
372
+ **kwargs: Any,
373
+ ) -> Any:
374
+ """Run when the `Retriever` starts running.
375
+
376
+ Args:
377
+ serialized: The serialized `Retriever`.
378
+ query: The query.
379
+ run_id: The ID of the current run.
380
+ parent_run_id: The ID of the parent run.
381
+ tags: The tags.
382
+ metadata: The metadata.
383
+ **kwargs: Additional keyword arguments.
384
+ """
385
+
386
+ def on_chain_start(
387
+ self,
388
+ serialized: dict[str, Any],
389
+ inputs: dict[str, Any],
390
+ *,
391
+ run_id: UUID,
392
+ parent_run_id: UUID | None = None,
393
+ tags: list[str] | None = None,
394
+ metadata: dict[str, Any] | None = None,
395
+ **kwargs: Any,
396
+ ) -> Any:
397
+ """Run when a chain starts running.
398
+
399
+ Args:
400
+ serialized: The serialized chain.
401
+ inputs: The inputs.
402
+ run_id: The ID of the current run.
403
+ parent_run_id: The ID of the parent run.
404
+ tags: The tags.
405
+ metadata: The metadata.
406
+ **kwargs: Additional keyword arguments.
407
+ """
408
+
409
+ def on_tool_start(
410
+ self,
411
+ serialized: dict[str, Any],
412
+ input_str: str,
413
+ *,
414
+ run_id: UUID,
415
+ parent_run_id: UUID | None = None,
416
+ tags: list[str] | None = None,
417
+ metadata: dict[str, Any] | None = None,
418
+ inputs: dict[str, Any] | None = None,
419
+ **kwargs: Any,
420
+ ) -> Any:
421
+ """Run when the tool starts running.
422
+
423
+ Args:
424
+ serialized: The serialized chain.
425
+ input_str: The input string.
426
+ run_id: The ID of the current run.
427
+ parent_run_id: The ID of the parent run.
428
+ tags: The tags.
429
+ metadata: The metadata.
430
+ inputs: The inputs.
431
+ **kwargs: Additional keyword arguments.
432
+ """
433
+
434
+
435
+ class RunManagerMixin:
436
+ """Mixin for run manager."""
437
+
438
+ def on_text(
439
+ self,
440
+ text: str,
441
+ *,
442
+ run_id: UUID,
443
+ parent_run_id: UUID | None = None,
444
+ **kwargs: Any,
445
+ ) -> Any:
446
+ """Run on an arbitrary text.
447
+
448
+ Args:
449
+ text: The text.
450
+ run_id: The ID of the current run.
451
+ parent_run_id: The ID of the parent run.
452
+ **kwargs: Additional keyword arguments.
453
+ """
454
+
455
+ def on_retry(
456
+ self,
457
+ retry_state: RetryCallState,
458
+ *,
459
+ run_id: UUID,
460
+ parent_run_id: UUID | None = None,
461
+ **kwargs: Any,
462
+ ) -> Any:
463
+ """Run on a retry event.
464
+
465
+ Args:
466
+ retry_state: The retry state.
467
+ run_id: The ID of the current run.
468
+ parent_run_id: The ID of the parent run.
469
+ **kwargs: Additional keyword arguments.
470
+ """
471
+
472
+ def on_custom_event(
473
+ self,
474
+ name: str,
475
+ data: Any,
476
+ *,
477
+ run_id: UUID,
478
+ tags: list[str] | None = None,
479
+ metadata: dict[str, Any] | None = None,
480
+ **kwargs: Any,
481
+ ) -> Any:
482
+ """Override to define a handler for a custom event.
483
+
484
+ Args:
485
+ name: The name of the custom event.
486
+ data: The data for the custom event.
487
+
488
+ Format will match the format specified by the user.
489
+ run_id: The ID of the run.
490
+ tags: The tags associated with the custom event (includes inherited tags).
491
+ metadata: The metadata associated with the custom event (includes inherited
492
+ metadata).
493
+ """
494
+
495
+
496
+ class BaseCallbackHandler(
497
+ LLMManagerMixin,
498
+ ChainManagerMixin,
499
+ ToolManagerMixin,
500
+ RetrieverManagerMixin,
501
+ CallbackManagerMixin,
502
+ RunManagerMixin,
503
+ ):
504
+ """Base callback handler."""
505
+
506
+ raise_error: bool = False
507
+ """Whether to raise an error if an exception occurs."""
508
+
509
+ run_inline: bool = False
510
+ """Whether to run the callback inline."""
511
+
512
+ @property
513
+ def ignore_llm(self) -> bool:
514
+ """Whether to ignore LLM callbacks."""
515
+ return False
516
+
517
+ @property
518
+ def ignore_retry(self) -> bool:
519
+ """Whether to ignore retry callbacks."""
520
+ return False
521
+
522
+ @property
523
+ def ignore_chain(self) -> bool:
524
+ """Whether to ignore chain callbacks."""
525
+ return False
526
+
527
+ @property
528
+ def ignore_agent(self) -> bool:
529
+ """Whether to ignore agent callbacks."""
530
+ return False
531
+
532
+ @property
533
+ def ignore_retriever(self) -> bool:
534
+ """Whether to ignore retriever callbacks."""
535
+ return False
536
+
537
+ @property
538
+ def ignore_chat_model(self) -> bool:
539
+ """Whether to ignore chat model callbacks."""
540
+ return False
541
+
542
+ @property
543
+ def ignore_custom_event(self) -> bool:
544
+ """Ignore custom event."""
545
+ return False
546
+
547
+
548
+ class AsyncCallbackHandler(BaseCallbackHandler):
549
+ """Base async callback handler."""
550
+
551
+ async def on_llm_start(
552
+ self,
553
+ serialized: dict[str, Any],
554
+ prompts: list[str],
555
+ *,
556
+ run_id: UUID,
557
+ parent_run_id: UUID | None = None,
558
+ tags: list[str] | None = None,
559
+ metadata: dict[str, Any] | None = None,
560
+ **kwargs: Any,
561
+ ) -> None:
562
+ """Run when the model starts running.
563
+
564
+ !!! warning
565
+
566
+ This method is called for non-chat models (regular text completion LLMs). If
567
+ you're implementing a handler for a chat model, you should use
568
+ `on_chat_model_start` instead.
569
+
570
+ Args:
571
+ serialized: The serialized LLM.
572
+ prompts: The prompts.
573
+ run_id: The ID of the current run.
574
+ parent_run_id: The ID of the parent run.
575
+ tags: The tags.
576
+ metadata: The metadata.
577
+ **kwargs: Additional keyword arguments.
578
+ """
579
+
580
+ async def on_chat_model_start(
581
+ self,
582
+ serialized: dict[str, Any],
583
+ messages: list[list[BaseMessage]],
584
+ *,
585
+ run_id: UUID,
586
+ parent_run_id: UUID | None = None,
587
+ tags: list[str] | None = None,
588
+ metadata: dict[str, Any] | None = None,
589
+ **kwargs: Any,
590
+ ) -> Any:
591
+ """Run when a chat model starts running.
592
+
593
+ !!! warning
594
+
595
+ This method is called for chat models. If you're implementing a handler for
596
+ a non-chat model, you should use `on_llm_start` instead.
597
+
598
+ !!! note
599
+
600
+ When overriding this method, the signature **must** include the two
601
+ required positional arguments `serialized` and `messages`. Avoid
602
+ using `*args` in your override — doing so causes an `IndexError`
603
+ in the fallback path when the callback system converts `messages`
604
+ to prompt strings for `on_llm_start`. Always declare the
605
+ signature explicitly:
606
+
607
+ .. code-block:: python
608
+
609
+ async def on_chat_model_start(
610
+ self,
611
+ serialized: dict[str, Any],
612
+ messages: list[list[BaseMessage]],
613
+ **kwargs: Any,
614
+ ) -> None:
615
+ raise NotImplementedError # triggers fallback to on_llm_start
616
+
617
+ Args:
618
+ serialized: The serialized chat model.
619
+ messages: The messages. Must be a list of message lists — this is a
620
+ required positional argument and must be present in any override.
621
+ run_id: The ID of the current run.
622
+ parent_run_id: The ID of the parent run.
623
+ tags: The tags.
624
+ metadata: The metadata.
625
+ **kwargs: Additional keyword arguments.
626
+ """
627
+ # NotImplementedError is thrown intentionally
628
+ # Callback handler will fall back to on_llm_start if this exception is thrown
629
+ msg = f"{self.__class__.__name__} does not implement `on_chat_model_start`"
630
+ raise NotImplementedError(msg)
631
+
632
+ async def on_llm_new_token(
633
+ self,
634
+ token: str | list[str | dict[str, Any]],
635
+ *,
636
+ chunk: GenerationChunk | ChatGenerationChunk | None = None,
637
+ run_id: UUID,
638
+ parent_run_id: UUID | None = None,
639
+ tags: list[str] | None = None,
640
+ **kwargs: Any,
641
+ ) -> None:
642
+ """Run on new output token. Only available when streaming is enabled.
643
+
644
+ For both chat models and non-chat models (legacy text completion LLMs).
645
+
646
+ Args:
647
+ token: The new token, or a list of content blocks.
648
+ chunk: The new generated chunk, containing content and other information.
649
+ run_id: The ID of the current run.
650
+ parent_run_id: The ID of the parent run.
651
+ tags: The tags.
652
+ **kwargs: Additional keyword arguments.
653
+ """
654
+
655
+ async def on_llm_end(
656
+ self,
657
+ response: LLMResult,
658
+ *,
659
+ run_id: UUID,
660
+ parent_run_id: UUID | None = None,
661
+ tags: list[str] | None = None,
662
+ **kwargs: Any,
663
+ ) -> None:
664
+ """Run when the model ends running.
665
+
666
+ Args:
667
+ response: The response which was generated.
668
+ run_id: The ID of the current run.
669
+ parent_run_id: The ID of the parent run.
670
+ tags: The tags.
671
+ **kwargs: Additional keyword arguments.
672
+ """
673
+
674
+ async def on_llm_error(
675
+ self,
676
+ error: BaseException,
677
+ *,
678
+ run_id: UUID,
679
+ parent_run_id: UUID | None = None,
680
+ tags: list[str] | None = None,
681
+ **kwargs: Any,
682
+ ) -> None:
683
+ """Run when LLM errors.
684
+
685
+ Args:
686
+ error: The error that occurred.
687
+ run_id: The ID of the current run.
688
+ parent_run_id: The ID of the parent run.
689
+ tags: The tags.
690
+ **kwargs: Additional keyword arguments.
691
+
692
+ - response (LLMResult): The response which was generated before
693
+ the error occurred.
694
+ """
695
+
696
+ async def on_stream_event(
697
+ self,
698
+ event: MessagesData,
699
+ *,
700
+ run_id: UUID,
701
+ parent_run_id: UUID | None = None,
702
+ tags: list[str] | None = None,
703
+ **kwargs: Any,
704
+ ) -> None:
705
+ """Run on each protocol event produced by `astream_events(version="v3")`.
706
+
707
+ See :meth:`LLMManagerMixin.on_stream_event` for the full contract.
708
+ Fires once per `MessagesData` event at event granularity, uniformly
709
+ across native and compat-bridge providers, and is purely additive
710
+ to the existing `on_chat_model_start` / `on_llm_end` /
711
+ `on_llm_error` callbacks.
712
+
713
+ Args:
714
+ event: The protocol event.
715
+ run_id: The ID of the current run.
716
+ parent_run_id: The ID of the parent run.
717
+ tags: The tags.
718
+ **kwargs: Additional keyword arguments.
719
+ """
720
+
721
+ async def on_chain_start(
722
+ self,
723
+ serialized: dict[str, Any],
724
+ inputs: dict[str, Any],
725
+ *,
726
+ run_id: UUID,
727
+ parent_run_id: UUID | None = None,
728
+ tags: list[str] | None = None,
729
+ metadata: dict[str, Any] | None = None,
730
+ **kwargs: Any,
731
+ ) -> None:
732
+ """Run when a chain starts running.
733
+
734
+ Args:
735
+ serialized: The serialized chain.
736
+ inputs: The inputs.
737
+ run_id: The ID of the current run.
738
+ parent_run_id: The ID of the parent run.
739
+ tags: The tags.
740
+ metadata: The metadata.
741
+ **kwargs: Additional keyword arguments.
742
+ """
743
+
744
+ async def on_chain_end(
745
+ self,
746
+ outputs: dict[str, Any],
747
+ *,
748
+ run_id: UUID,
749
+ parent_run_id: UUID | None = None,
750
+ tags: list[str] | None = None,
751
+ **kwargs: Any,
752
+ ) -> None:
753
+ """Run when a chain ends running.
754
+
755
+ Args:
756
+ outputs: The outputs of the chain.
757
+ run_id: The ID of the current run.
758
+ parent_run_id: The ID of the parent run.
759
+ tags: The tags.
760
+ **kwargs: Additional keyword arguments.
761
+ """
762
+
763
+ async def on_chain_error(
764
+ self,
765
+ error: BaseException,
766
+ *,
767
+ run_id: UUID,
768
+ parent_run_id: UUID | None = None,
769
+ tags: list[str] | None = None,
770
+ **kwargs: Any,
771
+ ) -> None:
772
+ """Run when chain errors.
773
+
774
+ Args:
775
+ error: The error that occurred.
776
+ run_id: The ID of the current run.
777
+ parent_run_id: The ID of the parent run.
778
+ tags: The tags.
779
+ **kwargs: Additional keyword arguments.
780
+ """
781
+
782
+ async def on_tool_start(
783
+ self,
784
+ serialized: dict[str, Any],
785
+ input_str: str,
786
+ *,
787
+ run_id: UUID,
788
+ parent_run_id: UUID | None = None,
789
+ tags: list[str] | None = None,
790
+ metadata: dict[str, Any] | None = None,
791
+ inputs: dict[str, Any] | None = None,
792
+ **kwargs: Any,
793
+ ) -> None:
794
+ """Run when the tool starts running.
795
+
796
+ Args:
797
+ serialized: The serialized tool.
798
+ input_str: The input string.
799
+ run_id: The ID of the current run.
800
+ parent_run_id: The ID of the parent run.
801
+ tags: The tags.
802
+ metadata: The metadata.
803
+ inputs: The inputs.
804
+ **kwargs: Additional keyword arguments.
805
+ """
806
+
807
+ async def on_tool_end(
808
+ self,
809
+ output: Any,
810
+ *,
811
+ run_id: UUID,
812
+ parent_run_id: UUID | None = None,
813
+ tags: list[str] | None = None,
814
+ **kwargs: Any,
815
+ ) -> None:
816
+ """Run when the tool ends running.
817
+
818
+ Args:
819
+ output: The output of the tool.
820
+ run_id: The ID of the current run.
821
+ parent_run_id: The ID of the parent run.
822
+ tags: The tags.
823
+ **kwargs: Additional keyword arguments.
824
+ """
825
+
826
+ async def on_tool_error(
827
+ self,
828
+ error: BaseException,
829
+ *,
830
+ run_id: UUID,
831
+ parent_run_id: UUID | None = None,
832
+ tags: list[str] | None = None,
833
+ **kwargs: Any,
834
+ ) -> None:
835
+ """Run when tool errors.
836
+
837
+ Args:
838
+ error: The error that occurred.
839
+ run_id: The ID of the current run.
840
+ parent_run_id: The ID of the parent run.
841
+ tags: The tags.
842
+ **kwargs: Additional keyword arguments.
843
+ """
844
+
845
+ async def on_text(
846
+ self,
847
+ text: str,
848
+ *,
849
+ run_id: UUID,
850
+ parent_run_id: UUID | None = None,
851
+ tags: list[str] | None = None,
852
+ **kwargs: Any,
853
+ ) -> None:
854
+ """Run on an arbitrary text.
855
+
856
+ Args:
857
+ text: The text.
858
+ run_id: The ID of the current run.
859
+ parent_run_id: The ID of the parent run.
860
+ tags: The tags.
861
+ **kwargs: Additional keyword arguments.
862
+ """
863
+
864
+ async def on_retry(
865
+ self,
866
+ retry_state: RetryCallState,
867
+ *,
868
+ run_id: UUID,
869
+ parent_run_id: UUID | None = None,
870
+ **kwargs: Any,
871
+ ) -> Any:
872
+ """Run on a retry event.
873
+
874
+ Args:
875
+ retry_state: The retry state.
876
+ run_id: The ID of the current run.
877
+ parent_run_id: The ID of the parent run.
878
+ **kwargs: Additional keyword arguments.
879
+ """
880
+
881
+ async def on_agent_action(
882
+ self,
883
+ action: AgentAction,
884
+ *,
885
+ run_id: UUID,
886
+ parent_run_id: UUID | None = None,
887
+ tags: list[str] | None = None,
888
+ **kwargs: Any,
889
+ ) -> None:
890
+ """Run on agent action.
891
+
892
+ Args:
893
+ action: The agent action.
894
+ run_id: The ID of the current run.
895
+ parent_run_id: The ID of the parent run.
896
+ tags: The tags.
897
+ **kwargs: Additional keyword arguments.
898
+ """
899
+
900
+ async def on_agent_finish(
901
+ self,
902
+ finish: AgentFinish,
903
+ *,
904
+ run_id: UUID,
905
+ parent_run_id: UUID | None = None,
906
+ tags: list[str] | None = None,
907
+ **kwargs: Any,
908
+ ) -> None:
909
+ """Run on the agent end.
910
+
911
+ Args:
912
+ finish: The agent finish.
913
+ run_id: The ID of the current run.
914
+ parent_run_id: The ID of the parent run.
915
+ tags: The tags.
916
+ **kwargs: Additional keyword arguments.
917
+ """
918
+
919
+ async def on_retriever_start(
920
+ self,
921
+ serialized: dict[str, Any],
922
+ query: str,
923
+ *,
924
+ run_id: UUID,
925
+ parent_run_id: UUID | None = None,
926
+ tags: list[str] | None = None,
927
+ metadata: dict[str, Any] | None = None,
928
+ **kwargs: Any,
929
+ ) -> None:
930
+ """Run on the retriever start.
931
+
932
+ Args:
933
+ serialized: The serialized retriever.
934
+ query: The query.
935
+ run_id: The ID of the current run.
936
+ parent_run_id: The ID of the parent run.
937
+ tags: The tags.
938
+ metadata: The metadata.
939
+ **kwargs: Additional keyword arguments.
940
+ """
941
+
942
+ async def on_retriever_end(
943
+ self,
944
+ documents: Sequence[Document],
945
+ *,
946
+ run_id: UUID,
947
+ parent_run_id: UUID | None = None,
948
+ tags: list[str] | None = None,
949
+ **kwargs: Any,
950
+ ) -> None:
951
+ """Run on the retriever end.
952
+
953
+ Args:
954
+ documents: The documents retrieved.
955
+ run_id: The ID of the current run.
956
+ parent_run_id: The ID of the parent run.
957
+ tags: The tags.
958
+ **kwargs: Additional keyword arguments.
959
+ """
960
+
961
+ async def on_retriever_error(
962
+ self,
963
+ error: BaseException,
964
+ *,
965
+ run_id: UUID,
966
+ parent_run_id: UUID | None = None,
967
+ tags: list[str] | None = None,
968
+ **kwargs: Any,
969
+ ) -> None:
970
+ """Run on retriever error.
971
+
972
+ Args:
973
+ error: The error that occurred.
974
+ run_id: The ID of the current run.
975
+ parent_run_id: The ID of the parent run.
976
+ tags: The tags.
977
+ **kwargs: Additional keyword arguments.
978
+ """
979
+
980
+ async def on_custom_event(
981
+ self,
982
+ name: str,
983
+ data: Any,
984
+ *,
985
+ run_id: UUID,
986
+ tags: list[str] | None = None,
987
+ metadata: dict[str, Any] | None = None,
988
+ **kwargs: Any,
989
+ ) -> None:
990
+ """Override to define a handler for custom events.
991
+
992
+ Args:
993
+ name: The name of the custom event.
994
+ data: The data for the custom event.
995
+
996
+ Format will match the format specified by the user.
997
+ run_id: The ID of the run.
998
+ tags: The tags associated with the custom event (includes inherited tags).
999
+ metadata: The metadata associated with the custom event (includes inherited
1000
+ metadata).
1001
+ """
1002
+
1003
+
1004
+ class BaseCallbackManager(CallbackManagerMixin):
1005
+ """Base callback manager."""
1006
+
1007
+ def __init__(
1008
+ self,
1009
+ handlers: list[BaseCallbackHandler],
1010
+ inheritable_handlers: list[BaseCallbackHandler] | None = None,
1011
+ parent_run_id: UUID | None = None,
1012
+ *,
1013
+ tags: list[str] | None = None,
1014
+ inheritable_tags: list[str] | None = None,
1015
+ metadata: dict[str, Any] | None = None,
1016
+ inheritable_metadata: dict[str, Any] | None = None,
1017
+ ) -> None:
1018
+ """Initialize callback manager.
1019
+
1020
+ Args:
1021
+ handlers: The handlers.
1022
+ inheritable_handlers: The inheritable handlers.
1023
+ parent_run_id: The parent run ID.
1024
+ tags: The tags.
1025
+ inheritable_tags: The inheritable tags.
1026
+ metadata: The metadata.
1027
+ inheritable_metadata: The inheritable metadata.
1028
+ """
1029
+ self.handlers: list[BaseCallbackHandler] = handlers
1030
+ self.inheritable_handlers: list[BaseCallbackHandler] = (
1031
+ inheritable_handlers or []
1032
+ )
1033
+ self.parent_run_id: UUID | None = parent_run_id
1034
+ self.tags = tags or []
1035
+ self.inheritable_tags = inheritable_tags or []
1036
+ self.metadata = metadata or {}
1037
+ self.inheritable_metadata = inheritable_metadata or {}
1038
+
1039
+ def copy(self) -> Self:
1040
+ """Return a copy of the callback manager."""
1041
+ return self.__class__(
1042
+ handlers=self.handlers.copy(),
1043
+ inheritable_handlers=self.inheritable_handlers.copy(),
1044
+ parent_run_id=self.parent_run_id,
1045
+ tags=self.tags.copy(),
1046
+ inheritable_tags=self.inheritable_tags.copy(),
1047
+ metadata=self.metadata.copy(),
1048
+ inheritable_metadata=self.inheritable_metadata.copy(),
1049
+ )
1050
+
1051
+ def merge(self, other: BaseCallbackManager) -> Self:
1052
+ """Merge the callback manager with another callback manager.
1053
+
1054
+ May be overwritten in subclasses.
1055
+
1056
+ Primarily used internally within `merge_configs`.
1057
+
1058
+ Returns:
1059
+ The merged callback manager of the same type as the current object.
1060
+
1061
+ Example:
1062
+ ```python
1063
+ # Merging two callback managers`
1064
+ from coco_core.callbacks.manager import (
1065
+ CallbackManager,
1066
+ trace_as_chain_group,
1067
+ )
1068
+ from coco_core.callbacks.stdout import StdOutCallbackHandler
1069
+
1070
+ manager = CallbackManager(handlers=[StdOutCallbackHandler()], tags=["tag2"])
1071
+ with trace_as_chain_group("My Group Name", tags=["tag1"]) as group_manager:
1072
+ merged_manager = group_manager.merge(manager)
1073
+ print(merged_manager.handlers)
1074
+ # [
1075
+ # <coco_core.callbacks.stdout.StdOutCallbackHandler object at ...>,
1076
+ # <coco_core.callbacks.streaming_stdout.StreamingStdOutCallbackHandler object at ...>,
1077
+ # ]
1078
+
1079
+ print(merged_manager.tags)
1080
+ # ['tag2', 'tag1']
1081
+ ```
1082
+ """ # noqa: E501
1083
+ # Combine handlers and inheritable_handlers separately, using sets
1084
+ # to deduplicate (order not preserved)
1085
+ combined_handlers = list(set(self.handlers) | set(other.handlers))
1086
+ combined_inheritable = list(
1087
+ set(self.inheritable_handlers) | set(other.inheritable_handlers)
1088
+ )
1089
+
1090
+ return self.__class__(
1091
+ parent_run_id=self.parent_run_id or other.parent_run_id,
1092
+ handlers=combined_handlers,
1093
+ inheritable_handlers=combined_inheritable,
1094
+ tags=list(set(self.tags + other.tags)),
1095
+ inheritable_tags=list(set(self.inheritable_tags + other.inheritable_tags)),
1096
+ metadata={
1097
+ **self.metadata,
1098
+ **other.metadata,
1099
+ },
1100
+ inheritable_metadata={
1101
+ **self.inheritable_metadata,
1102
+ **other.inheritable_metadata,
1103
+ },
1104
+ )
1105
+
1106
+ @property
1107
+ def is_async(self) -> bool:
1108
+ """Whether the callback manager is async."""
1109
+ return False
1110
+
1111
+ def add_handler(
1112
+ self,
1113
+ handler: BaseCallbackHandler,
1114
+ inherit: bool = True, # noqa: FBT001,FBT002
1115
+ ) -> None:
1116
+ """Add a handler to the callback manager.
1117
+
1118
+ Args:
1119
+ handler: The handler to add.
1120
+ inherit: Whether to inherit the handler.
1121
+ """
1122
+ if handler not in self.handlers:
1123
+ self.handlers.append(handler)
1124
+ if inherit and handler not in self.inheritable_handlers:
1125
+ self.inheritable_handlers.append(handler)
1126
+
1127
+ def remove_handler(self, handler: BaseCallbackHandler) -> None:
1128
+ """Remove a handler from the callback manager.
1129
+
1130
+ Args:
1131
+ handler: The handler to remove.
1132
+ """
1133
+ if handler in self.handlers:
1134
+ self.handlers.remove(handler)
1135
+ if handler in self.inheritable_handlers:
1136
+ self.inheritable_handlers.remove(handler)
1137
+
1138
+ def set_handlers(
1139
+ self,
1140
+ handlers: list[BaseCallbackHandler],
1141
+ inherit: bool = True, # noqa: FBT001,FBT002
1142
+ ) -> None:
1143
+ """Set handlers as the only handlers on the callback manager.
1144
+
1145
+ Args:
1146
+ handlers: The handlers to set.
1147
+ inherit: Whether to inherit the handlers.
1148
+ """
1149
+ self.handlers = []
1150
+ self.inheritable_handlers = []
1151
+ for handler in handlers:
1152
+ self.add_handler(handler, inherit=inherit)
1153
+
1154
+ def set_handler(
1155
+ self,
1156
+ handler: BaseCallbackHandler,
1157
+ inherit: bool = True, # noqa: FBT001,FBT002
1158
+ ) -> None:
1159
+ """Set handler as the only handler on the callback manager.
1160
+
1161
+ Args:
1162
+ handler: The handler to set.
1163
+ inherit: Whether to inherit the handler.
1164
+ """
1165
+ self.set_handlers([handler], inherit=inherit)
1166
+
1167
+ def add_tags(
1168
+ self,
1169
+ tags: list[str],
1170
+ inherit: bool = True, # noqa: FBT001,FBT002
1171
+ ) -> None:
1172
+ """Add tags to the callback manager.
1173
+
1174
+ Args:
1175
+ tags: The tags to add.
1176
+ inherit: Whether to inherit the tags.
1177
+ """
1178
+ for tag in tags:
1179
+ if tag in self.tags:
1180
+ self.remove_tags([tag])
1181
+ self.tags.extend(tags)
1182
+ if inherit:
1183
+ self.inheritable_tags.extend(tags)
1184
+
1185
+ def remove_tags(self, tags: list[str]) -> None:
1186
+ """Remove tags from the callback manager.
1187
+
1188
+ Args:
1189
+ tags: The tags to remove.
1190
+ """
1191
+ for tag in tags:
1192
+ if tag in self.tags:
1193
+ self.tags.remove(tag)
1194
+ if tag in self.inheritable_tags:
1195
+ self.inheritable_tags.remove(tag)
1196
+
1197
+ def add_metadata(
1198
+ self,
1199
+ metadata: dict[str, Any],
1200
+ inherit: bool = True, # noqa: FBT001,FBT002
1201
+ ) -> None:
1202
+ """Add metadata to the callback manager.
1203
+
1204
+ Args:
1205
+ metadata: The metadata to add.
1206
+ inherit: Whether to inherit the metadata.
1207
+ """
1208
+ from coco_core.runnables.config import ( # noqa: PLC0415
1209
+ _merge_metadata_dicts,
1210
+ )
1211
+
1212
+ self.metadata = _merge_metadata_dicts(self.metadata, metadata)
1213
+ if inherit:
1214
+ self.inheritable_metadata = _merge_metadata_dicts(
1215
+ self.inheritable_metadata, metadata
1216
+ )
1217
+
1218
+ def remove_metadata(self, keys: list[str]) -> None:
1219
+ """Remove metadata from the callback manager.
1220
+
1221
+ Args:
1222
+ keys: The keys to remove.
1223
+ """
1224
+ for key in keys:
1225
+ self.metadata.pop(key, None)
1226
+ self.inheritable_metadata.pop(key, None)
1227
+
1228
+
1229
+ Callbacks = list[BaseCallbackHandler] | BaseCallbackManager | None