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,399 @@
|
|
|
1
|
+
"""`BasePrompt` schema definition."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from string import Formatter
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, create_model
|
|
11
|
+
from typing_extensions import override
|
|
12
|
+
|
|
13
|
+
from coco_core.prompt_values import PromptValue, StringPromptValue
|
|
14
|
+
from coco_core.prompts.base import BasePromptTemplate
|
|
15
|
+
from coco_core.utils import get_colored_text, mustache
|
|
16
|
+
from coco_core.utils.formatting import formatter
|
|
17
|
+
from coco_core.utils.interactive_env import is_interactive_env
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Callable, Sequence
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from jinja2 import meta
|
|
24
|
+
from jinja2.sandbox import SandboxedEnvironment
|
|
25
|
+
|
|
26
|
+
_HAS_JINJA2 = True
|
|
27
|
+
except ImportError:
|
|
28
|
+
_HAS_JINJA2 = False
|
|
29
|
+
|
|
30
|
+
PromptTemplateFormat = Literal["f-string", "mustache", "jinja2"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def jinja2_formatter(template: str, /, **kwargs: Any) -> str:
|
|
34
|
+
"""Format a template using jinja2.
|
|
35
|
+
|
|
36
|
+
!!! warning "Security"
|
|
37
|
+
|
|
38
|
+
As of Coco 0.0.329, this method uses Jinja2's `SandboxedEnvironment` by
|
|
39
|
+
default. However, this sandboxing should be treated as a best-effort approach
|
|
40
|
+
rather than a guarantee of security.
|
|
41
|
+
|
|
42
|
+
Do not accept jinja2 templates from untrusted sources as they may lead
|
|
43
|
+
to arbitrary Python code execution.
|
|
44
|
+
|
|
45
|
+
[More information.](https://jinja.palletsprojects.com/en/3.1.x/sandbox/)
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
template: The template string.
|
|
49
|
+
**kwargs: The variables to format the template with.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
The formatted string.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
ImportError: If jinja2 is not installed.
|
|
56
|
+
"""
|
|
57
|
+
if not _HAS_JINJA2:
|
|
58
|
+
msg = (
|
|
59
|
+
"jinja2 not installed, which is needed to use the jinja2_formatter. "
|
|
60
|
+
"Please install it with `pip install jinja2`."
|
|
61
|
+
"Please be cautious when using jinja2 templates. "
|
|
62
|
+
"Do not expand jinja2 templates using unverified or user-controlled "
|
|
63
|
+
"inputs as that can result in arbitrary Python code execution."
|
|
64
|
+
)
|
|
65
|
+
raise ImportError(msg)
|
|
66
|
+
|
|
67
|
+
# Use Jinja2's SandboxedEnvironment which blocks access to dunder attributes
|
|
68
|
+
# (e.g., __class__, __globals__) to prevent sandbox escapes.
|
|
69
|
+
# Note: regular attribute access (e.g., {{obj.attr}}) and method calls are
|
|
70
|
+
# still allowed. This is a best-effort measure — do not use with untrusted
|
|
71
|
+
# templates.
|
|
72
|
+
return SandboxedEnvironment().from_string(template).render(**kwargs)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def validate_jinja2(template: str, input_variables: list[str]) -> None:
|
|
76
|
+
"""Validate that the input variables are valid for the template.
|
|
77
|
+
|
|
78
|
+
Issues a warning if missing or extra variables are found.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
template: The template string.
|
|
82
|
+
input_variables: The input variables.
|
|
83
|
+
"""
|
|
84
|
+
input_variables_set = set(input_variables)
|
|
85
|
+
valid_variables = _get_jinja2_variables_from_template(template)
|
|
86
|
+
missing_variables = valid_variables - input_variables_set
|
|
87
|
+
extra_variables = input_variables_set - valid_variables
|
|
88
|
+
|
|
89
|
+
warning_message = ""
|
|
90
|
+
if missing_variables:
|
|
91
|
+
warning_message += f"Missing variables: {missing_variables} "
|
|
92
|
+
|
|
93
|
+
if extra_variables:
|
|
94
|
+
warning_message += f"Extra variables: {extra_variables}"
|
|
95
|
+
|
|
96
|
+
if warning_message:
|
|
97
|
+
warnings.warn(warning_message.strip(), stacklevel=7)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _get_jinja2_variables_from_template(template: str) -> set[str]:
|
|
101
|
+
if not _HAS_JINJA2:
|
|
102
|
+
msg = (
|
|
103
|
+
"jinja2 not installed, which is needed to use the jinja2_formatter. "
|
|
104
|
+
"Please install it with `pip install jinja2`."
|
|
105
|
+
)
|
|
106
|
+
raise ImportError(msg)
|
|
107
|
+
env = SandboxedEnvironment()
|
|
108
|
+
ast = env.parse(template)
|
|
109
|
+
return meta.find_undeclared_variables(ast)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def mustache_formatter(template: str, /, **kwargs: Any) -> str:
|
|
113
|
+
"""Format a template using mustache.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
template: The template string.
|
|
117
|
+
**kwargs: The variables to format the template with.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
The formatted string.
|
|
121
|
+
"""
|
|
122
|
+
return mustache.render(template, kwargs)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def mustache_template_vars(
|
|
126
|
+
template: str,
|
|
127
|
+
) -> set[str]:
|
|
128
|
+
"""Get the top-level variables from a mustache template.
|
|
129
|
+
|
|
130
|
+
For nested variables like `{{person.name}}`, only the top-level key (`person`) is
|
|
131
|
+
returned.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
template: The template string.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
The top-level variables from the template.
|
|
138
|
+
"""
|
|
139
|
+
variables: set[str] = set()
|
|
140
|
+
section_depth = 0
|
|
141
|
+
for type_, key in mustache.tokenize(template):
|
|
142
|
+
if type_ == "end":
|
|
143
|
+
section_depth -= 1
|
|
144
|
+
elif (
|
|
145
|
+
type_ in {"variable", "section", "inverted section", "no escape"}
|
|
146
|
+
and key != "."
|
|
147
|
+
and section_depth == 0
|
|
148
|
+
):
|
|
149
|
+
variables.add(key.split(".")[0])
|
|
150
|
+
if type_ in {"section", "inverted section"}:
|
|
151
|
+
section_depth += 1
|
|
152
|
+
return variables
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
Defs = dict[str, "Defs"]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def mustache_schema(template: str) -> type[BaseModel]:
|
|
159
|
+
"""Get the variables from a mustache template.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
template: The template string.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
The variables from the template as a Pydantic model.
|
|
166
|
+
"""
|
|
167
|
+
fields = {}
|
|
168
|
+
prefix: tuple[str, ...] = ()
|
|
169
|
+
section_stack: list[tuple[str, ...]] = []
|
|
170
|
+
for type_, key in mustache.tokenize(template):
|
|
171
|
+
if key == ".":
|
|
172
|
+
continue
|
|
173
|
+
if type_ == "end":
|
|
174
|
+
if section_stack:
|
|
175
|
+
prefix = section_stack.pop()
|
|
176
|
+
elif type_ in {"section", "inverted section"}:
|
|
177
|
+
section_stack.append(prefix)
|
|
178
|
+
prefix += tuple(key.split("."))
|
|
179
|
+
fields[prefix] = False
|
|
180
|
+
elif type_ in {"variable", "no escape"}:
|
|
181
|
+
fields[prefix + tuple(key.split("."))] = True
|
|
182
|
+
|
|
183
|
+
for fkey, fval in fields.items():
|
|
184
|
+
fields[fkey] = fval and not any(
|
|
185
|
+
is_subsequence(fkey, k) for k in fields if k != fkey
|
|
186
|
+
)
|
|
187
|
+
defs: Defs = {} # None means leaf node
|
|
188
|
+
while fields:
|
|
189
|
+
field, is_leaf = fields.popitem()
|
|
190
|
+
current = defs
|
|
191
|
+
for part in field[:-1]:
|
|
192
|
+
current = current.setdefault(part, {})
|
|
193
|
+
current.setdefault(field[-1], "" if is_leaf else {}) # type: ignore[arg-type]
|
|
194
|
+
return _create_model_recursive("PromptInput", defs)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _create_model_recursive(name: str, defs: Defs) -> type[BaseModel]:
|
|
198
|
+
return cast(
|
|
199
|
+
"type[BaseModel]",
|
|
200
|
+
create_model( # type: ignore[call-overload]
|
|
201
|
+
name,
|
|
202
|
+
**{
|
|
203
|
+
k: (_create_model_recursive(k, v), None) if v else (type(v), None)
|
|
204
|
+
for k, v in defs.items()
|
|
205
|
+
},
|
|
206
|
+
),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
DEFAULT_FORMATTER_MAPPING: dict[str, Callable[..., str]] = {
|
|
211
|
+
"f-string": formatter.format,
|
|
212
|
+
"mustache": mustache_formatter,
|
|
213
|
+
"jinja2": jinja2_formatter,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
DEFAULT_VALIDATOR_MAPPING: dict[str, Callable[[str, list[str]], None]] = {
|
|
217
|
+
"f-string": formatter.validate_input_variables,
|
|
218
|
+
"jinja2": validate_jinja2,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _parse_f_string_fields(template: str) -> list[tuple[str, str | None]]:
|
|
223
|
+
fields: list[tuple[str, str | None]] = []
|
|
224
|
+
for _, field_name, format_spec, _ in Formatter().parse(template):
|
|
225
|
+
if field_name is not None:
|
|
226
|
+
fields.append((field_name, format_spec))
|
|
227
|
+
return fields
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def validate_f_string_template(template: str) -> list[str]:
|
|
231
|
+
"""Validate an f-string template and return its input variables."""
|
|
232
|
+
input_variables = set()
|
|
233
|
+
for var, format_spec in _parse_f_string_fields(template):
|
|
234
|
+
if "." in var or "[" in var or "]" in var:
|
|
235
|
+
msg = (
|
|
236
|
+
f"Invalid variable name {var!r} in f-string template. "
|
|
237
|
+
f"Variable names cannot contain attribute "
|
|
238
|
+
f"access (.) or indexing ([])."
|
|
239
|
+
)
|
|
240
|
+
raise ValueError(msg)
|
|
241
|
+
|
|
242
|
+
if var.isdigit():
|
|
243
|
+
msg = (
|
|
244
|
+
f"Invalid variable name {var!r} in f-string template. "
|
|
245
|
+
f"Variable names cannot be all digits as they are interpreted "
|
|
246
|
+
f"as positional arguments."
|
|
247
|
+
)
|
|
248
|
+
raise ValueError(msg)
|
|
249
|
+
|
|
250
|
+
if format_spec and ("{" in format_spec or "}" in format_spec):
|
|
251
|
+
msg = (
|
|
252
|
+
"Invalid format specifier in f-string template. "
|
|
253
|
+
"Nested replacement fields are not allowed."
|
|
254
|
+
)
|
|
255
|
+
raise ValueError(msg)
|
|
256
|
+
|
|
257
|
+
input_variables.add(var)
|
|
258
|
+
|
|
259
|
+
return sorted(input_variables)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def check_valid_template(
|
|
263
|
+
template: str, template_format: str, input_variables: list[str]
|
|
264
|
+
) -> None:
|
|
265
|
+
"""Check that template string is valid.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
template: The template string.
|
|
269
|
+
template_format: The template format.
|
|
270
|
+
|
|
271
|
+
Should be one of `'f-string'` or `'jinja2'`.
|
|
272
|
+
input_variables: The input variables.
|
|
273
|
+
|
|
274
|
+
Raises:
|
|
275
|
+
ValueError: If the template format is not supported.
|
|
276
|
+
ValueError: If the prompt schema is invalid.
|
|
277
|
+
"""
|
|
278
|
+
try:
|
|
279
|
+
validator_func = DEFAULT_VALIDATOR_MAPPING[template_format]
|
|
280
|
+
except KeyError as exc:
|
|
281
|
+
msg = (
|
|
282
|
+
f"Invalid template format {template_format!r}, should be one of"
|
|
283
|
+
f" {list(DEFAULT_FORMATTER_MAPPING)}."
|
|
284
|
+
)
|
|
285
|
+
raise ValueError(msg) from exc
|
|
286
|
+
if template_format == "f-string":
|
|
287
|
+
validate_f_string_template(template)
|
|
288
|
+
try:
|
|
289
|
+
validator_func(template, input_variables)
|
|
290
|
+
except (KeyError, IndexError) as exc:
|
|
291
|
+
msg = (
|
|
292
|
+
"Invalid prompt schema; check for mismatched or missing input parameters"
|
|
293
|
+
f" from {input_variables}."
|
|
294
|
+
)
|
|
295
|
+
raise ValueError(msg) from exc
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def get_template_variables(template: str, template_format: str) -> list[str]:
|
|
299
|
+
"""Get the variables from the template.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
template: The template string.
|
|
303
|
+
template_format: The template format.
|
|
304
|
+
|
|
305
|
+
Should be one of `'f-string'`, `'mustache'` or `'jinja2'`.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
The variables from the template.
|
|
309
|
+
|
|
310
|
+
Raises:
|
|
311
|
+
ValueError: If the template format is not supported.
|
|
312
|
+
"""
|
|
313
|
+
input_variables: list[str] | set[str]
|
|
314
|
+
if template_format == "jinja2":
|
|
315
|
+
# Get the variables for the template
|
|
316
|
+
input_variables = sorted(_get_jinja2_variables_from_template(template))
|
|
317
|
+
elif template_format == "f-string":
|
|
318
|
+
input_variables = validate_f_string_template(template)
|
|
319
|
+
elif template_format == "mustache":
|
|
320
|
+
input_variables = mustache_template_vars(template)
|
|
321
|
+
else:
|
|
322
|
+
msg = f"Unsupported template format: {template_format}"
|
|
323
|
+
raise ValueError(msg)
|
|
324
|
+
|
|
325
|
+
return sorted(input_variables)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class StringPromptTemplate(BasePromptTemplate[str], ABC):
|
|
329
|
+
"""String prompt that exposes the format method, returning a prompt."""
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def get_lc_namespace(cls) -> list[str]:
|
|
333
|
+
"""Get the namespace of the Coco object.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
`["coco", "prompts", "base"]`
|
|
337
|
+
"""
|
|
338
|
+
return ["coco", "prompts", "base"]
|
|
339
|
+
|
|
340
|
+
def format_prompt(self, **kwargs: Any) -> PromptValue:
|
|
341
|
+
"""Format the prompt with the inputs.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
**kwargs: Any arguments to be passed to the prompt template.
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
A formatted string.
|
|
348
|
+
"""
|
|
349
|
+
return StringPromptValue(text=self.format(**kwargs))
|
|
350
|
+
|
|
351
|
+
async def aformat_prompt(self, **kwargs: Any) -> PromptValue:
|
|
352
|
+
"""Async format the prompt with the inputs.
|
|
353
|
+
|
|
354
|
+
Args:
|
|
355
|
+
**kwargs: Any arguments to be passed to the prompt template.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
A formatted string.
|
|
359
|
+
"""
|
|
360
|
+
return StringPromptValue(text=await self.aformat(**kwargs))
|
|
361
|
+
|
|
362
|
+
@override
|
|
363
|
+
@abstractmethod
|
|
364
|
+
def format(self, **kwargs: Any) -> str: ...
|
|
365
|
+
|
|
366
|
+
def pretty_repr(
|
|
367
|
+
self,
|
|
368
|
+
html: bool = False, # noqa: FBT001,FBT002
|
|
369
|
+
) -> str:
|
|
370
|
+
"""Get a pretty representation of the prompt.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
html: Whether to return an HTML-formatted string.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
A pretty representation of the prompt.
|
|
377
|
+
"""
|
|
378
|
+
# TODO: handle partials
|
|
379
|
+
dummy_vars = {
|
|
380
|
+
input_var: "{" + f"{input_var}" + "}" for input_var in self.input_variables
|
|
381
|
+
}
|
|
382
|
+
if html:
|
|
383
|
+
dummy_vars = {
|
|
384
|
+
k: get_colored_text(v, "yellow") for k, v in dummy_vars.items()
|
|
385
|
+
}
|
|
386
|
+
return self.format(**dummy_vars)
|
|
387
|
+
|
|
388
|
+
def pretty_print(self) -> None:
|
|
389
|
+
"""Print a pretty representation of the prompt."""
|
|
390
|
+
print(self.pretty_repr(html=is_interactive_env())) # noqa: T201
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def is_subsequence(child: Sequence[Any], parent: Sequence[Any]) -> bool:
|
|
394
|
+
"""Return `True` if child is subsequence of parent."""
|
|
395
|
+
if len(child) == 0 or len(parent) == 0:
|
|
396
|
+
return False
|
|
397
|
+
if len(parent) < len(child):
|
|
398
|
+
return False
|
|
399
|
+
return all(child[i] == parent[i] for i in range(len(child)))
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Structured prompt template for a language model."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import (
|
|
4
|
+
AsyncIterator,
|
|
5
|
+
Awaitable,
|
|
6
|
+
Callable,
|
|
7
|
+
Iterator,
|
|
8
|
+
Mapping,
|
|
9
|
+
Sequence,
|
|
10
|
+
)
|
|
11
|
+
from typing import (
|
|
12
|
+
Any,
|
|
13
|
+
overload,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, Field
|
|
17
|
+
from typing_extensions import override
|
|
18
|
+
|
|
19
|
+
from coco_core._api.beta_decorator import beta
|
|
20
|
+
from coco_core.language_models.base import BaseLanguageModel
|
|
21
|
+
from coco_core.prompt_values import PromptValue
|
|
22
|
+
from coco_core.prompts.chat import (
|
|
23
|
+
ChatPromptTemplate,
|
|
24
|
+
MessageLikeRepresentation,
|
|
25
|
+
)
|
|
26
|
+
from coco_core.prompts.string import PromptTemplateFormat
|
|
27
|
+
from coco_core.runnables.base import (
|
|
28
|
+
Other,
|
|
29
|
+
Runnable,
|
|
30
|
+
RunnableSequence,
|
|
31
|
+
RunnableSerializable,
|
|
32
|
+
)
|
|
33
|
+
from coco_core.utils import get_pydantic_field_names
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@beta()
|
|
37
|
+
class StructuredPrompt(ChatPromptTemplate):
|
|
38
|
+
"""Structured prompt template for a language model."""
|
|
39
|
+
|
|
40
|
+
schema_: dict[str, Any] | type
|
|
41
|
+
"""Schema for the structured prompt."""
|
|
42
|
+
|
|
43
|
+
structured_output_kwargs: dict[str, Any] = Field(default_factory=dict)
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
messages: Sequence[MessageLikeRepresentation],
|
|
48
|
+
schema_: dict[str, Any] | type[BaseModel] | None = None,
|
|
49
|
+
*,
|
|
50
|
+
structured_output_kwargs: dict[str, Any] | None = None,
|
|
51
|
+
template_format: PromptTemplateFormat = "f-string",
|
|
52
|
+
**kwargs: Any,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Create a structured prompt template.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
messages: Sequence of messages.
|
|
58
|
+
schema_: Schema for the structured prompt.
|
|
59
|
+
structured_output_kwargs: Additional kwargs for structured output.
|
|
60
|
+
template_format: Template format for the prompt.
|
|
61
|
+
|
|
62
|
+
Raises:
|
|
63
|
+
ValueError: If schema is not provided.
|
|
64
|
+
"""
|
|
65
|
+
schema_ = schema_ or kwargs.pop("schema", None)
|
|
66
|
+
if not schema_:
|
|
67
|
+
err_msg = (
|
|
68
|
+
"Must pass in a non-empty structured output schema. Received: "
|
|
69
|
+
f"{schema_}"
|
|
70
|
+
)
|
|
71
|
+
raise ValueError(err_msg)
|
|
72
|
+
# Avoid mutating a caller-provided dict when merging extra kwargs.
|
|
73
|
+
structured_output_kwargs = dict(structured_output_kwargs or {})
|
|
74
|
+
for k in set(kwargs).difference(get_pydantic_field_names(self.__class__)):
|
|
75
|
+
structured_output_kwargs[k] = kwargs.pop(k)
|
|
76
|
+
super().__init__(
|
|
77
|
+
messages=messages,
|
|
78
|
+
schema_=schema_,
|
|
79
|
+
structured_output_kwargs=structured_output_kwargs,
|
|
80
|
+
template_format=template_format,
|
|
81
|
+
**kwargs,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def get_lc_namespace(cls) -> list[str]:
|
|
86
|
+
"""Get the namespace of the Coco object.
|
|
87
|
+
|
|
88
|
+
For example, if the class is `coco.llms.openai.OpenAI`, then the namespace
|
|
89
|
+
is `["coco", "llms", "openai"]`
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
The namespace of the Coco object.
|
|
93
|
+
"""
|
|
94
|
+
return cls.__module__.split(".")
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def from_messages_and_schema(
|
|
98
|
+
cls,
|
|
99
|
+
messages: Sequence[MessageLikeRepresentation],
|
|
100
|
+
schema: dict[str, Any] | type,
|
|
101
|
+
**kwargs: Any,
|
|
102
|
+
) -> ChatPromptTemplate:
|
|
103
|
+
"""Create a chat prompt template from a variety of message formats.
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
Instantiation from a list of message templates:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from coco_core.prompts import StructuredPrompt
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class OutputSchema(BaseModel):
|
|
113
|
+
name: str
|
|
114
|
+
value: int
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
template = StructuredPrompt(
|
|
118
|
+
[
|
|
119
|
+
("human", "Hello, how are you?"),
|
|
120
|
+
("ai", "I'm doing well, thanks!"),
|
|
121
|
+
("human", "That's good to hear."),
|
|
122
|
+
],
|
|
123
|
+
OutputSchema,
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
messages: Sequence of message representations.
|
|
129
|
+
|
|
130
|
+
A message can be represented using the following formats:
|
|
131
|
+
|
|
132
|
+
1. `BaseMessagePromptTemplate`
|
|
133
|
+
2. `BaseMessage`
|
|
134
|
+
3. 2-tuple of `(message type, template)`; e.g.,
|
|
135
|
+
`("human", "{user_input}")`
|
|
136
|
+
4. 2-tuple of `(message class, template)`
|
|
137
|
+
5. A string which is shorthand for `("human", template)`; e.g.,
|
|
138
|
+
`"{user_input}"`
|
|
139
|
+
schema: A dictionary representation of function call, or a Pydantic model.
|
|
140
|
+
**kwargs: Any additional kwargs to pass through to
|
|
141
|
+
`ChatModel.with_structured_output(schema, **kwargs)`.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
A structured prompt template
|
|
145
|
+
"""
|
|
146
|
+
return cls(messages, schema, **kwargs)
|
|
147
|
+
|
|
148
|
+
@overload
|
|
149
|
+
def __or__(
|
|
150
|
+
self, other: Mapping[str, Any]
|
|
151
|
+
) -> RunnableSerializable[dict[str, Any], dict[str, Any]]: ...
|
|
152
|
+
|
|
153
|
+
@overload
|
|
154
|
+
def __or__(
|
|
155
|
+
self,
|
|
156
|
+
other: Callable[[PromptValue], Runnable[PromptValue, Other]]
|
|
157
|
+
| Callable[[PromptValue], Awaitable[Runnable[PromptValue, Other]]],
|
|
158
|
+
) -> RunnableSerializable[dict[str, Any], Other]: ...
|
|
159
|
+
|
|
160
|
+
@overload
|
|
161
|
+
def __or__(
|
|
162
|
+
self,
|
|
163
|
+
other: Runnable[PromptValue, Other]
|
|
164
|
+
| Callable[[Iterator[PromptValue]], Iterator[Other]]
|
|
165
|
+
| Callable[[AsyncIterator[PromptValue]], AsyncIterator[Other]]
|
|
166
|
+
| Callable[[PromptValue], Other],
|
|
167
|
+
) -> RunnableSerializable[dict[str, Any], Other]: ...
|
|
168
|
+
|
|
169
|
+
@override
|
|
170
|
+
def __or__(
|
|
171
|
+
self,
|
|
172
|
+
other: Runnable[PromptValue, Other]
|
|
173
|
+
| Callable[[Iterator[PromptValue]], Iterator[Other]]
|
|
174
|
+
| Callable[[AsyncIterator[PromptValue]], AsyncIterator[Other]]
|
|
175
|
+
| Callable[[PromptValue], Other]
|
|
176
|
+
| Mapping[str, Runnable[PromptValue, Any] | Callable[[PromptValue], Any] | Any],
|
|
177
|
+
) -> RunnableSerializable[dict[str, Any], Any]:
|
|
178
|
+
return self.pipe(other)
|
|
179
|
+
|
|
180
|
+
def pipe(
|
|
181
|
+
self,
|
|
182
|
+
*others: Runnable[Any, Other]
|
|
183
|
+
| Callable[[Iterator[Any]], Iterator[Other]]
|
|
184
|
+
| Callable[[AsyncIterator[Any]], AsyncIterator[Other]]
|
|
185
|
+
| Callable[[Any], Other]
|
|
186
|
+
| Mapping[str, Runnable[Any, Other] | Callable[[Any], Other] | Any],
|
|
187
|
+
name: str | None = None,
|
|
188
|
+
) -> RunnableSerializable[dict[str, Any], Other]:
|
|
189
|
+
"""Pipe the structured prompt to a language model.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
others: The language model to pipe the structured prompt to.
|
|
193
|
+
name: The name of the pipeline.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
A `RunnableSequence` object.
|
|
197
|
+
|
|
198
|
+
Raises:
|
|
199
|
+
NotImplementedError: If the first element of `others` is not a language
|
|
200
|
+
model.
|
|
201
|
+
"""
|
|
202
|
+
if (others and isinstance(others[0], BaseLanguageModel)) or hasattr(
|
|
203
|
+
others[0], "with_structured_output"
|
|
204
|
+
):
|
|
205
|
+
return RunnableSequence(
|
|
206
|
+
self,
|
|
207
|
+
others[0].with_structured_output(
|
|
208
|
+
self.schema_, **self.structured_output_kwargs
|
|
209
|
+
),
|
|
210
|
+
*others[1:],
|
|
211
|
+
name=name,
|
|
212
|
+
)
|
|
213
|
+
msg = "Structured prompts need to be piped to a language model."
|
|
214
|
+
raise NotImplementedError(msg)
|
coco_core/py.typed
ADDED
|
File without changes
|