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,497 @@
|
|
|
1
|
+
"""Convert functions and runnables to tools."""
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any, Literal, cast, get_type_hints, overload
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field, RootModel, create_model
|
|
8
|
+
|
|
9
|
+
from coco_core.callbacks import Callbacks
|
|
10
|
+
from coco_core.runnables import Runnable
|
|
11
|
+
from coco_core.tools.base import ArgsSchema, BaseTool
|
|
12
|
+
from coco_core.tools.simple import Tool
|
|
13
|
+
from coco_core.tools.structured import StructuredTool
|
|
14
|
+
from coco_core.utils.pydantic import TypeBaseModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@overload
|
|
18
|
+
def tool(
|
|
19
|
+
*,
|
|
20
|
+
description: str | None = None,
|
|
21
|
+
return_direct: bool = False,
|
|
22
|
+
args_schema: ArgsSchema | None = None,
|
|
23
|
+
infer_schema: bool = True,
|
|
24
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
25
|
+
parse_docstring: bool = False,
|
|
26
|
+
error_on_invalid_docstring: bool = True,
|
|
27
|
+
extras: dict[str, Any] | None = None,
|
|
28
|
+
) -> Callable[[Callable[..., Any] | Runnable[Any, Any]], BaseTool]: ...
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@overload
|
|
32
|
+
def tool(
|
|
33
|
+
name_or_callable: str,
|
|
34
|
+
runnable: Runnable[Any, Any],
|
|
35
|
+
*,
|
|
36
|
+
description: str | None = None,
|
|
37
|
+
return_direct: bool = False,
|
|
38
|
+
args_schema: ArgsSchema | None = None,
|
|
39
|
+
infer_schema: bool = True,
|
|
40
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
41
|
+
parse_docstring: bool = False,
|
|
42
|
+
error_on_invalid_docstring: bool = True,
|
|
43
|
+
extras: dict[str, Any] | None = None,
|
|
44
|
+
) -> BaseTool: ...
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@overload
|
|
48
|
+
def tool(
|
|
49
|
+
name_or_callable: Callable[..., Any],
|
|
50
|
+
*,
|
|
51
|
+
description: str | None = None,
|
|
52
|
+
return_direct: bool = False,
|
|
53
|
+
args_schema: ArgsSchema | None = None,
|
|
54
|
+
infer_schema: bool = True,
|
|
55
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
56
|
+
parse_docstring: bool = False,
|
|
57
|
+
error_on_invalid_docstring: bool = True,
|
|
58
|
+
extras: dict[str, Any] | None = None,
|
|
59
|
+
) -> BaseTool: ...
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@overload
|
|
63
|
+
def tool(
|
|
64
|
+
name_or_callable: str,
|
|
65
|
+
*,
|
|
66
|
+
description: str | None = None,
|
|
67
|
+
return_direct: bool = False,
|
|
68
|
+
args_schema: ArgsSchema | None = None,
|
|
69
|
+
infer_schema: bool = True,
|
|
70
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
71
|
+
parse_docstring: bool = False,
|
|
72
|
+
error_on_invalid_docstring: bool = True,
|
|
73
|
+
extras: dict[str, Any] | None = None,
|
|
74
|
+
) -> Callable[[Callable[..., Any] | Runnable[Any, Any]], BaseTool]: ...
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def tool(
|
|
78
|
+
name_or_callable: str | Callable[..., Any] | None = None,
|
|
79
|
+
runnable: Runnable[Any, Any] | None = None,
|
|
80
|
+
*args: Any,
|
|
81
|
+
description: str | None = None,
|
|
82
|
+
return_direct: bool = False,
|
|
83
|
+
args_schema: ArgsSchema | None = None,
|
|
84
|
+
infer_schema: bool = True,
|
|
85
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
86
|
+
parse_docstring: bool = False,
|
|
87
|
+
error_on_invalid_docstring: bool = True,
|
|
88
|
+
extras: dict[str, Any] | None = None,
|
|
89
|
+
) -> BaseTool | Callable[[Callable[..., Any] | Runnable[Any, Any]], BaseTool]:
|
|
90
|
+
"""Convert Python functions and `Runnables` to Coco tools.
|
|
91
|
+
|
|
92
|
+
Can be used as a decorator with or without arguments to create tools from functions.
|
|
93
|
+
|
|
94
|
+
Functions can have any signature - the tool will automatically infer input schemas
|
|
95
|
+
unless disabled.
|
|
96
|
+
|
|
97
|
+
!!! note "Requirements"
|
|
98
|
+
|
|
99
|
+
- Functions should have type hints for proper schema inference.
|
|
100
|
+
- Functions may accept multiple arguments and return types are flexible;
|
|
101
|
+
outputs will be serialized if needed.
|
|
102
|
+
- When using with `Runnable`, a string name must be provided.
|
|
103
|
+
|
|
104
|
+
!!! warning "Reserved argument names"
|
|
105
|
+
|
|
106
|
+
Avoid naming tool arguments `config`, `run_manager`, or `callbacks`. These
|
|
107
|
+
collide with values Coco injects into tools at call time. A `config`
|
|
108
|
+
argument is shadowed by the injected `RunnableConfig`, so the tool fails
|
|
109
|
+
at call time with `TypeError: ... missing 1 required positional argument:
|
|
110
|
+
'config'`, while `run_manager` and `callbacks` are silently dropped from
|
|
111
|
+
the generated schema. To access runtime information (state, context, store,
|
|
112
|
+
config), add a `ToolRuntime` parameter instead.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
name_or_callable: Optional name of the tool or the `Callable` to be
|
|
116
|
+
converted to a tool.
|
|
117
|
+
|
|
118
|
+
Overrides the function's name.
|
|
119
|
+
|
|
120
|
+
Must be provided as a positional argument.
|
|
121
|
+
runnable: Optional `Runnable` to convert to a tool.
|
|
122
|
+
|
|
123
|
+
Must be provided as a positional argument.
|
|
124
|
+
description: Optional description for the tool.
|
|
125
|
+
|
|
126
|
+
Precedence for the tool description value is as follows:
|
|
127
|
+
|
|
128
|
+
- This `description` argument (used even if docstring and/or `args_schema`
|
|
129
|
+
are provided)
|
|
130
|
+
- Tool function docstring (used even if `args_schema` is provided)
|
|
131
|
+
- `args_schema` description (used only if `description` and docstring are
|
|
132
|
+
not provided)
|
|
133
|
+
*args: Extra positional arguments.
|
|
134
|
+
|
|
135
|
+
Must be empty.
|
|
136
|
+
return_direct: Whether to return directly from the tool rather than continuing
|
|
137
|
+
the agent loop.
|
|
138
|
+
args_schema: Optional argument schema for user to specify.
|
|
139
|
+
infer_schema: Whether to infer the schema of the arguments from the function's
|
|
140
|
+
signature.
|
|
141
|
+
|
|
142
|
+
This also makes the resultant tool accept a dictionary input to its `run()`
|
|
143
|
+
function.
|
|
144
|
+
response_format: The tool response format.
|
|
145
|
+
|
|
146
|
+
If `'content'`, then the output of the tool is interpreted as the contents
|
|
147
|
+
of a `ToolMessage`.
|
|
148
|
+
|
|
149
|
+
If `'content_and_artifact'`, then the output is expected to be a two-tuple
|
|
150
|
+
corresponding to the `(content, artifact)` of a `ToolMessage`.
|
|
151
|
+
parse_docstring: If `infer_schema` and `parse_docstring`, will attempt to
|
|
152
|
+
parse parameter descriptions from Google Style function docstrings.
|
|
153
|
+
error_on_invalid_docstring: If `parse_docstring` is provided, configure
|
|
154
|
+
whether to raise `ValueError` on invalid Google Style docstrings.
|
|
155
|
+
extras: Optional provider-specific extra fields for the tool.
|
|
156
|
+
|
|
157
|
+
Used to pass configuration that doesn't fit into standard tool fields.
|
|
158
|
+
Chat models should process known extras when constructing model payloads.
|
|
159
|
+
|
|
160
|
+
!!! example
|
|
161
|
+
|
|
162
|
+
For example, Anthropic-specific fields like `cache_control`,
|
|
163
|
+
`defer_loading`, or `input_examples`.
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
ValueError: If too many positional arguments are provided (e.g. violating the
|
|
167
|
+
`*args` constraint).
|
|
168
|
+
ValueError: If a `Runnable` is provided without a string name. When using `tool`
|
|
169
|
+
with a `Runnable`, a `str` name must be provided as the `name_or_callable`.
|
|
170
|
+
ValueError: If the first argument is not a string or callable with
|
|
171
|
+
a `__name__` attribute.
|
|
172
|
+
ValueError: If the function does not have a docstring and description
|
|
173
|
+
is not provided and `infer_schema` is `False`.
|
|
174
|
+
ValueError: If `parse_docstring` is `True` and the function has an invalid
|
|
175
|
+
Google-style docstring and `error_on_invalid_docstring` is True.
|
|
176
|
+
ValueError: If a `Runnable` is provided that does not have an object schema.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
The tool.
|
|
180
|
+
|
|
181
|
+
Examples:
|
|
182
|
+
```python
|
|
183
|
+
@tool
|
|
184
|
+
def search_api(query: str) -> str:
|
|
185
|
+
# Searches the API for the query.
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@tool("search", return_direct=True)
|
|
190
|
+
def search_api(query: str) -> str:
|
|
191
|
+
# Searches the API for the query.
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@tool(response_format="content_and_artifact")
|
|
196
|
+
def search_api(query: str) -> tuple[str, dict]:
|
|
197
|
+
return "partial json of results", {"full": "object of results"}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Parse Google-style docstrings:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
@tool(parse_docstring=True)
|
|
204
|
+
def foo(bar: str, baz: int) -> str:
|
|
205
|
+
\"\"\"The foo.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
bar: The bar.
|
|
209
|
+
baz: The baz.
|
|
210
|
+
\"\"\"
|
|
211
|
+
return bar
|
|
212
|
+
|
|
213
|
+
foo.args_schema.model_json_schema()
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
{
|
|
218
|
+
"title": "foo",
|
|
219
|
+
"description": "The foo.",
|
|
220
|
+
"type": "object",
|
|
221
|
+
"properties": {
|
|
222
|
+
"bar": {
|
|
223
|
+
"title": "Bar",
|
|
224
|
+
"description": "The bar.",
|
|
225
|
+
"type": "string",
|
|
226
|
+
},
|
|
227
|
+
"baz": {
|
|
228
|
+
"title": "Baz",
|
|
229
|
+
"description": "The baz.",
|
|
230
|
+
"type": "integer",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
"required": ["bar", "baz"],
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Note that parsing by default will raise `ValueError` if the docstring is
|
|
238
|
+
considered invalid. A docstring is considered invalid if it contains arguments
|
|
239
|
+
not in the function signature, or is unable to be parsed into a summary and
|
|
240
|
+
`'Args:'` blocks. Examples below:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# No args section
|
|
244
|
+
def invalid_docstring_1(bar: str, baz: int) -> str:
|
|
245
|
+
\"\"\"The foo.\"\"\"
|
|
246
|
+
return bar
|
|
247
|
+
|
|
248
|
+
# Improper whitespace between summary and args section
|
|
249
|
+
def invalid_docstring_2(bar: str, baz: int) -> str:
|
|
250
|
+
\"\"\"The foo.
|
|
251
|
+
Args:
|
|
252
|
+
bar: The bar.
|
|
253
|
+
baz: The baz.
|
|
254
|
+
\"\"\"
|
|
255
|
+
return bar
|
|
256
|
+
|
|
257
|
+
# Documented args absent from function signature
|
|
258
|
+
def invalid_docstring_3(bar: str, baz: int) -> str:
|
|
259
|
+
\"\"\"The foo.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
banana: The bar.
|
|
263
|
+
monkey: The baz.
|
|
264
|
+
\"\"\"
|
|
265
|
+
return bar
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
""" # noqa: D214, D410, D411 # We're intentionally showing bad formatting in examples
|
|
269
|
+
|
|
270
|
+
def _create_tool_factory(
|
|
271
|
+
tool_name: str,
|
|
272
|
+
) -> Callable[[Callable[..., Any] | Runnable[Any, Any]], BaseTool]:
|
|
273
|
+
"""Create a decorator that takes a callable and returns a tool.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
tool_name: The name that will be assigned to the tool.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
A function that takes a callable or `Runnable` and returns a tool.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def _tool_factory(
|
|
283
|
+
dec_func: Callable[..., Any] | Runnable[Any, Any],
|
|
284
|
+
) -> BaseTool:
|
|
285
|
+
tool_description = description
|
|
286
|
+
if isinstance(dec_func, Runnable):
|
|
287
|
+
runnable = dec_func
|
|
288
|
+
|
|
289
|
+
if runnable.get_input_jsonschema().get("type") != "object":
|
|
290
|
+
msg = "Runnable must have an object schema."
|
|
291
|
+
raise ValueError(msg)
|
|
292
|
+
|
|
293
|
+
async def ainvoke_wrapper(
|
|
294
|
+
callbacks: Callbacks | None = None, **kwargs: Any
|
|
295
|
+
) -> Any:
|
|
296
|
+
return await runnable.ainvoke(kwargs, {"callbacks": callbacks})
|
|
297
|
+
|
|
298
|
+
def invoke_wrapper(
|
|
299
|
+
callbacks: Callbacks | None = None, **kwargs: Any
|
|
300
|
+
) -> Any:
|
|
301
|
+
return runnable.invoke(kwargs, {"callbacks": callbacks})
|
|
302
|
+
|
|
303
|
+
coroutine = ainvoke_wrapper
|
|
304
|
+
func = invoke_wrapper
|
|
305
|
+
schema: ArgsSchema | None = runnable.input_schema
|
|
306
|
+
tool_description = description or repr(runnable)
|
|
307
|
+
elif inspect.iscoroutinefunction(dec_func):
|
|
308
|
+
coroutine = dec_func
|
|
309
|
+
func = None
|
|
310
|
+
schema = args_schema
|
|
311
|
+
else:
|
|
312
|
+
coroutine = None
|
|
313
|
+
func = dec_func
|
|
314
|
+
schema = args_schema
|
|
315
|
+
|
|
316
|
+
if infer_schema or args_schema is not None:
|
|
317
|
+
return StructuredTool.from_function(
|
|
318
|
+
func,
|
|
319
|
+
coroutine,
|
|
320
|
+
name=tool_name,
|
|
321
|
+
description=tool_description,
|
|
322
|
+
return_direct=return_direct,
|
|
323
|
+
args_schema=schema,
|
|
324
|
+
infer_schema=infer_schema,
|
|
325
|
+
response_format=response_format,
|
|
326
|
+
parse_docstring=parse_docstring,
|
|
327
|
+
error_on_invalid_docstring=error_on_invalid_docstring,
|
|
328
|
+
extras=extras,
|
|
329
|
+
)
|
|
330
|
+
# If someone doesn't want a schema applied, we must treat it as
|
|
331
|
+
# a simple string->string function
|
|
332
|
+
tool_description = tool_description or dec_func.__doc__
|
|
333
|
+
if tool_description is None:
|
|
334
|
+
msg = (
|
|
335
|
+
"Function must have either a docstring or description "
|
|
336
|
+
"when infer_schema is False."
|
|
337
|
+
)
|
|
338
|
+
raise ValueError(msg)
|
|
339
|
+
return Tool(
|
|
340
|
+
name=tool_name,
|
|
341
|
+
func=func,
|
|
342
|
+
description=tool_description,
|
|
343
|
+
return_direct=return_direct,
|
|
344
|
+
coroutine=coroutine,
|
|
345
|
+
response_format=response_format,
|
|
346
|
+
extras=extras,
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
return _tool_factory
|
|
350
|
+
|
|
351
|
+
if len(args) != 0:
|
|
352
|
+
# Triggered if a user attempts to use positional arguments that
|
|
353
|
+
# do not exist in the function signature
|
|
354
|
+
# e.g., @tool("name", runnable, "extra_arg")
|
|
355
|
+
# Here, "extra_arg" is not a valid argument
|
|
356
|
+
msg = "Too many arguments for tool decorator. A decorator "
|
|
357
|
+
raise ValueError(msg)
|
|
358
|
+
|
|
359
|
+
if runnable is not None:
|
|
360
|
+
# tool is used as a function
|
|
361
|
+
# for instance tool_from_runnable = tool("name", runnable)
|
|
362
|
+
if not name_or_callable:
|
|
363
|
+
msg = "Runnable without name for tool constructor"
|
|
364
|
+
raise ValueError(msg)
|
|
365
|
+
if not isinstance(name_or_callable, str):
|
|
366
|
+
msg = "Name must be a string for tool constructor"
|
|
367
|
+
raise ValueError(msg)
|
|
368
|
+
return _create_tool_factory(name_or_callable)(runnable)
|
|
369
|
+
if name_or_callable is not None:
|
|
370
|
+
if callable(name_or_callable) and hasattr(name_or_callable, "__name__"):
|
|
371
|
+
# Used as a decorator without parameters
|
|
372
|
+
# @tool
|
|
373
|
+
# def my_tool():
|
|
374
|
+
# pass
|
|
375
|
+
return _create_tool_factory(name_or_callable.__name__)(name_or_callable)
|
|
376
|
+
if isinstance(name_or_callable, str):
|
|
377
|
+
# Used with a new name for the tool
|
|
378
|
+
# @tool("search")
|
|
379
|
+
# def my_tool():
|
|
380
|
+
# pass
|
|
381
|
+
#
|
|
382
|
+
# or
|
|
383
|
+
#
|
|
384
|
+
# @tool("search", parse_docstring=True)
|
|
385
|
+
# def my_tool():
|
|
386
|
+
# pass
|
|
387
|
+
return _create_tool_factory(name_or_callable)
|
|
388
|
+
msg = (
|
|
389
|
+
f"The first argument must be a string or a callable with a __name__ "
|
|
390
|
+
f"for tool decorator. Got {type(name_or_callable)}"
|
|
391
|
+
)
|
|
392
|
+
raise ValueError(msg)
|
|
393
|
+
|
|
394
|
+
# Tool is used as a decorator with parameters specified
|
|
395
|
+
# @tool(parse_docstring=True)
|
|
396
|
+
# def my_tool():
|
|
397
|
+
# pass
|
|
398
|
+
def _partial(func: Callable[..., Any] | Runnable[Any, Any]) -> BaseTool:
|
|
399
|
+
"""Partial function that takes a `Callable` and returns a tool."""
|
|
400
|
+
name_ = func.get_name() if isinstance(func, Runnable) else func.__name__
|
|
401
|
+
tool_factory = _create_tool_factory(name_)
|
|
402
|
+
return tool_factory(func)
|
|
403
|
+
|
|
404
|
+
return _partial
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _get_description_from_runnable(runnable: Runnable[Any, Any]) -> str:
|
|
408
|
+
"""Generate a placeholder description of a `Runnable`."""
|
|
409
|
+
input_schema = runnable.get_input_jsonschema()
|
|
410
|
+
return f"Takes {input_schema}."
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _get_schema_from_runnable_and_arg_types(
|
|
414
|
+
runnable: Runnable[Any, Any],
|
|
415
|
+
name: str,
|
|
416
|
+
arg_types: dict[str, type] | None = None,
|
|
417
|
+
) -> type[BaseModel]:
|
|
418
|
+
"""Infer `args_schema` for tool."""
|
|
419
|
+
if arg_types is None:
|
|
420
|
+
try:
|
|
421
|
+
arg_types = get_type_hints(runnable.InputType)
|
|
422
|
+
except TypeError as e:
|
|
423
|
+
msg = (
|
|
424
|
+
"Tool input must be str or dict. If dict, dict arguments must be "
|
|
425
|
+
"typed. Either annotate types (e.g., with TypedDict) or pass "
|
|
426
|
+
f"arg_types into `.as_tool` to specify. {e}"
|
|
427
|
+
)
|
|
428
|
+
raise TypeError(msg) from e
|
|
429
|
+
fields = {key: (key_type, Field(...)) for key, key_type in arg_types.items()}
|
|
430
|
+
return cast("type[BaseModel]", create_model(name, **fields)) # type: ignore[call-overload]
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def convert_runnable_to_tool(
|
|
434
|
+
runnable: Runnable[Any, Any],
|
|
435
|
+
args_schema: TypeBaseModel | None = None,
|
|
436
|
+
*,
|
|
437
|
+
name: str | None = None,
|
|
438
|
+
description: str | None = None,
|
|
439
|
+
arg_types: dict[str, type] | None = None,
|
|
440
|
+
) -> BaseTool:
|
|
441
|
+
"""Convert a `Runnable` into a `BaseTool`.
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
runnable: The `Runnable` to convert.
|
|
445
|
+
args_schema: The schema for the tool's input arguments.
|
|
446
|
+
name: The name of the tool.
|
|
447
|
+
description: The description of the tool.
|
|
448
|
+
arg_types: The types of the arguments.
|
|
449
|
+
|
|
450
|
+
Returns:
|
|
451
|
+
The tool.
|
|
452
|
+
"""
|
|
453
|
+
if args_schema:
|
|
454
|
+
runnable = runnable.with_types(input_type=args_schema)
|
|
455
|
+
description = description or _get_description_from_runnable(runnable)
|
|
456
|
+
name = name or runnable.get_name()
|
|
457
|
+
|
|
458
|
+
schema = runnable.get_input_jsonschema()
|
|
459
|
+
if schema.get("type") == "string":
|
|
460
|
+
return Tool(
|
|
461
|
+
name=name,
|
|
462
|
+
func=runnable.invoke,
|
|
463
|
+
coroutine=runnable.ainvoke,
|
|
464
|
+
description=description,
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
async def ainvoke_wrapper(callbacks: Callbacks | None = None, **kwargs: Any) -> Any:
|
|
468
|
+
return await runnable.ainvoke(kwargs, config={"callbacks": callbacks})
|
|
469
|
+
|
|
470
|
+
def invoke_wrapper(callbacks: Callbacks | None = None, **kwargs: Any) -> Any:
|
|
471
|
+
return runnable.invoke(kwargs, config={"callbacks": callbacks})
|
|
472
|
+
|
|
473
|
+
input_schema_cls = runnable.input_schema
|
|
474
|
+
# Detect `RootModel` input schemas so we don't use them directly as the tool
|
|
475
|
+
# args schema.
|
|
476
|
+
is_root_model = isinstance(input_schema_cls, type) and issubclass(
|
|
477
|
+
input_schema_cls, RootModel
|
|
478
|
+
)
|
|
479
|
+
if (
|
|
480
|
+
arg_types is None
|
|
481
|
+
and schema.get("type") == "object"
|
|
482
|
+
and schema.get("properties")
|
|
483
|
+
and not is_root_model
|
|
484
|
+
):
|
|
485
|
+
args_schema = input_schema_cls
|
|
486
|
+
else:
|
|
487
|
+
args_schema = _get_schema_from_runnable_and_arg_types(
|
|
488
|
+
runnable, name, arg_types=arg_types
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
return StructuredTool.from_function(
|
|
492
|
+
name=name,
|
|
493
|
+
func=invoke_wrapper,
|
|
494
|
+
coroutine=ainvoke_wrapper,
|
|
495
|
+
description=description,
|
|
496
|
+
args_schema=args_schema,
|
|
497
|
+
)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Utilities to render tools."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from inspect import signature
|
|
7
|
+
|
|
8
|
+
from coco_core.tools.base import BaseTool
|
|
9
|
+
|
|
10
|
+
ToolsRenderer = Callable[[list[BaseTool]], str]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def render_text_description(tools: list[BaseTool]) -> str:
|
|
14
|
+
"""Render the tool name and description in plain text.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
tools: The tools to render.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The rendered text.
|
|
21
|
+
|
|
22
|
+
Output will be in the format of:
|
|
23
|
+
|
|
24
|
+
```txt
|
|
25
|
+
search: This tool is used for search
|
|
26
|
+
calculator: This tool is used for math
|
|
27
|
+
```
|
|
28
|
+
"""
|
|
29
|
+
descriptions = []
|
|
30
|
+
for tool in tools:
|
|
31
|
+
if hasattr(tool, "func") and tool.func:
|
|
32
|
+
sig = signature(tool.func)
|
|
33
|
+
description = f"{tool.name}{sig} - {tool.description}"
|
|
34
|
+
else:
|
|
35
|
+
description = f"{tool.name} - {tool.description}"
|
|
36
|
+
|
|
37
|
+
descriptions.append(description)
|
|
38
|
+
return "\n".join(descriptions)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def render_text_description_and_args(tools: list[BaseTool]) -> str:
|
|
42
|
+
"""Render the tool name, description, and args in plain text.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
tools: The tools to render.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
The rendered text.
|
|
49
|
+
|
|
50
|
+
Output will be in the format of:
|
|
51
|
+
|
|
52
|
+
```txt
|
|
53
|
+
search: This tool is used for search, args: {"query": {"type": "string"}}
|
|
54
|
+
calculator: This tool is used for math, \
|
|
55
|
+
args: {"expression": {"type": "string"}}
|
|
56
|
+
```
|
|
57
|
+
"""
|
|
58
|
+
tool_strings = []
|
|
59
|
+
for tool in tools:
|
|
60
|
+
args_schema = str(tool.args)
|
|
61
|
+
if hasattr(tool, "func") and tool.func:
|
|
62
|
+
sig = signature(tool.func)
|
|
63
|
+
description = f"{tool.name}{sig} - {tool.description}"
|
|
64
|
+
else:
|
|
65
|
+
description = f"{tool.name} - {tool.description}"
|
|
66
|
+
tool_strings.append(f"{description}, args: {args_schema}")
|
|
67
|
+
return "\n".join(tool_strings)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Retriever tool."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
# Cannot move Callbacks and Document to TYPE_CHECKING as StructuredTool's
|
|
10
|
+
# func/coroutine parameter annotations are evaluated at runtime.
|
|
11
|
+
from coco_core.callbacks import Callbacks # noqa: TC001
|
|
12
|
+
from coco_core.documents import Document # noqa: TC001
|
|
13
|
+
from coco_core.prompts import (
|
|
14
|
+
BasePromptTemplate,
|
|
15
|
+
PromptTemplate,
|
|
16
|
+
aformat_document,
|
|
17
|
+
format_document,
|
|
18
|
+
)
|
|
19
|
+
from coco_core.tools.structured import StructuredTool
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from coco_core.retrievers import BaseRetriever
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RetrieverInput(BaseModel):
|
|
26
|
+
"""Input to the retriever."""
|
|
27
|
+
|
|
28
|
+
query: str = Field(description="query to look up in retriever")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def create_retriever_tool(
|
|
32
|
+
retriever: BaseRetriever,
|
|
33
|
+
name: str,
|
|
34
|
+
description: str,
|
|
35
|
+
*,
|
|
36
|
+
document_prompt: BasePromptTemplate[str] | None = None,
|
|
37
|
+
document_separator: str = "\n\n",
|
|
38
|
+
response_format: Literal["content", "content_and_artifact"] = "content",
|
|
39
|
+
) -> StructuredTool:
|
|
40
|
+
r"""Create a tool to do retrieval of documents.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
retriever: The retriever to use for the retrieval
|
|
44
|
+
name: The name for the tool.
|
|
45
|
+
|
|
46
|
+
This will be passed to the language model, so should be unique and somewhat
|
|
47
|
+
descriptive.
|
|
48
|
+
description: The description for the tool.
|
|
49
|
+
|
|
50
|
+
This will be passed to the language model, so should be descriptive.
|
|
51
|
+
document_prompt: The prompt to use for the document.
|
|
52
|
+
document_separator: The separator to use between documents.
|
|
53
|
+
response_format: The tool response format.
|
|
54
|
+
|
|
55
|
+
If `'content'` then the output of the tool is interpreted as the contents of
|
|
56
|
+
a `ToolMessage`. If `'content_and_artifact'` then the output is expected to
|
|
57
|
+
be a two-tuple corresponding to the `(content, artifact)` of a `ToolMessage`
|
|
58
|
+
(artifact being a list of documents in this case).
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Tool class to pass to an agent.
|
|
62
|
+
"""
|
|
63
|
+
document_prompt_ = document_prompt or PromptTemplate.from_template("{page_content}")
|
|
64
|
+
|
|
65
|
+
def func(
|
|
66
|
+
query: str, callbacks: Callbacks = None
|
|
67
|
+
) -> str | tuple[str, list[Document]]:
|
|
68
|
+
docs = retriever.invoke(query, config={"callbacks": callbacks})
|
|
69
|
+
content = document_separator.join(
|
|
70
|
+
format_document(doc, document_prompt_) for doc in docs
|
|
71
|
+
)
|
|
72
|
+
if response_format == "content_and_artifact":
|
|
73
|
+
return (content, docs)
|
|
74
|
+
return content
|
|
75
|
+
|
|
76
|
+
async def afunc(
|
|
77
|
+
query: str, callbacks: Callbacks = None
|
|
78
|
+
) -> str | tuple[str, list[Document]]:
|
|
79
|
+
docs = await retriever.ainvoke(query, config={"callbacks": callbacks})
|
|
80
|
+
content = document_separator.join(
|
|
81
|
+
[await aformat_document(doc, document_prompt_) for doc in docs]
|
|
82
|
+
)
|
|
83
|
+
if response_format == "content_and_artifact":
|
|
84
|
+
return (content, docs)
|
|
85
|
+
return content
|
|
86
|
+
|
|
87
|
+
return StructuredTool(
|
|
88
|
+
name=name,
|
|
89
|
+
description=description,
|
|
90
|
+
func=func,
|
|
91
|
+
coroutine=afunc,
|
|
92
|
+
args_schema=RetrieverInput,
|
|
93
|
+
response_format=response_format,
|
|
94
|
+
)
|