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.
- coco/__init__.py +3 -0
- coco/agents/__init__.py +9 -0
- coco/agents/_subagent_transformer.py +307 -0
- coco/agents/factory.py +2164 -0
- coco/agents/middleware/__init__.py +100 -0
- coco/agents/middleware/_execution.py +385 -0
- coco/agents/middleware/_redaction.py +454 -0
- coco/agents/middleware/_retry.py +134 -0
- coco/agents/middleware/_trace_policy.py +61 -0
- coco/agents/middleware/context_editing.py +306 -0
- coco/agents/middleware/file_search.py +433 -0
- coco/agents/middleware/human_in_the_loop.py +680 -0
- coco/agents/middleware/internal_call_transformer.py +108 -0
- coco/agents/middleware/model_call_limit.py +267 -0
- coco/agents/middleware/model_fallback.py +417 -0
- coco/agents/middleware/model_retry.py +327 -0
- coco/agents/middleware/pii.py +878 -0
- coco/agents/middleware/provider_tool_search.py +307 -0
- coco/agents/middleware/shell_tool.py +949 -0
- coco/agents/middleware/summarization.py +910 -0
- coco/agents/middleware/todo.py +357 -0
- coco/agents/middleware/tool_call_limit.py +495 -0
- coco/agents/middleware/tool_emulator.py +251 -0
- coco/agents/middleware/tool_error.py +209 -0
- coco/agents/middleware/tool_retry.py +421 -0
- coco/agents/middleware/tool_selection.py +515 -0
- coco/agents/middleware/types.py +2201 -0
- coco/agents/structured_output.py +472 -0
- coco/chat_models/__init__.py +7 -0
- coco/chat_models/base.py +1082 -0
- coco/embeddings/__init__.py +18 -0
- coco/embeddings/base.py +279 -0
- coco/mcp/__init__.py +36 -0
- coco/mcp/adapter.py +245 -0
- coco/mcp/elicitation.py +394 -0
- coco/mcp/tools.py +307 -0
- coco/messages/__init__.py +73 -0
- coco/py.typed +0 -0
- coco/rate_limiters/__init__.py +13 -0
- coco/tools/__init__.py +22 -0
- coco/tools/tool_node.py +20 -0
- coco_anthropic/__init__.py +15 -0
- coco_anthropic/_client_utils.py +81 -0
- coco_anthropic/_compat.py +228 -0
- coco_anthropic/_sdk_compat.py +124 -0
- coco_anthropic/_version.py +3 -0
- coco_anthropic/chat_models.py +3349 -0
- coco_anthropic/data/__init__.py +1 -0
- coco_anthropic/data/_profiles.py +491 -0
- coco_anthropic/data/profile_augmentations.toml +69 -0
- coco_anthropic/experimental.py +140 -0
- coco_anthropic/llms.py +428 -0
- coco_anthropic/middleware/__init__.py +25 -0
- coco_anthropic/middleware/anthropic_tools.py +1197 -0
- coco_anthropic/middleware/bash.py +84 -0
- coco_anthropic/middleware/file_search.py +360 -0
- coco_anthropic/middleware/prompt_caching.py +276 -0
- coco_anthropic/output_parsers.py +93 -0
- coco_anthropic/py.typed +0 -0
- coco_core/__init__.py +20 -0
- coco_core/_api/__init__.py +87 -0
- coco_core/_api/beta_decorator.py +266 -0
- coco_core/_api/deprecation.py +637 -0
- coco_core/_api/internal.py +23 -0
- coco_core/_api/path.py +50 -0
- coco_core/_import_utils.py +41 -0
- coco_core/_protocol.py +625 -0
- coco_core/_security/__init__.py +36 -0
- coco_core/_security/_exceptions.py +9 -0
- coco_core/_security/_policy.py +313 -0
- coco_core/_security/_ssrf_protection.py +155 -0
- coco_core/_security/_transport.py +254 -0
- coco_core/agents.py +258 -0
- coco_core/caches.py +272 -0
- coco_core/callbacks/__init__.py +132 -0
- coco_core/callbacks/base.py +1229 -0
- coco_core/callbacks/file.py +266 -0
- coco_core/callbacks/manager.py +2826 -0
- coco_core/callbacks/stdout.py +123 -0
- coco_core/callbacks/streaming_stdout.py +154 -0
- coco_core/callbacks/usage.py +124 -0
- coco_core/chat_history.py +267 -0
- coco_core/chat_loaders.py +26 -0
- coco_core/chat_sessions.py +19 -0
- coco_core/cross_encoders.py +18 -0
- coco_core/document_loaders/__init__.py +36 -0
- coco_core/document_loaders/base.py +155 -0
- coco_core/document_loaders/blob_loaders.py +38 -0
- coco_core/documents/__init__.py +55 -0
- coco_core/documents/base.py +347 -0
- coco_core/documents/compressor.py +74 -0
- coco_core/documents/transformers.py +79 -0
- coco_core/embeddings/__init__.py +31 -0
- coco_core/embeddings/embeddings.py +78 -0
- coco_core/embeddings/fake.py +129 -0
- coco_core/env.py +22 -0
- coco_core/example_selectors/__init__.py +47 -0
- coco_core/example_selectors/base.py +60 -0
- coco_core/example_selectors/length_based.py +131 -0
- coco_core/example_selectors/semantic_similarity.py +366 -0
- coco_core/exceptions.py +166 -0
- coco_core/globals.py +72 -0
- coco_core/indexing/__init__.py +53 -0
- coco_core/indexing/api.py +954 -0
- coco_core/indexing/base.py +661 -0
- coco_core/indexing/in_memory.py +104 -0
- coco_core/language_models/__init__.py +116 -0
- coco_core/language_models/_compat_bridge.py +844 -0
- coco_core/language_models/_utils.py +343 -0
- coco_core/language_models/base.py +500 -0
- coco_core/language_models/chat_model_stream.py +1525 -0
- coco_core/language_models/chat_models.py +2748 -0
- coco_core/language_models/fake.py +137 -0
- coco_core/language_models/fake_chat_models.py +396 -0
- coco_core/language_models/llms.py +1569 -0
- coco_core/language_models/model_profile.py +183 -0
- coco_core/load/__init__.py +44 -0
- coco_core/load/_validation.py +191 -0
- coco_core/load/dump.py +120 -0
- coco_core/load/load.py +828 -0
- coco_core/load/mapping.py +1097 -0
- coco_core/load/serializable.py +406 -0
- coco_core/messages/__init__.py +198 -0
- coco_core/messages/ai.py +854 -0
- coco_core/messages/base.py +518 -0
- coco_core/messages/block_translators/__init__.py +112 -0
- coco_core/messages/block_translators/anthropic.py +534 -0
- coco_core/messages/block_translators/bedrock.py +108 -0
- coco_core/messages/block_translators/bedrock_converse.py +329 -0
- coco_core/messages/block_translators/coco_v0.py +303 -0
- coco_core/messages/block_translators/google_genai.py +610 -0
- coco_core/messages/block_translators/google_vertexai.py +21 -0
- coco_core/messages/block_translators/groq.py +157 -0
- coco_core/messages/block_translators/openai.py +1089 -0
- coco_core/messages/chat.py +64 -0
- coco_core/messages/content.py +1488 -0
- coco_core/messages/function.py +62 -0
- coco_core/messages/human.py +70 -0
- coco_core/messages/modifier.py +33 -0
- coco_core/messages/system.py +70 -0
- coco_core/messages/tool.py +418 -0
- coco_core/messages/utils.py +2442 -0
- coco_core/output_parsers/__init__.py +101 -0
- coco_core/output_parsers/base.py +361 -0
- coco_core/output_parsers/format_instructions.py +16 -0
- coco_core/output_parsers/json.py +139 -0
- coco_core/output_parsers/list.py +249 -0
- coco_core/output_parsers/openai_functions.py +324 -0
- coco_core/output_parsers/openai_tools.py +383 -0
- coco_core/output_parsers/pydantic.py +141 -0
- coco_core/output_parsers/string.py +63 -0
- coco_core/output_parsers/transform.py +175 -0
- coco_core/output_parsers/xml.py +301 -0
- coco_core/outputs/__init__.py +66 -0
- coco_core/outputs/chat_generation.py +147 -0
- coco_core/outputs/chat_result.py +39 -0
- coco_core/outputs/generation.py +80 -0
- coco_core/outputs/llm_result.py +112 -0
- coco_core/outputs/run_info.py +22 -0
- coco_core/prompt_values.py +161 -0
- coco_core/prompts/__init__.py +101 -0
- coco_core/prompts/base.py +508 -0
- coco_core/prompts/chat.py +1495 -0
- coco_core/prompts/dict.py +177 -0
- coco_core/prompts/few_shot.py +483 -0
- coco_core/prompts/few_shot_with_templates.py +239 -0
- coco_core/prompts/image.py +177 -0
- coco_core/prompts/loading.py +296 -0
- coco_core/prompts/message.py +97 -0
- coco_core/prompts/prompt.py +312 -0
- coco_core/prompts/string.py +399 -0
- coco_core/prompts/structured.py +214 -0
- coco_core/py.typed +0 -0
- coco_core/rate_limiters.py +254 -0
- coco_core/retrievers.py +328 -0
- coco_core/runnables/__init__.py +136 -0
- coco_core/runnables/base.py +6725 -0
- coco_core/runnables/branch.py +457 -0
- coco_core/runnables/config.py +712 -0
- coco_core/runnables/configurable.py +710 -0
- coco_core/runnables/fallbacks.py +663 -0
- coco_core/runnables/graph.py +741 -0
- coco_core/runnables/graph_ascii.py +366 -0
- coco_core/runnables/graph_mermaid.py +503 -0
- coco_core/runnables/graph_png.py +215 -0
- coco_core/runnables/history.py +631 -0
- coco_core/runnables/passthrough.py +849 -0
- coco_core/runnables/retry.py +379 -0
- coco_core/runnables/router.py +239 -0
- coco_core/runnables/schema.py +188 -0
- coco_core/runnables/utils.py +798 -0
- coco_core/stores.py +291 -0
- coco_core/structured_query.py +203 -0
- coco_core/sys_info.py +154 -0
- coco_core/tools/__init__.py +95 -0
- coco_core/tools/base.py +1948 -0
- coco_core/tools/convert.py +497 -0
- coco_core/tools/render.py +67 -0
- coco_core/tools/retriever.py +94 -0
- coco_core/tools/simple.py +208 -0
- coco_core/tools/structured.py +322 -0
- coco_core/tracers/__init__.py +47 -0
- coco_core/tracers/_compat.py +95 -0
- coco_core/tracers/_context.py +337 -0
- coco_core/tracers/_streaming.py +53 -0
- coco_core/tracers/base.py +955 -0
- coco_core/tracers/coco.py +279 -0
- coco_core/tracers/context.py +205 -0
- coco_core/tracers/core.py +766 -0
- coco_core/tracers/event_stream.py +1101 -0
- coco_core/tracers/log_stream.py +765 -0
- coco_core/tracers/memory_stream.py +200 -0
- coco_core/tracers/root_listeners.py +130 -0
- coco_core/tracers/run_collector.py +40 -0
- coco_core/tracers/schemas.py +14 -0
- coco_core/tracers/stdout.py +205 -0
- coco_core/utils/__init__.py +111 -0
- coco_core/utils/_gateway.py +274 -0
- coco_core/utils/_merge.py +218 -0
- coco_core/utils/aiter.py +357 -0
- coco_core/utils/env.py +86 -0
- coco_core/utils/formatting.py +80 -0
- coco_core/utils/function_calling.py +869 -0
- coco_core/utils/html.py +132 -0
- coco_core/utils/image.py +15 -0
- coco_core/utils/input.py +82 -0
- coco_core/utils/interactive_env.py +12 -0
- coco_core/utils/iter.py +229 -0
- coco_core/utils/json.py +230 -0
- coco_core/utils/json_schema.py +273 -0
- coco_core/utils/mustache.py +706 -0
- coco_core/utils/pydantic.py +631 -0
- coco_core/utils/strings.py +69 -0
- coco_core/utils/usage.py +61 -0
- coco_core/utils/utils.py +528 -0
- coco_core/utils/uuid.py +57 -0
- coco_core/vectorstores/__init__.py +53 -0
- coco_core/vectorstores/base.py +1111 -0
- coco_core/vectorstores/in_memory.py +546 -0
- coco_core/vectorstores/utils.py +163 -0
- coco_core/version.py +3 -0
- coco_framework-0.1.0.dist-info/METADATA +184 -0
- coco_framework-0.1.0.dist-info/RECORD +400 -0
- coco_framework-0.1.0.dist-info/WHEEL +4 -0
- coco_framework-0.1.0.dist-info/licenses/LICENSE +24 -0
- coco_framework-0.1.0.dist-info/licenses/NOTICE +15 -0
- coco_graph/_internal/__init__.py +4 -0
- coco_graph/_internal/_cache.py +31 -0
- coco_graph/_internal/_config.py +474 -0
- coco_graph/_internal/_constants.py +140 -0
- coco_graph/_internal/_fields.py +213 -0
- coco_graph/_internal/_future.py +220 -0
- coco_graph/_internal/_pydantic.py +275 -0
- coco_graph/_internal/_queue.py +124 -0
- coco_graph/_internal/_replay.py +90 -0
- coco_graph/_internal/_retry.py +29 -0
- coco_graph/_internal/_runnable.py +969 -0
- coco_graph/_internal/_scratchpad.py +19 -0
- coco_graph/_internal/_serde.py +253 -0
- coco_graph/_internal/_timeout.py +25 -0
- coco_graph/_internal/_typing.py +54 -0
- coco_graph/cache/base/__init__.py +48 -0
- coco_graph/cache/base/py.typed +0 -0
- coco_graph/cache/memory/__init__.py +73 -0
- coco_graph/cache/redis/__init__.py +144 -0
- coco_graph/cache/sqlite/__init__.py +120 -0
- coco_graph/callbacks.py +394 -0
- coco_graph/channels/__init__.py +29 -0
- coco_graph/channels/any_value.py +72 -0
- coco_graph/channels/base.py +121 -0
- coco_graph/channels/binop.py +155 -0
- coco_graph/channels/delta.py +202 -0
- coco_graph/channels/ephemeral_value.py +79 -0
- coco_graph/channels/last_value.py +151 -0
- coco_graph/channels/named_barrier_value.py +167 -0
- coco_graph/channels/topic.py +94 -0
- coco_graph/channels/untracked_value.py +73 -0
- coco_graph/checkpoint/base/__init__.py +861 -0
- coco_graph/checkpoint/base/id.py +109 -0
- coco_graph/checkpoint/base/py.typed +0 -0
- coco_graph/checkpoint/memory/__init__.py +698 -0
- coco_graph/checkpoint/memory/py.typed +0 -0
- coco_graph/checkpoint/postgres/__init__.py +602 -0
- coco_graph/checkpoint/postgres/_ainternal.py +23 -0
- coco_graph/checkpoint/postgres/_internal.py +21 -0
- coco_graph/checkpoint/postgres/aio.py +691 -0
- coco_graph/checkpoint/postgres/base.py +666 -0
- coco_graph/checkpoint/postgres/py.typed +0 -0
- coco_graph/checkpoint/postgres/shallow.py +967 -0
- coco_graph/checkpoint/serde/__init__.py +0 -0
- coco_graph/checkpoint/serde/_msgpack.py +97 -0
- coco_graph/checkpoint/serde/base.py +64 -0
- coco_graph/checkpoint/serde/encrypted.py +80 -0
- coco_graph/checkpoint/serde/event_hooks.py +52 -0
- coco_graph/checkpoint/serde/jsonplus.py +883 -0
- coco_graph/checkpoint/serde/py.typed +0 -0
- coco_graph/checkpoint/serde/types.py +68 -0
- coco_graph/checkpoint/sqlite/__init__.py +645 -0
- coco_graph/checkpoint/sqlite/_delta.py +172 -0
- coco_graph/checkpoint/sqlite/aio.py +738 -0
- coco_graph/checkpoint/sqlite/py.typed +0 -0
- coco_graph/checkpoint/sqlite/utils.py +116 -0
- coco_graph/config.py +196 -0
- coco_graph/constants.py +64 -0
- coco_graph/errors.py +241 -0
- coco_graph/func/__init__.py +620 -0
- coco_graph/graph/__init__.py +12 -0
- coco_graph/graph/_branch.py +225 -0
- coco_graph/graph/_node.py +103 -0
- coco_graph/graph/message.py +437 -0
- coco_graph/graph/state.py +1978 -0
- coco_graph/graph/ui.py +227 -0
- coco_graph/managed/__init__.py +3 -0
- coco_graph/managed/base.py +31 -0
- coco_graph/managed/is_last_step.py +24 -0
- coco_graph/prebuilt/__init__.py +23 -0
- coco_graph/prebuilt/_tool_call_stream.py +117 -0
- coco_graph/prebuilt/_tool_call_transformer.py +165 -0
- coco_graph/prebuilt/chat_agent_executor.py +1015 -0
- coco_graph/prebuilt/interrupt.py +105 -0
- coco_graph/prebuilt/py.typed +0 -0
- coco_graph/prebuilt/tool_node.py +2030 -0
- coco_graph/prebuilt/tool_validator.py +221 -0
- coco_graph/pregel/__init__.py +3 -0
- coco_graph/pregel/_algo.py +1460 -0
- coco_graph/pregel/_call.py +298 -0
- coco_graph/pregel/_checkpoint.py +331 -0
- coco_graph/pregel/_config.py +0 -0
- coco_graph/pregel/_draw.py +294 -0
- coco_graph/pregel/_executor.py +223 -0
- coco_graph/pregel/_io.py +174 -0
- coco_graph/pregel/_log.py +3 -0
- coco_graph/pregel/_loop.py +1988 -0
- coco_graph/pregel/_messages.py +461 -0
- coco_graph/pregel/_read.py +312 -0
- coco_graph/pregel/_retry.py +854 -0
- coco_graph/pregel/_runner.py +941 -0
- coco_graph/pregel/_tools.py +268 -0
- coco_graph/pregel/_utils.py +221 -0
- coco_graph/pregel/_validate.py +120 -0
- coco_graph/pregel/_write.py +192 -0
- coco_graph/pregel/debug.py +302 -0
- coco_graph/pregel/main.py +4364 -0
- coco_graph/pregel/protocol.py +288 -0
- coco_graph/pregel/types.py +38 -0
- coco_graph/py.typed +0 -0
- coco_graph/runtime.py +350 -0
- coco_graph/store/base/__init__.py +1322 -0
- coco_graph/store/base/batch.py +371 -0
- coco_graph/store/base/embed.py +436 -0
- coco_graph/store/base/py.typed +0 -0
- coco_graph/store/memory/__init__.py +592 -0
- coco_graph/store/memory/py.typed +0 -0
- coco_graph/store/postgres/__init__.py +4 -0
- coco_graph/store/postgres/aio.py +592 -0
- coco_graph/store/postgres/base.py +1480 -0
- coco_graph/store/postgres/py.typed +0 -0
- coco_graph/store/sqlite/__init__.py +4 -0
- coco_graph/store/sqlite/aio.py +632 -0
- coco_graph/store/sqlite/base.py +1514 -0
- coco_graph/stream/__init__.py +45 -0
- coco_graph/stream/_convert.py +32 -0
- coco_graph/stream/_mux.py +523 -0
- coco_graph/stream/_types.py +330 -0
- coco_graph/stream/run_stream.py +735 -0
- coco_graph/stream/stream_channel.py +341 -0
- coco_graph/stream/transformers.py +1039 -0
- coco_graph/types.py +1079 -0
- coco_graph/typing.py +48 -0
- coco_graph/utils/__init__.py +1 -0
- coco_graph/utils/config.py +4 -0
- coco_graph/utils/runnable.py +3 -0
- coco_graph/version.py +13 -0
- coco_graph/warnings.py +69 -0
- coco_openai/__init__.py +20 -0
- coco_openai/_compat.py +45 -0
- coco_openai/_version.py +3 -0
- coco_openai/chat_models/__init__.py +6 -0
- coco_openai/chat_models/_client_utils.py +684 -0
- coco_openai/chat_models/_compat.py +525 -0
- coco_openai/chat_models/azure.py +1227 -0
- coco_openai/chat_models/base.py +5654 -0
- coco_openai/chat_models/codex.py +557 -0
- coco_openai/chatgpt_oauth.py +1063 -0
- coco_openai/data/__init__.py +1 -0
- coco_openai/data/_profiles.py +1655 -0
- coco_openai/data/profile_augmentations.toml +127 -0
- coco_openai/embeddings/__init__.py +6 -0
- coco_openai/embeddings/azure.py +240 -0
- coco_openai/embeddings/base.py +820 -0
- coco_openai/llms/__init__.py +6 -0
- coco_openai/llms/azure.py +249 -0
- coco_openai/llms/base.py +919 -0
- coco_openai/middleware/__init__.py +11 -0
- coco_openai/middleware/openai_moderation.py +484 -0
- coco_openai/output_parsers/__init__.py +9 -0
- coco_openai/output_parsers/tools.py +9 -0
- coco_openai/py.typed +0 -0
- coco_openai/tools/__init__.py +5 -0
- coco_openai/tools/custom_tool.py +111 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Module implements a memory stream for communication between two co-routines.
|
|
2
|
+
|
|
3
|
+
This module provides a way to communicate between two co-routines using a memory
|
|
4
|
+
channel. The writer and reader can be in the same event loop or in different event
|
|
5
|
+
loops. When they're in different event loops, they will also be in different threads.
|
|
6
|
+
|
|
7
|
+
Useful in situations when there's a mix of synchronous and asynchronous used in the
|
|
8
|
+
code.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
import contextlib
|
|
13
|
+
import weakref
|
|
14
|
+
from asyncio import AbstractEventLoop, Queue
|
|
15
|
+
from collections.abc import AsyncIterator
|
|
16
|
+
from typing import Any, Generic, TypeVar
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _close_loop_quietly(loop: AbstractEventLoop) -> None:
|
|
22
|
+
"""Close an event loop that was created internally, as a finalizer callback.
|
|
23
|
+
|
|
24
|
+
Errors are suppressed rather than logged. `weakref.finalize` defaults to
|
|
25
|
+
`atexit=True`, so this can run during interpreter shutdown, where `logging`
|
|
26
|
+
may already be torn down. Python routes finalizer exceptions to
|
|
27
|
+
`sys.unraisablehook` rather than propagating them, so suppressing here only
|
|
28
|
+
avoids dumping a traceback to stderr at a nondeterministic moment, which is
|
|
29
|
+
the same kind of noise this cleanup exists to remove. If `close()` does
|
|
30
|
+
fail, the loop's own `__del__` still emits
|
|
31
|
+
`ResourceWarning: unclosed event loop`, so the leak stays detectable.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
loop: The event loop to close. A running loop is left alone.
|
|
35
|
+
"""
|
|
36
|
+
if loop.is_running():
|
|
37
|
+
# `close()` would raise; leave the `ResourceWarning` as the signal.
|
|
38
|
+
return
|
|
39
|
+
with contextlib.suppress(Exception):
|
|
40
|
+
loop.close()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _get_or_create_loop(owner: object) -> AbstractEventLoop:
|
|
44
|
+
"""Get the current event loop, creating one if this thread has none.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
owner: Object whose lifetime bounds a loop created here.
|
|
48
|
+
|
|
49
|
+
A loop created by this function is closed once `owner` is
|
|
50
|
+
garbage collected.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The event loop to back a `_MemoryStream` with.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
return asyncio.get_event_loop()
|
|
57
|
+
except RuntimeError:
|
|
58
|
+
# No loop is set on this thread. That is always the case in a sync
|
|
59
|
+
# context on Python 3.14+, where `get_event_loop()` no longer creates
|
|
60
|
+
# one implicitly, and on any version in a non-main thread.
|
|
61
|
+
#
|
|
62
|
+
# This loop is ours: unlike one returned by `get_event_loop()`, no
|
|
63
|
+
# caller owns it, so close it once `owner` dies. Otherwise the loop's
|
|
64
|
+
# `__del__` emits `ResourceWarning: unclosed event loop` at whatever
|
|
65
|
+
# nondeterministic point GC happens to run.
|
|
66
|
+
loop = asyncio.new_event_loop()
|
|
67
|
+
weakref.finalize(owner, _close_loop_quietly, loop)
|
|
68
|
+
return loop
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class _SendStream(Generic[T]):
|
|
72
|
+
def __init__(
|
|
73
|
+
self, reader_loop: AbstractEventLoop, queue: Queue[Any], done: object
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Create a writer for the queue and done object.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
reader_loop: The event loop to use for the writer.
|
|
79
|
+
|
|
80
|
+
This loop will be used to schedule the writes to the queue.
|
|
81
|
+
queue: The queue to write to.
|
|
82
|
+
|
|
83
|
+
This is an asyncio queue.
|
|
84
|
+
done: Special sentinel object to indicate that the writer is done.
|
|
85
|
+
"""
|
|
86
|
+
self._reader_loop = reader_loop
|
|
87
|
+
self._queue = queue
|
|
88
|
+
self._done = done
|
|
89
|
+
|
|
90
|
+
async def send(self, item: T) -> None:
|
|
91
|
+
"""Schedule the item to be written to the queue using the original loop.
|
|
92
|
+
|
|
93
|
+
This is a coroutine that can be awaited.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
item: The item to write to the queue.
|
|
97
|
+
"""
|
|
98
|
+
return self.send_nowait(item)
|
|
99
|
+
|
|
100
|
+
def send_nowait(self, item: T) -> None:
|
|
101
|
+
"""Schedule the item to be written to the queue using the original loop.
|
|
102
|
+
|
|
103
|
+
This is a non-blocking call.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
item: The item to write to the queue.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
RuntimeError: If the event loop is already closed when trying to write to
|
|
110
|
+
the queue.
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
self._reader_loop.call_soon_threadsafe(self._queue.put_nowait, item)
|
|
114
|
+
except RuntimeError:
|
|
115
|
+
if not self._reader_loop.is_closed():
|
|
116
|
+
raise # Raise the exception if the loop is not closed
|
|
117
|
+
|
|
118
|
+
async def aclose(self) -> None:
|
|
119
|
+
"""Async schedule the done object write the queue using the original loop."""
|
|
120
|
+
return self.close()
|
|
121
|
+
|
|
122
|
+
def close(self) -> None:
|
|
123
|
+
"""Schedule the done object write the queue using the original loop.
|
|
124
|
+
|
|
125
|
+
This is a non-blocking call.
|
|
126
|
+
|
|
127
|
+
Raises:
|
|
128
|
+
RuntimeError: If the event loop is already closed when trying to write to
|
|
129
|
+
the queue.
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
self._reader_loop.call_soon_threadsafe(self._queue.put_nowait, self._done)
|
|
133
|
+
except RuntimeError:
|
|
134
|
+
if not self._reader_loop.is_closed():
|
|
135
|
+
raise # Raise the exception if the loop is not closed
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class _ReceiveStream(Generic[T]):
|
|
139
|
+
def __init__(self, queue: Queue[Any], done: object) -> None:
|
|
140
|
+
"""Create a reader for the queue and done object.
|
|
141
|
+
|
|
142
|
+
This reader should be used in the same loop as the loop that was passed to the
|
|
143
|
+
channel.
|
|
144
|
+
"""
|
|
145
|
+
self._queue = queue
|
|
146
|
+
self._done = done
|
|
147
|
+
self._is_closed = False
|
|
148
|
+
|
|
149
|
+
async def __aiter__(self) -> AsyncIterator[T]:
|
|
150
|
+
while True:
|
|
151
|
+
item = await self._queue.get()
|
|
152
|
+
if item is self._done:
|
|
153
|
+
self._is_closed = True
|
|
154
|
+
break
|
|
155
|
+
yield item
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class _MemoryStream(Generic[T]):
|
|
159
|
+
"""Stream data from a writer to a reader even if they are in different threads.
|
|
160
|
+
|
|
161
|
+
Uses asyncio queues to communicate between two co-routines. This implementation
|
|
162
|
+
should work even if the writer and reader co-routines belong to two different event
|
|
163
|
+
loops (e.g. one running from an event loop in the main thread and the other running
|
|
164
|
+
in an event loop in a background thread).
|
|
165
|
+
|
|
166
|
+
This implementation is meant to be used with a single writer and a single reader.
|
|
167
|
+
|
|
168
|
+
This is an internal implementation to Coco. Do not use it directly.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(self, loop: AbstractEventLoop) -> None:
|
|
172
|
+
"""Create a channel for the given loop.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
loop: The event loop to use for the channel.
|
|
176
|
+
|
|
177
|
+
The reader is assumed to be running in the same loop as the one passed
|
|
178
|
+
to this constructor. This will NOT be validated at run time.
|
|
179
|
+
"""
|
|
180
|
+
self._loop = loop
|
|
181
|
+
self._queue = asyncio.Queue[Any](maxsize=0)
|
|
182
|
+
self._done = object()
|
|
183
|
+
|
|
184
|
+
def get_send_stream(self) -> _SendStream[T]:
|
|
185
|
+
"""Get a writer for the channel.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
The writer for the channel.
|
|
189
|
+
"""
|
|
190
|
+
return _SendStream[T](
|
|
191
|
+
reader_loop=self._loop, queue=self._queue, done=self._done
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def get_receive_stream(self) -> _ReceiveStream[T]:
|
|
195
|
+
"""Get a reader for the channel.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
The reader for the channel.
|
|
199
|
+
"""
|
|
200
|
+
return _ReceiveStream[T](queue=self._queue, done=self._done)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""Tracers that call listeners."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Awaitable, Callable
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from coco_core.runnables.config import (
|
|
7
|
+
RunnableConfig,
|
|
8
|
+
acall_func_with_variable_args,
|
|
9
|
+
call_func_with_variable_args,
|
|
10
|
+
)
|
|
11
|
+
from coco_core.tracers.base import AsyncBaseTracer, BaseTracer
|
|
12
|
+
from coco_core.tracers.schemas import Run
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
Listener = Callable[[Run], None] | Callable[[Run, RunnableConfig], None]
|
|
18
|
+
AsyncListener = (
|
|
19
|
+
Callable[[Run], Awaitable[None]] | Callable[[Run, RunnableConfig], Awaitable[None]]
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RootListenersTracer(BaseTracer):
|
|
24
|
+
"""Tracer that calls listeners on run start, end, and error."""
|
|
25
|
+
|
|
26
|
+
log_missing_parent = False
|
|
27
|
+
"""Whether to log a warning if the parent is missing."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
config: RunnableConfig,
|
|
33
|
+
on_start: Listener | None,
|
|
34
|
+
on_end: Listener | None,
|
|
35
|
+
on_error: Listener | None,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Initialize the tracer.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
config: The runnable config.
|
|
41
|
+
on_start: The listener to call on run start.
|
|
42
|
+
on_end: The listener to call on run end.
|
|
43
|
+
on_error: The listener to call on run error
|
|
44
|
+
"""
|
|
45
|
+
super().__init__(_schema_format="original+chat")
|
|
46
|
+
|
|
47
|
+
self.config = config
|
|
48
|
+
self._arg_on_start = on_start
|
|
49
|
+
self._arg_on_end = on_end
|
|
50
|
+
self._arg_on_error = on_error
|
|
51
|
+
self.root_id: UUID | None = None
|
|
52
|
+
|
|
53
|
+
def _persist_run(self, run: Run) -> None:
|
|
54
|
+
# This is a legacy method only called once for an entire run tree
|
|
55
|
+
# therefore not useful here
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def _on_run_create(self, run: Run) -> None:
|
|
59
|
+
if self.root_id is not None:
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
self.root_id = run.id
|
|
63
|
+
|
|
64
|
+
if self._arg_on_start is not None:
|
|
65
|
+
call_func_with_variable_args(self._arg_on_start, run, self.config)
|
|
66
|
+
|
|
67
|
+
def _on_run_update(self, run: Run) -> None:
|
|
68
|
+
if run.id != self.root_id:
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
if run.error is None:
|
|
72
|
+
if self._arg_on_end is not None:
|
|
73
|
+
call_func_with_variable_args(self._arg_on_end, run, self.config)
|
|
74
|
+
elif self._arg_on_error is not None:
|
|
75
|
+
call_func_with_variable_args(self._arg_on_error, run, self.config)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class AsyncRootListenersTracer(AsyncBaseTracer):
|
|
79
|
+
"""Async tracer that calls listeners on run start, end, and error."""
|
|
80
|
+
|
|
81
|
+
log_missing_parent = False
|
|
82
|
+
"""Whether to log a warning if the parent is missing."""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
*,
|
|
87
|
+
config: RunnableConfig,
|
|
88
|
+
on_start: AsyncListener | None,
|
|
89
|
+
on_end: AsyncListener | None,
|
|
90
|
+
on_error: AsyncListener | None,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""Initialize the tracer.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
config: The runnable config.
|
|
96
|
+
on_start: The listener to call on run start.
|
|
97
|
+
on_end: The listener to call on run end.
|
|
98
|
+
on_error: The listener to call on run error
|
|
99
|
+
"""
|
|
100
|
+
super().__init__(_schema_format="original+chat")
|
|
101
|
+
|
|
102
|
+
self.config = config
|
|
103
|
+
self._arg_on_start = on_start
|
|
104
|
+
self._arg_on_end = on_end
|
|
105
|
+
self._arg_on_error = on_error
|
|
106
|
+
self.root_id: UUID | None = None
|
|
107
|
+
|
|
108
|
+
async def _persist_run(self, run: Run) -> None:
|
|
109
|
+
# This is a legacy method only called once for an entire run tree
|
|
110
|
+
# therefore not useful here
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
async def _on_run_create(self, run: Run) -> None:
|
|
114
|
+
if self.root_id is not None:
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
self.root_id = run.id
|
|
118
|
+
|
|
119
|
+
if self._arg_on_start is not None:
|
|
120
|
+
await acall_func_with_variable_args(self._arg_on_start, run, self.config)
|
|
121
|
+
|
|
122
|
+
async def _on_run_update(self, run: Run) -> None:
|
|
123
|
+
if run.id != self.root_id:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
if run.error is None:
|
|
127
|
+
if self._arg_on_end is not None:
|
|
128
|
+
await acall_func_with_variable_args(self._arg_on_end, run, self.config)
|
|
129
|
+
elif self._arg_on_error is not None:
|
|
130
|
+
await acall_func_with_variable_args(self._arg_on_error, run, self.config)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""A tracer that collects all nested runs in a list."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from coco_core.tracers._compat import run_copy
|
|
7
|
+
from coco_core.tracers.base import BaseTracer
|
|
8
|
+
from coco_core.tracers.schemas import Run
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RunCollectorCallbackHandler(BaseTracer):
|
|
12
|
+
"""Tracer that collects all nested runs in a list.
|
|
13
|
+
|
|
14
|
+
This tracer is useful for inspection and evaluation purposes.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name: str = "run-collector_callback_handler"
|
|
18
|
+
|
|
19
|
+
def __init__(self, example_id: UUID | str | None = None, **kwargs: Any) -> None:
|
|
20
|
+
"""Initialize the `RunCollectorCallbackHandler`.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
example_id: The ID of the example being traced.
|
|
24
|
+
**kwargs: Additional keyword arguments.
|
|
25
|
+
"""
|
|
26
|
+
super().__init__(**kwargs)
|
|
27
|
+
self.example_id = (
|
|
28
|
+
UUID(example_id) if isinstance(example_id, str) else example_id
|
|
29
|
+
)
|
|
30
|
+
self.traced_runs: list[Run] = []
|
|
31
|
+
|
|
32
|
+
def _persist_run(self, run: Run) -> None:
|
|
33
|
+
"""Persist a run by adding it to the `traced_runs` list.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
run: The run to be persisted.
|
|
37
|
+
"""
|
|
38
|
+
run_ = run_copy(run)
|
|
39
|
+
run_.reference_example_id = self.example_id
|
|
40
|
+
self.traced_runs.append(run_)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""Tracers that print to the console."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from coco_core.tracers.base import BaseTracer
|
|
8
|
+
from coco_core.tracers.schemas import Run
|
|
9
|
+
from coco_core.utils.input import get_bolded_text, get_colored_text
|
|
10
|
+
|
|
11
|
+
MILLISECONDS_IN_SECOND = 1000
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def try_json_stringify(obj: Any, fallback: str) -> str:
|
|
15
|
+
"""Try to stringify an object to JSON.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
obj: Object to stringify.
|
|
19
|
+
fallback: Fallback string to return if the object cannot be stringified.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
A JSON string if the object can be stringified, otherwise the fallback string.
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
return json.dumps(obj, indent=2, ensure_ascii=False)
|
|
26
|
+
except Exception:
|
|
27
|
+
return fallback
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def elapsed(run: Any) -> str:
|
|
31
|
+
"""Get the elapsed time of a run.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
run: any object with a `start_time` and `end_time` attribute.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
A string with the elapsed time in seconds or milliseconds if time is less than a
|
|
38
|
+
second.
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
elapsed_time = run.end_time - run.start_time
|
|
42
|
+
seconds = elapsed_time.total_seconds()
|
|
43
|
+
if seconds < 1:
|
|
44
|
+
return f"{seconds * MILLISECONDS_IN_SECOND:.0f}ms"
|
|
45
|
+
return f"{seconds:.2f}s"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class FunctionCallbackHandler(BaseTracer):
|
|
49
|
+
"""Tracer that calls a function with a single str parameter."""
|
|
50
|
+
|
|
51
|
+
name: str = "function_callback_handler"
|
|
52
|
+
"""The name of the tracer.
|
|
53
|
+
|
|
54
|
+
This is used to identify the tracer in the logs.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, function: Callable[[str], None], **kwargs: Any) -> None:
|
|
58
|
+
"""Create a `FunctionCallbackHandler`.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
function: The callback function to call.
|
|
62
|
+
"""
|
|
63
|
+
super().__init__(**kwargs)
|
|
64
|
+
self.function_callback = function
|
|
65
|
+
|
|
66
|
+
def _persist_run(self, run: Run) -> None:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
def get_parents(self, run: Run) -> list[Run]:
|
|
70
|
+
"""Get the parents of a run.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
run: The run to get the parents of.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
A list of parent runs.
|
|
77
|
+
"""
|
|
78
|
+
parents = []
|
|
79
|
+
current_run = run
|
|
80
|
+
while current_run.parent_run_id:
|
|
81
|
+
parent = self.run_map.get(str(current_run.parent_run_id))
|
|
82
|
+
if parent:
|
|
83
|
+
parents.append(parent)
|
|
84
|
+
current_run = parent
|
|
85
|
+
else:
|
|
86
|
+
break
|
|
87
|
+
return parents
|
|
88
|
+
|
|
89
|
+
def get_breadcrumbs(self, run: Run) -> str:
|
|
90
|
+
"""Get the breadcrumbs of a run.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
run: The run to get the breadcrumbs of.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
A string with the breadcrumbs of the run.
|
|
97
|
+
"""
|
|
98
|
+
parents = self.get_parents(run)[::-1]
|
|
99
|
+
return " > ".join(
|
|
100
|
+
f"{parent.run_type}:{parent.name}"
|
|
101
|
+
for i, parent in enumerate([*parents, run])
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# logging methods
|
|
105
|
+
def _on_chain_start(self, run: Run) -> None:
|
|
106
|
+
crumbs = self.get_breadcrumbs(run)
|
|
107
|
+
run_type = run.run_type.capitalize()
|
|
108
|
+
self.function_callback(
|
|
109
|
+
f"{get_colored_text('[chain/start]', color='green')} "
|
|
110
|
+
+ get_bolded_text(f"[{crumbs}] Entering {run_type} run with input:\n")
|
|
111
|
+
+ f"{try_json_stringify(run.inputs, '[inputs]')}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def _on_chain_end(self, run: Run) -> None:
|
|
115
|
+
crumbs = self.get_breadcrumbs(run)
|
|
116
|
+
run_type = run.run_type.capitalize()
|
|
117
|
+
self.function_callback(
|
|
118
|
+
f"{get_colored_text('[chain/end]', color='blue')} "
|
|
119
|
+
+ get_bolded_text(
|
|
120
|
+
f"[{crumbs}] [{elapsed(run)}] Exiting {run_type} run with output:\n"
|
|
121
|
+
)
|
|
122
|
+
+ f"{try_json_stringify(run.outputs, '[outputs]')}"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def _on_chain_error(self, run: Run) -> None:
|
|
126
|
+
crumbs = self.get_breadcrumbs(run)
|
|
127
|
+
run_type = run.run_type.capitalize()
|
|
128
|
+
self.function_callback(
|
|
129
|
+
f"{get_colored_text('[chain/error]', color='red')} "
|
|
130
|
+
+ get_bolded_text(
|
|
131
|
+
f"[{crumbs}] [{elapsed(run)}] {run_type} run errored with error:\n"
|
|
132
|
+
)
|
|
133
|
+
+ f"{try_json_stringify(run.error, '[error]')}"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def _on_llm_start(self, run: Run) -> None:
|
|
137
|
+
crumbs = self.get_breadcrumbs(run)
|
|
138
|
+
inputs = (
|
|
139
|
+
{"prompts": [p.strip() for p in run.inputs["prompts"]]}
|
|
140
|
+
if "prompts" in run.inputs
|
|
141
|
+
else run.inputs
|
|
142
|
+
)
|
|
143
|
+
self.function_callback(
|
|
144
|
+
f"{get_colored_text('[llm/start]', color='green')} "
|
|
145
|
+
+ get_bolded_text(f"[{crumbs}] Entering LLM run with input:\n")
|
|
146
|
+
+ f"{try_json_stringify(inputs, '[inputs]')}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def _on_llm_end(self, run: Run) -> None:
|
|
150
|
+
crumbs = self.get_breadcrumbs(run)
|
|
151
|
+
self.function_callback(
|
|
152
|
+
f"{get_colored_text('[llm/end]', color='blue')} "
|
|
153
|
+
+ get_bolded_text(
|
|
154
|
+
f"[{crumbs}] [{elapsed(run)}] Exiting LLM run with output:\n"
|
|
155
|
+
)
|
|
156
|
+
+ f"{try_json_stringify(run.outputs, '[response]')}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def _on_llm_error(self, run: Run) -> None:
|
|
160
|
+
crumbs = self.get_breadcrumbs(run)
|
|
161
|
+
self.function_callback(
|
|
162
|
+
f"{get_colored_text('[llm/error]', color='red')} "
|
|
163
|
+
+ get_bolded_text(
|
|
164
|
+
f"[{crumbs}] [{elapsed(run)}] LLM run errored with error:\n"
|
|
165
|
+
)
|
|
166
|
+
+ f"{try_json_stringify(run.error, '[error]')}"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def _on_tool_start(self, run: Run) -> None:
|
|
170
|
+
crumbs = self.get_breadcrumbs(run)
|
|
171
|
+
self.function_callback(
|
|
172
|
+
f"{get_colored_text('[tool/start]', color='green')} "
|
|
173
|
+
+ get_bolded_text(f"[{crumbs}] Entering Tool run with input:\n")
|
|
174
|
+
+ f'"{run.inputs["input"].strip()}"'
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def _on_tool_end(self, run: Run) -> None:
|
|
178
|
+
crumbs = self.get_breadcrumbs(run)
|
|
179
|
+
if run.outputs:
|
|
180
|
+
self.function_callback(
|
|
181
|
+
f"{get_colored_text('[tool/end]', color='blue')} "
|
|
182
|
+
+ get_bolded_text(
|
|
183
|
+
f"[{crumbs}] [{elapsed(run)}] Exiting Tool run with output:\n"
|
|
184
|
+
)
|
|
185
|
+
+ f'"{str(run.outputs["output"]).strip()}"'
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def _on_tool_error(self, run: Run) -> None:
|
|
189
|
+
crumbs = self.get_breadcrumbs(run)
|
|
190
|
+
self.function_callback(
|
|
191
|
+
f"{get_colored_text('[tool/error]', color='red')} "
|
|
192
|
+
+ get_bolded_text(f"[{crumbs}] [{elapsed(run)}] ")
|
|
193
|
+
+ f"Tool run errored with error:\n"
|
|
194
|
+
f"{run.error}"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class ConsoleCallbackHandler(FunctionCallbackHandler):
|
|
199
|
+
"""Tracer that prints to the console."""
|
|
200
|
+
|
|
201
|
+
name: str = "console_callback_handler"
|
|
202
|
+
|
|
203
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
204
|
+
"""Create a ConsoleCallbackHandler."""
|
|
205
|
+
super().__init__(function=print, **kwargs)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""Utility functions for Coco.
|
|
2
|
+
|
|
3
|
+
These functions do not depend on any other Coco module.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from coco_core._import_utils import import_attr
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
# for type checking and IDE support, we include the imports here
|
|
12
|
+
# but we don't want to eagerly import them at runtime
|
|
13
|
+
from coco_core.utils import image
|
|
14
|
+
from coco_core.utils.aiter import abatch_iterate
|
|
15
|
+
from coco_core.utils.env import get_from_dict_or_env, get_from_env
|
|
16
|
+
from coco_core.utils.formatting import StrictFormatter, formatter
|
|
17
|
+
from coco_core.utils.input import (
|
|
18
|
+
get_bolded_text,
|
|
19
|
+
get_color_mapping,
|
|
20
|
+
get_colored_text,
|
|
21
|
+
print_text,
|
|
22
|
+
)
|
|
23
|
+
from coco_core.utils.iter import batch_iterate
|
|
24
|
+
from coco_core.utils.pydantic import pre_init
|
|
25
|
+
from coco_core.utils.strings import (
|
|
26
|
+
comma_list,
|
|
27
|
+
sanitize_for_postgres,
|
|
28
|
+
stringify_dict,
|
|
29
|
+
stringify_value,
|
|
30
|
+
)
|
|
31
|
+
from coco_core.utils.utils import (
|
|
32
|
+
build_extra_kwargs,
|
|
33
|
+
check_package_version,
|
|
34
|
+
convert_to_secret_str,
|
|
35
|
+
from_env,
|
|
36
|
+
get_pydantic_field_names,
|
|
37
|
+
guard_import,
|
|
38
|
+
mock_now,
|
|
39
|
+
raise_for_status_with_text,
|
|
40
|
+
secret_from_env,
|
|
41
|
+
xor_args,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
__all__ = (
|
|
45
|
+
"StrictFormatter",
|
|
46
|
+
"abatch_iterate",
|
|
47
|
+
"batch_iterate",
|
|
48
|
+
"build_extra_kwargs",
|
|
49
|
+
"check_package_version",
|
|
50
|
+
"comma_list",
|
|
51
|
+
"convert_to_secret_str",
|
|
52
|
+
"formatter",
|
|
53
|
+
"from_env",
|
|
54
|
+
"get_bolded_text",
|
|
55
|
+
"get_color_mapping",
|
|
56
|
+
"get_colored_text",
|
|
57
|
+
"get_from_dict_or_env",
|
|
58
|
+
"get_from_env",
|
|
59
|
+
"get_pydantic_field_names",
|
|
60
|
+
"guard_import",
|
|
61
|
+
"image",
|
|
62
|
+
"mock_now",
|
|
63
|
+
"pre_init",
|
|
64
|
+
"print_text",
|
|
65
|
+
"raise_for_status_with_text",
|
|
66
|
+
"sanitize_for_postgres",
|
|
67
|
+
"secret_from_env",
|
|
68
|
+
"stringify_dict",
|
|
69
|
+
"stringify_value",
|
|
70
|
+
"xor_args",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
_dynamic_imports = {
|
|
74
|
+
"image": "__module__",
|
|
75
|
+
"abatch_iterate": "aiter",
|
|
76
|
+
"get_from_dict_or_env": "env",
|
|
77
|
+
"get_from_env": "env",
|
|
78
|
+
"StrictFormatter": "formatting",
|
|
79
|
+
"formatter": "formatting",
|
|
80
|
+
"get_bolded_text": "input",
|
|
81
|
+
"get_color_mapping": "input",
|
|
82
|
+
"get_colored_text": "input",
|
|
83
|
+
"print_text": "input",
|
|
84
|
+
"batch_iterate": "iter",
|
|
85
|
+
"pre_init": "pydantic",
|
|
86
|
+
"comma_list": "strings",
|
|
87
|
+
"sanitize_for_postgres": "strings",
|
|
88
|
+
"stringify_dict": "strings",
|
|
89
|
+
"stringify_value": "strings",
|
|
90
|
+
"build_extra_kwargs": "utils",
|
|
91
|
+
"check_package_version": "utils",
|
|
92
|
+
"convert_to_secret_str": "utils",
|
|
93
|
+
"from_env": "utils",
|
|
94
|
+
"get_pydantic_field_names": "utils",
|
|
95
|
+
"guard_import": "utils",
|
|
96
|
+
"mock_now": "utils",
|
|
97
|
+
"secret_from_env": "utils",
|
|
98
|
+
"xor_args": "utils",
|
|
99
|
+
"raise_for_status_with_text": "utils",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def __getattr__(attr_name: str) -> object:
|
|
104
|
+
module_name = _dynamic_imports.get(attr_name)
|
|
105
|
+
result = import_attr(attr_name, module_name, __spec__.parent)
|
|
106
|
+
globals()[attr_name] = result
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def __dir__() -> list[str]:
|
|
111
|
+
return list(__all__)
|