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,101 @@
|
|
|
1
|
+
"""`OutputParser` classes parse the output of an LLM call into structured data.
|
|
2
|
+
|
|
3
|
+
!!! tip "Structured output"
|
|
4
|
+
|
|
5
|
+
Output parsers emerged as an early solution to the challenge of obtaining structured
|
|
6
|
+
output from LLMs.
|
|
7
|
+
|
|
8
|
+
Today, most LLMs support [structured output](https://docs.langchain.com/oss/python/langchain/models#structured-outputs)
|
|
9
|
+
natively. In such cases, using output parsers may be unnecessary, and you should
|
|
10
|
+
leverage the model's built-in capabilities for structured output. Refer to the
|
|
11
|
+
[documentation of your chosen model](https://docs.langchain.com/oss/python/integrations/providers/overview)
|
|
12
|
+
for guidance on how to achieve structured output directly.
|
|
13
|
+
|
|
14
|
+
Output parsers remain valuable when working with models that do not support
|
|
15
|
+
structured output natively, or when you require additional processing or validation
|
|
16
|
+
of the model's output beyond its inherent capabilities.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
from coco_core._import_utils import import_attr
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from coco_core.output_parsers.base import (
|
|
25
|
+
BaseGenerationOutputParser,
|
|
26
|
+
BaseLLMOutputParser,
|
|
27
|
+
BaseOutputParser,
|
|
28
|
+
)
|
|
29
|
+
from coco_core.output_parsers.json import (
|
|
30
|
+
JsonOutputParser,
|
|
31
|
+
SimpleJsonOutputParser,
|
|
32
|
+
)
|
|
33
|
+
from coco_core.output_parsers.list import (
|
|
34
|
+
CommaSeparatedListOutputParser,
|
|
35
|
+
ListOutputParser,
|
|
36
|
+
MarkdownListOutputParser,
|
|
37
|
+
NumberedListOutputParser,
|
|
38
|
+
)
|
|
39
|
+
from coco_core.output_parsers.openai_tools import (
|
|
40
|
+
JsonOutputKeyToolsParser,
|
|
41
|
+
JsonOutputToolsParser,
|
|
42
|
+
PydanticToolsParser,
|
|
43
|
+
)
|
|
44
|
+
from coco_core.output_parsers.pydantic import PydanticOutputParser
|
|
45
|
+
from coco_core.output_parsers.string import StrOutputParser
|
|
46
|
+
from coco_core.output_parsers.transform import (
|
|
47
|
+
BaseCumulativeTransformOutputParser,
|
|
48
|
+
BaseTransformOutputParser,
|
|
49
|
+
)
|
|
50
|
+
from coco_core.output_parsers.xml import XMLOutputParser
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"BaseCumulativeTransformOutputParser",
|
|
54
|
+
"BaseGenerationOutputParser",
|
|
55
|
+
"BaseLLMOutputParser",
|
|
56
|
+
"BaseOutputParser",
|
|
57
|
+
"BaseTransformOutputParser",
|
|
58
|
+
"CommaSeparatedListOutputParser",
|
|
59
|
+
"JsonOutputKeyToolsParser",
|
|
60
|
+
"JsonOutputParser",
|
|
61
|
+
"JsonOutputToolsParser",
|
|
62
|
+
"ListOutputParser",
|
|
63
|
+
"MarkdownListOutputParser",
|
|
64
|
+
"NumberedListOutputParser",
|
|
65
|
+
"PydanticOutputParser",
|
|
66
|
+
"PydanticToolsParser",
|
|
67
|
+
"SimpleJsonOutputParser",
|
|
68
|
+
"StrOutputParser",
|
|
69
|
+
"XMLOutputParser",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
_dynamic_imports = {
|
|
73
|
+
"BaseLLMOutputParser": "base",
|
|
74
|
+
"BaseGenerationOutputParser": "base",
|
|
75
|
+
"BaseOutputParser": "base",
|
|
76
|
+
"JsonOutputParser": "json",
|
|
77
|
+
"SimpleJsonOutputParser": "json",
|
|
78
|
+
"ListOutputParser": "list",
|
|
79
|
+
"CommaSeparatedListOutputParser": "list",
|
|
80
|
+
"MarkdownListOutputParser": "list",
|
|
81
|
+
"NumberedListOutputParser": "list",
|
|
82
|
+
"JsonOutputKeyToolsParser": "openai_tools",
|
|
83
|
+
"JsonOutputToolsParser": "openai_tools",
|
|
84
|
+
"PydanticToolsParser": "openai_tools",
|
|
85
|
+
"PydanticOutputParser": "pydantic",
|
|
86
|
+
"StrOutputParser": "string",
|
|
87
|
+
"BaseTransformOutputParser": "transform",
|
|
88
|
+
"BaseCumulativeTransformOutputParser": "transform",
|
|
89
|
+
"XMLOutputParser": "xml",
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def __getattr__(attr_name: str) -> object:
|
|
94
|
+
module_name = _dynamic_imports.get(attr_name)
|
|
95
|
+
result = import_attr(attr_name, module_name, __spec__.parent)
|
|
96
|
+
globals()[attr_name] = result
|
|
97
|
+
return result
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def __dir__() -> list[str]:
|
|
101
|
+
return __all__
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""Base parser for language model outputs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import builtins
|
|
6
|
+
import contextlib
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import (
|
|
9
|
+
TYPE_CHECKING,
|
|
10
|
+
Any,
|
|
11
|
+
Generic,
|
|
12
|
+
TypeVar,
|
|
13
|
+
cast,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from typing_extensions import override
|
|
17
|
+
|
|
18
|
+
from coco_core._api import deprecated
|
|
19
|
+
from coco_core.language_models import LanguageModelOutput
|
|
20
|
+
from coco_core.messages import AnyMessage, BaseMessage
|
|
21
|
+
from coco_core.outputs import ChatGeneration, Generation
|
|
22
|
+
from coco_core.runnables import Runnable, RunnableConfig, RunnableSerializable
|
|
23
|
+
from coco_core.runnables.config import run_in_executor
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
import builtins
|
|
27
|
+
|
|
28
|
+
from coco_core.prompt_values import PromptValue
|
|
29
|
+
|
|
30
|
+
T = TypeVar("T")
|
|
31
|
+
OutputParserLike = Runnable[LanguageModelOutput, T]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BaseLLMOutputParser(ABC, Generic[T]):
|
|
35
|
+
"""Abstract base class for parsing the outputs of a model."""
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
|
|
39
|
+
"""Parse a list of candidate model `Generation` objects into a specific format.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
result: A list of `Generation` to be parsed.
|
|
43
|
+
|
|
44
|
+
The `Generation` objects are assumed to be different candidate outputs
|
|
45
|
+
for a single model input.
|
|
46
|
+
partial: Whether to parse the output as a partial result.
|
|
47
|
+
|
|
48
|
+
This is useful for parsers that can parse partial results.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Structured output.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
async def aparse_result(
|
|
55
|
+
self, result: list[Generation], *, partial: bool = False
|
|
56
|
+
) -> T:
|
|
57
|
+
"""Parse a list of candidate model `Generation` objects into a specific format.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
result: A list of `Generation` to be parsed.
|
|
61
|
+
|
|
62
|
+
The Generations are assumed to be different candidate outputs for a
|
|
63
|
+
single model input.
|
|
64
|
+
partial: Whether to parse the output as a partial result.
|
|
65
|
+
|
|
66
|
+
This is useful for parsers that can parse partial results.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Structured output.
|
|
70
|
+
"""
|
|
71
|
+
return await run_in_executor(None, self.parse_result, result, partial=partial)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class BaseGenerationOutputParser(
|
|
75
|
+
BaseLLMOutputParser[T], RunnableSerializable[LanguageModelOutput, T]
|
|
76
|
+
):
|
|
77
|
+
"""Base class to parse the output of an LLM call."""
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
@override
|
|
81
|
+
def InputType(self) -> Any:
|
|
82
|
+
"""Return the input type for the parser."""
|
|
83
|
+
return str | AnyMessage
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
@override
|
|
87
|
+
def OutputType(self) -> type[T]:
|
|
88
|
+
"""Return the output type for the parser."""
|
|
89
|
+
# even though mypy complains this isn't valid,
|
|
90
|
+
# it is good enough for pydantic to build the schema from
|
|
91
|
+
return cast("type[T]", T) # type: ignore[misc]
|
|
92
|
+
|
|
93
|
+
@override
|
|
94
|
+
def invoke(
|
|
95
|
+
self,
|
|
96
|
+
input: str | BaseMessage,
|
|
97
|
+
config: RunnableConfig | None = None,
|
|
98
|
+
**kwargs: Any,
|
|
99
|
+
) -> T:
|
|
100
|
+
if isinstance(input, BaseMessage):
|
|
101
|
+
return self._call_with_config(
|
|
102
|
+
lambda inner_input: self.parse_result(
|
|
103
|
+
[ChatGeneration(message=inner_input)]
|
|
104
|
+
),
|
|
105
|
+
input,
|
|
106
|
+
config,
|
|
107
|
+
run_type="parser",
|
|
108
|
+
)
|
|
109
|
+
return self._call_with_config(
|
|
110
|
+
lambda inner_input: self.parse_result([Generation(text=inner_input)]),
|
|
111
|
+
input,
|
|
112
|
+
config,
|
|
113
|
+
run_type="parser",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
@override
|
|
117
|
+
async def ainvoke(
|
|
118
|
+
self,
|
|
119
|
+
input: str | BaseMessage,
|
|
120
|
+
config: RunnableConfig | None = None,
|
|
121
|
+
**kwargs: Any | None,
|
|
122
|
+
) -> T:
|
|
123
|
+
if isinstance(input, BaseMessage):
|
|
124
|
+
return await self._acall_with_config(
|
|
125
|
+
lambda inner_input: self.aparse_result(
|
|
126
|
+
[ChatGeneration(message=inner_input)]
|
|
127
|
+
),
|
|
128
|
+
input,
|
|
129
|
+
config,
|
|
130
|
+
run_type="parser",
|
|
131
|
+
)
|
|
132
|
+
return await self._acall_with_config(
|
|
133
|
+
lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
|
|
134
|
+
input,
|
|
135
|
+
config,
|
|
136
|
+
run_type="parser",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class BaseOutputParser(
|
|
141
|
+
BaseLLMOutputParser[T], RunnableSerializable[LanguageModelOutput, T]
|
|
142
|
+
):
|
|
143
|
+
"""Base class to parse the output of an LLM call.
|
|
144
|
+
|
|
145
|
+
Output parsers help structure language model responses.
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
```python
|
|
149
|
+
# Implement a simple boolean output parser
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class BooleanOutputParser(BaseOutputParser[bool]):
|
|
153
|
+
true_val: str = "YES"
|
|
154
|
+
false_val: str = "NO"
|
|
155
|
+
|
|
156
|
+
def parse(self, text: str) -> bool:
|
|
157
|
+
cleaned_text = text.strip().upper()
|
|
158
|
+
if cleaned_text not in (
|
|
159
|
+
self.true_val.upper(),
|
|
160
|
+
self.false_val.upper(),
|
|
161
|
+
):
|
|
162
|
+
raise OutputParserException(
|
|
163
|
+
f"BooleanOutputParser expected output value to either be "
|
|
164
|
+
f"{self.true_val} or {self.false_val} (case-insensitive). "
|
|
165
|
+
f"Received {cleaned_text}."
|
|
166
|
+
)
|
|
167
|
+
return cleaned_text == self.true_val.upper()
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def _type(self) -> str:
|
|
171
|
+
return "boolean_output_parser"
|
|
172
|
+
```
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
@override
|
|
177
|
+
def InputType(self) -> Any:
|
|
178
|
+
"""Return the input type for the parser."""
|
|
179
|
+
return str | AnyMessage
|
|
180
|
+
|
|
181
|
+
@property
|
|
182
|
+
@override
|
|
183
|
+
def OutputType(self) -> type[T]:
|
|
184
|
+
"""Return the output type for the parser.
|
|
185
|
+
|
|
186
|
+
This property is inferred from the first type argument of the class.
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
TypeError: If the class doesn't have an inferable `OutputType`.
|
|
190
|
+
"""
|
|
191
|
+
for base in self.__class__.mro():
|
|
192
|
+
if hasattr(base, "__pydantic_generic_metadata__"):
|
|
193
|
+
metadata = base.__pydantic_generic_metadata__
|
|
194
|
+
if "args" in metadata and len(metadata["args"]) > 0:
|
|
195
|
+
return cast("type[T]", metadata["args"][0])
|
|
196
|
+
|
|
197
|
+
msg = (
|
|
198
|
+
f"Runnable {self.__class__.__name__} doesn't have an inferable OutputType. "
|
|
199
|
+
"Override the OutputType property to specify the output type."
|
|
200
|
+
)
|
|
201
|
+
raise TypeError(msg)
|
|
202
|
+
|
|
203
|
+
@override
|
|
204
|
+
def invoke(
|
|
205
|
+
self,
|
|
206
|
+
input: str | BaseMessage,
|
|
207
|
+
config: RunnableConfig | None = None,
|
|
208
|
+
**kwargs: Any,
|
|
209
|
+
) -> T:
|
|
210
|
+
if isinstance(input, BaseMessage):
|
|
211
|
+
return self._call_with_config(
|
|
212
|
+
lambda inner_input: self.parse_result(
|
|
213
|
+
[ChatGeneration(message=inner_input)]
|
|
214
|
+
),
|
|
215
|
+
input,
|
|
216
|
+
config,
|
|
217
|
+
run_type="parser",
|
|
218
|
+
)
|
|
219
|
+
return self._call_with_config(
|
|
220
|
+
lambda inner_input: self.parse_result([Generation(text=inner_input)]),
|
|
221
|
+
input,
|
|
222
|
+
config,
|
|
223
|
+
run_type="parser",
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
@override
|
|
227
|
+
async def ainvoke(
|
|
228
|
+
self,
|
|
229
|
+
input: str | BaseMessage,
|
|
230
|
+
config: RunnableConfig | None = None,
|
|
231
|
+
**kwargs: Any | None,
|
|
232
|
+
) -> T:
|
|
233
|
+
if isinstance(input, BaseMessage):
|
|
234
|
+
return await self._acall_with_config(
|
|
235
|
+
lambda inner_input: self.aparse_result(
|
|
236
|
+
[ChatGeneration(message=inner_input)]
|
|
237
|
+
),
|
|
238
|
+
input,
|
|
239
|
+
config,
|
|
240
|
+
run_type="parser",
|
|
241
|
+
)
|
|
242
|
+
return await self._acall_with_config(
|
|
243
|
+
lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
|
|
244
|
+
input,
|
|
245
|
+
config,
|
|
246
|
+
run_type="parser",
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
@override
|
|
250
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
|
|
251
|
+
"""Parse a list of candidate model `Generation` objects into a specific format.
|
|
252
|
+
|
|
253
|
+
The return value is parsed from only the first `Generation` in the result, which
|
|
254
|
+
is assumed to be the highest-likelihood `Generation`.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
result: A list of `Generation` to be parsed.
|
|
258
|
+
|
|
259
|
+
The `Generation` objects are assumed to be different candidate outputs
|
|
260
|
+
for a single model input.
|
|
261
|
+
partial: Whether to parse the output as a partial result.
|
|
262
|
+
|
|
263
|
+
This is useful for parsers that can parse partial results.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Structured output.
|
|
267
|
+
"""
|
|
268
|
+
return self.parse(result[0].text)
|
|
269
|
+
|
|
270
|
+
@abstractmethod
|
|
271
|
+
def parse(self, text: str) -> T:
|
|
272
|
+
"""Parse a single string model output into some structure.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
text: String output of a language model.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Structured output.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
async def aparse_result(
|
|
282
|
+
self, result: list[Generation], *, partial: bool = False
|
|
283
|
+
) -> T:
|
|
284
|
+
"""Parse a list of candidate model `Generation` objects into a specific format.
|
|
285
|
+
|
|
286
|
+
The return value is parsed from only the first `Generation` in the result, which
|
|
287
|
+
is assumed to be the highest-likelihood `Generation`.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
result: A list of `Generation` to be parsed.
|
|
291
|
+
|
|
292
|
+
The `Generation` objects are assumed to be different candidate outputs
|
|
293
|
+
for a single model input.
|
|
294
|
+
partial: Whether to parse the output as a partial result.
|
|
295
|
+
|
|
296
|
+
This is useful for parsers that can parse partial results.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Structured output.
|
|
300
|
+
"""
|
|
301
|
+
return await run_in_executor(None, self.parse_result, result, partial=partial)
|
|
302
|
+
|
|
303
|
+
async def aparse(self, text: str) -> T:
|
|
304
|
+
"""Async parse a single string model output into some structure.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
text: String output of a language model.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
Structured output.
|
|
311
|
+
"""
|
|
312
|
+
return await run_in_executor(None, self.parse, text)
|
|
313
|
+
|
|
314
|
+
# TODO: rename 'completion' -> 'text'.
|
|
315
|
+
def parse_with_prompt(
|
|
316
|
+
self,
|
|
317
|
+
completion: str,
|
|
318
|
+
prompt: PromptValue, # noqa: ARG002
|
|
319
|
+
) -> Any:
|
|
320
|
+
"""Parse the output of an LLM call with the input prompt for context.
|
|
321
|
+
|
|
322
|
+
The prompt is largely provided in the event the `OutputParser` wants to retry or
|
|
323
|
+
fix the output in some way, and needs information from the prompt to do so.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
completion: String output of a language model.
|
|
327
|
+
prompt: Input `PromptValue`.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Structured output.
|
|
331
|
+
"""
|
|
332
|
+
return self.parse(completion)
|
|
333
|
+
|
|
334
|
+
def get_format_instructions(self) -> str:
|
|
335
|
+
"""Instructions on how the LLM output should be formatted."""
|
|
336
|
+
raise NotImplementedError
|
|
337
|
+
|
|
338
|
+
@property
|
|
339
|
+
def _type(self) -> str:
|
|
340
|
+
"""Return the output parser type for serialization."""
|
|
341
|
+
msg = (
|
|
342
|
+
f"_type property is not implemented in class {self.__class__.__name__}."
|
|
343
|
+
" This is required for serialization."
|
|
344
|
+
)
|
|
345
|
+
raise NotImplementedError(msg)
|
|
346
|
+
|
|
347
|
+
@deprecated("1.4.2", alternative="asdict", removal="2.0.0")
|
|
348
|
+
@override
|
|
349
|
+
def dict(self, **kwargs: Any) -> builtins.dict[str, Any]:
|
|
350
|
+
"""DEPRECATED - use `asdict()` instead.
|
|
351
|
+
|
|
352
|
+
Return a dictionary representation of the output parser.
|
|
353
|
+
"""
|
|
354
|
+
return self.asdict(**kwargs)
|
|
355
|
+
|
|
356
|
+
def asdict(self, **kwargs: Any) -> builtins.dict[str, Any]:
|
|
357
|
+
"""Return a dictionary representation of the output parser."""
|
|
358
|
+
output_parser_dict = super().model_dump(**kwargs)
|
|
359
|
+
with contextlib.suppress(NotImplementedError):
|
|
360
|
+
output_parser_dict["_type"] = self._type
|
|
361
|
+
return output_parser_dict
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Format instructions."""
|
|
2
|
+
|
|
3
|
+
JSON_FORMAT_INSTRUCTIONS = """STRICT OUTPUT FORMAT:
|
|
4
|
+
- Return only the JSON value that conforms to the schema. Do not include any additional text, explanations, headings, or separators.
|
|
5
|
+
- Do not wrap the JSON in Markdown or code fences (no ``` or ```json).
|
|
6
|
+
- Do not prepend or append any text (e.g., do not write "Here is the JSON:").
|
|
7
|
+
- The response must be a single top-level JSON value exactly as required by the schema (object/array/etc.), with no trailing commas or comments.
|
|
8
|
+
|
|
9
|
+
The output should be formatted as a JSON instance that conforms to the JSON schema below.
|
|
10
|
+
|
|
11
|
+
As an example, for the schema {{"properties": {{"foo": {{"title": "Foo", "description": "a list of strings", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}} the object {{"foo": ["bar", "baz"]}} is a well-formatted instance of the schema. The object {{"properties": {{"foo": ["bar", "baz"]}}}} is not well-formatted.
|
|
12
|
+
|
|
13
|
+
Here is the output schema (shown in a code block for readability only — do not include any backticks or Markdown in your output):
|
|
14
|
+
```
|
|
15
|
+
{schema}
|
|
16
|
+
```""" # noqa: E501
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Parser for JSON output."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from json import JSONDecodeError
|
|
7
|
+
from typing import Annotated, Any, TypeVar
|
|
8
|
+
|
|
9
|
+
import jsonpatch # type: ignore[import-untyped]
|
|
10
|
+
import pydantic
|
|
11
|
+
from pydantic import SkipValidation
|
|
12
|
+
from pydantic.v1 import BaseModel
|
|
13
|
+
from typing_extensions import override
|
|
14
|
+
|
|
15
|
+
from coco_core.exceptions import OutputParserException
|
|
16
|
+
from coco_core.output_parsers.format_instructions import JSON_FORMAT_INSTRUCTIONS
|
|
17
|
+
from coco_core.output_parsers.transform import BaseCumulativeTransformOutputParser
|
|
18
|
+
from coco_core.outputs import Generation
|
|
19
|
+
from coco_core.utils.json import (
|
|
20
|
+
parse_and_check_json_markdown,
|
|
21
|
+
parse_json_markdown,
|
|
22
|
+
parse_partial_json,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Union type needs to be last assignment to PydanticBaseModel to make mypy happy.
|
|
26
|
+
PydanticBaseModel = BaseModel | pydantic.BaseModel
|
|
27
|
+
|
|
28
|
+
TBaseModel = TypeVar("TBaseModel", bound=PydanticBaseModel)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]):
|
|
32
|
+
"""Parse the output of an LLM call to a JSON object.
|
|
33
|
+
|
|
34
|
+
Probably the most reliable output parser for getting structured data that does *not*
|
|
35
|
+
use function calling.
|
|
36
|
+
|
|
37
|
+
When used in streaming mode, it will yield partial JSON objects containing all the
|
|
38
|
+
keys that have been returned so far.
|
|
39
|
+
|
|
40
|
+
In streaming, if `diff` is set to `True`, yields `JSONPatch` operations describing
|
|
41
|
+
the difference between the previous and the current object.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
pydantic_object: Annotated[type[TBaseModel] | None, SkipValidation()] = None # type: ignore[valid-type]
|
|
45
|
+
"""The Pydantic object to use for validation.
|
|
46
|
+
|
|
47
|
+
If `None`, no validation is performed.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
@override
|
|
51
|
+
def _diff(self, prev: Any | None, next: Any) -> Any:
|
|
52
|
+
return jsonpatch.make_patch(prev, next).patch
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
def _get_schema(pydantic_object: type[TBaseModel]) -> dict[str, Any]:
|
|
56
|
+
if issubclass(pydantic_object, pydantic.BaseModel):
|
|
57
|
+
return pydantic_object.model_json_schema()
|
|
58
|
+
return pydantic_object.schema()
|
|
59
|
+
|
|
60
|
+
@override
|
|
61
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
62
|
+
"""Parse the result of an LLM call to a JSON object.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
result: The result of the LLM call.
|
|
66
|
+
partial: Whether to parse partial JSON objects.
|
|
67
|
+
|
|
68
|
+
If `True`, the output will be a JSON object containing all the keys that
|
|
69
|
+
have been returned so far.
|
|
70
|
+
|
|
71
|
+
If `False`, the output will be the full JSON object.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
The parsed JSON object.
|
|
75
|
+
|
|
76
|
+
Raises:
|
|
77
|
+
OutputParserException: If the output is not valid JSON.
|
|
78
|
+
"""
|
|
79
|
+
text = result[0].text
|
|
80
|
+
text = text.strip()
|
|
81
|
+
if partial:
|
|
82
|
+
try:
|
|
83
|
+
return parse_json_markdown(text)
|
|
84
|
+
except JSONDecodeError:
|
|
85
|
+
return None
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
return parse_json_markdown(text)
|
|
89
|
+
except JSONDecodeError as e:
|
|
90
|
+
msg = f"Invalid json output: {text}"
|
|
91
|
+
raise OutputParserException(msg, llm_output=text) from e
|
|
92
|
+
|
|
93
|
+
def parse(self, text: str) -> Any:
|
|
94
|
+
"""Parse the output of an LLM call to a JSON object.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
text: The output of the LLM call.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The parsed JSON object.
|
|
101
|
+
"""
|
|
102
|
+
return self.parse_result([Generation(text=text)])
|
|
103
|
+
|
|
104
|
+
def get_format_instructions(self) -> str:
|
|
105
|
+
"""Return the format instructions for the JSON output.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The format instructions for the JSON output.
|
|
109
|
+
"""
|
|
110
|
+
if self.pydantic_object is None:
|
|
111
|
+
return "Return a JSON object."
|
|
112
|
+
# Copy schema to avoid altering original Pydantic schema.
|
|
113
|
+
schema = dict(self._get_schema(self.pydantic_object).items())
|
|
114
|
+
|
|
115
|
+
# Remove extraneous fields.
|
|
116
|
+
reduced_schema = schema
|
|
117
|
+
if "title" in reduced_schema:
|
|
118
|
+
del reduced_schema["title"]
|
|
119
|
+
if "type" in reduced_schema:
|
|
120
|
+
del reduced_schema["type"]
|
|
121
|
+
# Ensure json in context is well-formed with double quotes.
|
|
122
|
+
schema_str = json.dumps(reduced_schema, ensure_ascii=False)
|
|
123
|
+
return JSON_FORMAT_INSTRUCTIONS.format(schema=schema_str)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def _type(self) -> str:
|
|
127
|
+
return "simple_json_output_parser"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# For backwards compatibility
|
|
131
|
+
SimpleJsonOutputParser = JsonOutputParser
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
__all__ = [
|
|
135
|
+
"JsonOutputParser",
|
|
136
|
+
"SimpleJsonOutputParser", # For backwards compatibility
|
|
137
|
+
"parse_and_check_json_markdown", # For backwards compatibility
|
|
138
|
+
"parse_partial_json", # For backwards compatibility
|
|
139
|
+
]
|