ellements 0.2.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.
- ellements/__init__.py +57 -0
- ellements/agents/__init__.py +45 -0
- ellements/agents/backend.py +100 -0
- ellements/agents/builder.py +303 -0
- ellements/agents/claude_backend.py +200 -0
- ellements/agents/controller.py +237 -0
- ellements/agents/openai_backend.py +187 -0
- ellements/agents/py.typed +0 -0
- ellements/agents/runner.py +358 -0
- ellements/agents/tools.py +30 -0
- ellements/benchmarking/__init__.py +52 -0
- ellements/benchmarking/harness.py +342 -0
- ellements/benchmarking/py.typed +0 -0
- ellements/benchmarking/results.py +173 -0
- ellements/cli/__init__.py +80 -0
- ellements/cli/adapters.py +73 -0
- ellements/cli/agent_tui.py +1178 -0
- ellements/cli/components.py +411 -0
- ellements/cli/printer.py +229 -0
- ellements/cli/py.typed +0 -0
- ellements/core/__init__.py +112 -0
- ellements/core/async_utils.py +42 -0
- ellements/core/budgeting/__init__.py +43 -0
- ellements/core/budgeting/client.py +276 -0
- ellements/core/budgeting/protocol.py +51 -0
- ellements/core/budgeting/trackers.py +177 -0
- ellements/core/caching/__init__.py +51 -0
- ellements/core/caching/cache.py +73 -0
- ellements/core/caching/client.py +300 -0
- ellements/core/caching/disk.py +128 -0
- ellements/core/caching/keys.py +97 -0
- ellements/core/caching/memory.py +104 -0
- ellements/core/chunking.py +262 -0
- ellements/core/config.py +180 -0
- ellements/core/exceptions.py +145 -0
- ellements/core/llm/__init__.py +46 -0
- ellements/core/llm/client.py +1124 -0
- ellements/core/llm/images.py +226 -0
- ellements/core/llm/messages.py +202 -0
- ellements/core/llm/model_params.py +66 -0
- ellements/core/llm/protocol.py +146 -0
- ellements/core/llm/requests.py +100 -0
- ellements/core/llm/structured.py +91 -0
- ellements/core/llm/wrapper.py +79 -0
- ellements/core/observability/__init__.py +39 -0
- ellements/core/observability/events.py +169 -0
- ellements/core/observability/jsonl_logger.py +244 -0
- ellements/core/observability/markdown_formatter.py +197 -0
- ellements/core/observability/observer.py +56 -0
- ellements/core/prompting/__init__.py +14 -0
- ellements/core/prompting/context.py +185 -0
- ellements/core/prompting/guideline.py +133 -0
- ellements/core/prompting/persona.py +267 -0
- ellements/core/prompting/sources.py +92 -0
- ellements/core/py.typed +0 -0
- ellements/core/rate_limit/__init__.py +44 -0
- ellements/core/rate_limit/bucket.py +85 -0
- ellements/core/rate_limit/client.py +216 -0
- ellements/core/rate_limit/protocol.py +27 -0
- ellements/core/templating.py +126 -0
- ellements/core/tools/__init__.py +51 -0
- ellements/core/tools/dialects.py +136 -0
- ellements/core/tools/executor.py +48 -0
- ellements/core/tools/protocol.py +36 -0
- ellements/core/tools/records.py +28 -0
- ellements/core/tools/registry.py +205 -0
- ellements/core/tools/schemas.py +80 -0
- ellements/core/tools/simple.py +119 -0
- ellements/core/tools/spec.py +33 -0
- ellements/domain_specific/__init__.py +7 -0
- ellements/domain_specific/finance/__init__.py +188 -0
- ellements/domain_specific/finance/calculations.py +837 -0
- ellements/domain_specific/finance/charts.py +426 -0
- ellements/domain_specific/finance/portfolio.py +129 -0
- ellements/domain_specific/finance/quant_analysis.py +279 -0
- ellements/domain_specific/finance/risk.py +362 -0
- ellements/domain_specific/finance/technical_indicators.py +241 -0
- ellements/domain_specific/finance/tools.py +483 -0
- ellements/domain_specific/finance/valuation.py +312 -0
- ellements/domain_specific/finance/yahoo_finance.py +1523 -0
- ellements/domain_specific/finance/yahoo_finance_models.py +321 -0
- ellements/domain_specific/py.typed +0 -0
- ellements/execution/__init__.py +56 -0
- ellements/execution/callbacks.py +149 -0
- ellements/execution/catalog.py +70 -0
- ellements/execution/collaborative.py +191 -0
- ellements/execution/config.py +135 -0
- ellements/execution/py.typed +0 -0
- ellements/execution/reflection.py +156 -0
- ellements/execution/self_consistency.py +189 -0
- ellements/execution/single_call.py +48 -0
- ellements/execution/strategies.py +237 -0
- ellements/execution/tree_of_thought.py +541 -0
- ellements/fslm/__init__.py +108 -0
- ellements/fslm/builtins.py +103 -0
- ellements/fslm/cli.py +199 -0
- ellements/fslm/context.py +50 -0
- ellements/fslm/definition.py +163 -0
- ellements/fslm/det.py +173 -0
- ellements/fslm/dsl.py +458 -0
- ellements/fslm/errors.py +38 -0
- ellements/fslm/evaluators.py +141 -0
- ellements/fslm/kernel.py +603 -0
- ellements/fslm/loading.py +123 -0
- ellements/fslm/models.py +623 -0
- ellements/fslm/nl.py +87 -0
- ellements/fslm/observers.py +107 -0
- ellements/fslm/persistence.py +72 -0
- ellements/fslm/py.typed +0 -0
- ellements/fslm/rendering.py +551 -0
- ellements/fslm/visualization.py +25 -0
- ellements/reporting/__init__.py +12 -0
- ellements/reporting/charts.py +364 -0
- ellements/reporting/html_generation.py +132 -0
- ellements/reporting/py.typed +0 -0
- ellements/reporting/visualization.py +73 -0
- ellements/standard_tools/__init__.py +22 -0
- ellements/standard_tools/py.typed +0 -0
- ellements/standard_tools/terminal.py +205 -0
- ellements/standard_tools/web/__init__.py +37 -0
- ellements/standard_tools/web/browser_viewer.py +214 -0
- ellements/standard_tools/web/crawler.py +454 -0
- ellements/standard_tools/web/search.py +399 -0
- ellements/standard_tools/web/youtube.py +1297 -0
- ellements-0.2.0.dist-info/METADATA +368 -0
- ellements-0.2.0.dist-info/RECORD +130 -0
- ellements-0.2.0.dist-info/WHEEL +5 -0
- ellements-0.2.0.dist-info/entry_points.txt +2 -0
- ellements-0.2.0.dist-info/licenses/LICENSE +42 -0
- ellements-0.2.0.dist-info/top_level.txt +1 -0
ellements/core/config.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Lightweight, opinionated configuration support for ellements.
|
|
2
|
+
|
|
3
|
+
Goals:
|
|
4
|
+
|
|
5
|
+
* Apps describe their settings as **frozen dataclasses** — strongly
|
|
6
|
+
typed, immutable, easy to introspect, trivially picklable, plays
|
|
7
|
+
well with Pydantic or attrs at the boundary.
|
|
8
|
+
* Loading from disk is **one function call** per supported format
|
|
9
|
+
(TOML, JSON). Both formats accept identical key→value structures, so
|
|
10
|
+
callers can pick whichever suits their tooling.
|
|
11
|
+
* No global "settings singleton". Apps build their config explicitly
|
|
12
|
+
and pass it to whoever needs it — this keeps tests trivial and
|
|
13
|
+
removes hidden coupling.
|
|
14
|
+
* Loaders never inject defaults silently. If the dataclass declares a
|
|
15
|
+
default, that's what callers get when the file omits the field; if
|
|
16
|
+
no default is declared, the loader raises a clear error.
|
|
17
|
+
* Composition is by **plain object construction** (``dataclasses.replace``
|
|
18
|
+
for overlays) rather than a bespoke merge DSL. We provide
|
|
19
|
+
:func:`overlay` as a tiny convenience for the common "base config +
|
|
20
|
+
per-environment overrides" pattern.
|
|
21
|
+
|
|
22
|
+
Example::
|
|
23
|
+
|
|
24
|
+
from dataclasses import dataclass
|
|
25
|
+
from ellements.core.config import load_toml, overlay
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True, slots=True)
|
|
28
|
+
class AppConfig:
|
|
29
|
+
model: str
|
|
30
|
+
temperature: float = 0.7
|
|
31
|
+
retries: int = 3
|
|
32
|
+
|
|
33
|
+
base = load_toml("config/base.toml", AppConfig)
|
|
34
|
+
prod = overlay(base, {"temperature": 0.0})
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
import json
|
|
40
|
+
import tomllib
|
|
41
|
+
from dataclasses import fields, is_dataclass, replace
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
from typing import Any, TypeVar
|
|
44
|
+
|
|
45
|
+
from .exceptions import EllementsError
|
|
46
|
+
|
|
47
|
+
ConfigT = TypeVar("ConfigT")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ConfigError(EllementsError):
|
|
51
|
+
"""Raised when a config payload cannot be turned into a dataclass."""
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def load_toml(path: Path | str, config_class: type[ConfigT]) -> ConfigT:
|
|
55
|
+
"""Load *path* as TOML and instantiate *config_class*.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
path: Path to a TOML file. Must be readable.
|
|
59
|
+
config_class: A dataclass type. Its field set defines the
|
|
60
|
+
expected schema. Extra keys in the file raise
|
|
61
|
+
:class:`ConfigError` so typos surface loudly.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
A fully populated instance of *config_class*.
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
ConfigError: If the file is unreadable, malformed TOML,
|
|
68
|
+
references unknown fields, or omits required fields.
|
|
69
|
+
"""
|
|
70
|
+
file_path = Path(path)
|
|
71
|
+
try:
|
|
72
|
+
with file_path.open("rb") as handle:
|
|
73
|
+
data = tomllib.load(handle)
|
|
74
|
+
except FileNotFoundError as exc:
|
|
75
|
+
raise ConfigError(f"Config file not found: {file_path}") from exc
|
|
76
|
+
except tomllib.TOMLDecodeError as exc:
|
|
77
|
+
raise ConfigError(f"Invalid TOML in {file_path}: {exc}") from exc
|
|
78
|
+
return _instantiate(config_class, data, source=str(file_path))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def load_json(path: Path | str, config_class: type[ConfigT]) -> ConfigT:
|
|
82
|
+
"""Load *path* as JSON and instantiate *config_class*.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
path: Path to a JSON file containing a single object literal.
|
|
86
|
+
config_class: A dataclass type. Its field set defines the
|
|
87
|
+
expected schema. Extra keys raise :class:`ConfigError`.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A fully populated instance of *config_class*.
|
|
91
|
+
|
|
92
|
+
Raises:
|
|
93
|
+
ConfigError: If the file is unreadable, malformed JSON, the
|
|
94
|
+
top-level value is not an object, or required fields are
|
|
95
|
+
missing.
|
|
96
|
+
"""
|
|
97
|
+
file_path = Path(path)
|
|
98
|
+
try:
|
|
99
|
+
text = file_path.read_text(encoding="utf-8")
|
|
100
|
+
except FileNotFoundError as exc:
|
|
101
|
+
raise ConfigError(f"Config file not found: {file_path}") from exc
|
|
102
|
+
try:
|
|
103
|
+
data = json.loads(text)
|
|
104
|
+
except json.JSONDecodeError as exc:
|
|
105
|
+
raise ConfigError(f"Invalid JSON in {file_path}: {exc}") from exc
|
|
106
|
+
if not isinstance(data, dict):
|
|
107
|
+
raise ConfigError(
|
|
108
|
+
f"Config file {file_path} must contain a JSON object at the "
|
|
109
|
+
f"top level (got {type(data).__name__})."
|
|
110
|
+
)
|
|
111
|
+
return _instantiate(config_class, data, source=str(file_path))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def overlay(base: ConfigT, changes: dict[str, Any]) -> ConfigT:
|
|
115
|
+
"""Return a copy of *base* with *changes* applied.
|
|
116
|
+
|
|
117
|
+
Thin wrapper over :func:`dataclasses.replace` that validates the
|
|
118
|
+
keys in *changes* against the dataclass schema, so callers get a
|
|
119
|
+
crisp error if they typo an override.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
base: An instance of a frozen dataclass.
|
|
123
|
+
changes: A mapping of field name → new value. Every key must
|
|
124
|
+
be an existing field on the dataclass.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
A new instance with the same type as *base*, sharing all
|
|
128
|
+
unchanged fields and using overridden values for everything
|
|
129
|
+
in *changes*.
|
|
130
|
+
|
|
131
|
+
Raises:
|
|
132
|
+
ConfigError: If *base* is not a dataclass instance, or if
|
|
133
|
+
*changes* contains an unknown field name.
|
|
134
|
+
"""
|
|
135
|
+
if not is_dataclass(base) or isinstance(base, type):
|
|
136
|
+
raise ConfigError(
|
|
137
|
+
f"overlay() expects a dataclass instance, got {type(base).__name__}."
|
|
138
|
+
)
|
|
139
|
+
known = {field.name for field in fields(base)}
|
|
140
|
+
unknown = set(changes) - known
|
|
141
|
+
if unknown:
|
|
142
|
+
raise ConfigError(
|
|
143
|
+
f"Unknown config fields for {type(base).__name__}: "
|
|
144
|
+
f"{sorted(unknown)}. Known fields: {sorted(known)}."
|
|
145
|
+
)
|
|
146
|
+
return replace(base, **changes)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _instantiate(
|
|
150
|
+
config_class: type[ConfigT], data: dict[str, Any], *, source: str
|
|
151
|
+
) -> ConfigT:
|
|
152
|
+
"""Construct *config_class* from *data*, raising on schema mismatches."""
|
|
153
|
+
if not is_dataclass(config_class):
|
|
154
|
+
raise ConfigError(
|
|
155
|
+
f"{config_class.__name__} is not a dataclass; config_class must "
|
|
156
|
+
f"be a (preferably frozen) dataclass."
|
|
157
|
+
)
|
|
158
|
+
known = {field.name for field in fields(config_class)}
|
|
159
|
+
unknown = set(data) - known
|
|
160
|
+
if unknown:
|
|
161
|
+
raise ConfigError(
|
|
162
|
+
f"Unknown config keys in {source} for "
|
|
163
|
+
f"{config_class.__name__}: {sorted(unknown)}. "
|
|
164
|
+
f"Known fields: {sorted(known)}."
|
|
165
|
+
)
|
|
166
|
+
try:
|
|
167
|
+
return config_class(**data)
|
|
168
|
+
except TypeError as exc:
|
|
169
|
+
raise ConfigError(
|
|
170
|
+
f"Failed to instantiate {config_class.__name__} from {source}: "
|
|
171
|
+
f"{exc}"
|
|
172
|
+
) from exc
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
__all__ = [
|
|
176
|
+
"ConfigError",
|
|
177
|
+
"load_json",
|
|
178
|
+
"load_toml",
|
|
179
|
+
"overlay",
|
|
180
|
+
]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Custom exceptions for the ellements library.
|
|
2
|
+
|
|
3
|
+
All ellements exceptions inherit from :class:`EllementsError`, which itself
|
|
4
|
+
inherits from :class:`Exception`. The taxonomy is intentionally small and
|
|
5
|
+
purpose-built — callers can catch the most specific class they care about,
|
|
6
|
+
or :class:`EllementsError` as a single umbrella.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .tools import ToolCallRecord
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EllementsError(Exception):
|
|
18
|
+
"""Base exception for all ellements errors."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LLMError(EllementsError):
|
|
22
|
+
"""LLM call failed irrecoverably (after any retries)."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ConversationError(EllementsError):
|
|
26
|
+
"""Conversation state or input was invalid."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class EllementsValidationError(EllementsError):
|
|
30
|
+
"""A validation rule inside the ellements library failed.
|
|
31
|
+
|
|
32
|
+
Distinct from :class:`pydantic.ValidationError`, which is raised by
|
|
33
|
+
Pydantic itself. Use this exception when an ellements component
|
|
34
|
+
rejects an input because it violates a library-defined contract
|
|
35
|
+
(e.g. a strategy expecting a non-empty prompt, a tool refusing a
|
|
36
|
+
malformed argument).
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class StructuredOutputUnsupportedError(LLMError):
|
|
41
|
+
"""The selected model/provider does not support native structured outputs.
|
|
42
|
+
|
|
43
|
+
Raised by :meth:`LLMClient.complete_structured` when the configured
|
|
44
|
+
model cannot produce a JSON object matching a Pydantic schema via
|
|
45
|
+
litellm's ``response_format=PydanticModel`` mechanism.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class LogprobsUnsupportedError(LLMError):
|
|
50
|
+
"""The selected model/provider does not expose token log-probabilities.
|
|
51
|
+
|
|
52
|
+
Raised eagerly at benchmark startup when the requested tasks need
|
|
53
|
+
log-likelihoods (e.g. MMLU, HellaSwag) but the model cannot provide
|
|
54
|
+
them. This is intentionally a hard failure — silently returning
|
|
55
|
+
fake ``0.0`` would invalidate benchmark results.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MaxToolIterationsError(LLMError):
|
|
60
|
+
"""The tool-calling loop hit its iteration cap without converging.
|
|
61
|
+
|
|
62
|
+
The error carries the partial conversation captured up to the cap
|
|
63
|
+
and the list of unresolved tool calls the model produced on the
|
|
64
|
+
final turn, so callers can inspect, log, or resume the loop with
|
|
65
|
+
additional executors.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
message: str,
|
|
71
|
+
*,
|
|
72
|
+
max_iterations: int,
|
|
73
|
+
messages: list[dict[str, Any]],
|
|
74
|
+
tool_calls_made: list[ToolCallRecord],
|
|
75
|
+
unresolved_tool_calls: list[dict[str, Any]],
|
|
76
|
+
) -> None:
|
|
77
|
+
super().__init__(message)
|
|
78
|
+
self.max_iterations = max_iterations
|
|
79
|
+
self.messages = messages
|
|
80
|
+
self.tool_calls_made = tool_calls_made
|
|
81
|
+
self.unresolved_tool_calls = unresolved_tool_calls
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class PromptLibraryError(EllementsError):
|
|
85
|
+
"""Base class for errors raised by persona / guideline / prompt libraries.
|
|
86
|
+
|
|
87
|
+
Catch this to handle any failure to resolve a named entry in any
|
|
88
|
+
prompt library — useful when several lookups happen in a row and
|
|
89
|
+
you want a single fallback path.
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class PersonaNotFoundError(PromptLibraryError):
|
|
94
|
+
"""The requested persona could not be located in the active library."""
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class GuidelineNotFoundError(PromptLibraryError):
|
|
98
|
+
"""The requested guideline could not be located in the active library."""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class PromptKeyMissingError(PromptLibraryError):
|
|
102
|
+
"""A strategy required a named prompt that was not supplied."""
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class BudgetExceededError(EllementsError):
|
|
106
|
+
"""A cost budget was exhausted before a request could complete.
|
|
107
|
+
|
|
108
|
+
Raised by :class:`ellements.core.budgeting.BudgetedLLMClient` (and
|
|
109
|
+
any :class:`~ellements.core.budgeting.BudgetTrackerProtocol`
|
|
110
|
+
implementation) when a request would push cumulative spend past
|
|
111
|
+
the configured cap.
|
|
112
|
+
|
|
113
|
+
The error carries the budget identifier, the limit that was hit,
|
|
114
|
+
and the amount that was charged so callers can surface useful
|
|
115
|
+
diagnostics or implement graceful fallbacks.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
message: str,
|
|
121
|
+
*,
|
|
122
|
+
limit: float,
|
|
123
|
+
spent: float,
|
|
124
|
+
attempted: float,
|
|
125
|
+
) -> None:
|
|
126
|
+
super().__init__(message)
|
|
127
|
+
self.limit = limit
|
|
128
|
+
self.spent = spent
|
|
129
|
+
self.attempted = attempted
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
__all__ = [
|
|
133
|
+
"BudgetExceededError",
|
|
134
|
+
"ConversationError",
|
|
135
|
+
"EllementsError",
|
|
136
|
+
"EllementsValidationError",
|
|
137
|
+
"GuidelineNotFoundError",
|
|
138
|
+
"LLMError",
|
|
139
|
+
"LogprobsUnsupportedError",
|
|
140
|
+
"MaxToolIterationsError",
|
|
141
|
+
"PersonaNotFoundError",
|
|
142
|
+
"PromptKeyMissingError",
|
|
143
|
+
"PromptLibraryError",
|
|
144
|
+
"StructuredOutputUnsupportedError",
|
|
145
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Internal LLM support package for ellements.core."""
|
|
2
|
+
|
|
3
|
+
from .client import LLMClient
|
|
4
|
+
from .images import (
|
|
5
|
+
GeneratedImage,
|
|
6
|
+
ImageGenerationResponse,
|
|
7
|
+
ImageInput,
|
|
8
|
+
)
|
|
9
|
+
from .messages import (
|
|
10
|
+
Conversation,
|
|
11
|
+
ImageURLPart,
|
|
12
|
+
Message,
|
|
13
|
+
MessageContent,
|
|
14
|
+
MessageInput,
|
|
15
|
+
build_multimodal_user_message,
|
|
16
|
+
normalize_message_input,
|
|
17
|
+
)
|
|
18
|
+
from .model_params import filter_parameters, get_unsupported_parameters
|
|
19
|
+
from .protocol import LLMClientProtocol
|
|
20
|
+
from .structured import (
|
|
21
|
+
ensure_structured_support,
|
|
22
|
+
parse_structured_content,
|
|
23
|
+
supports_structured_output,
|
|
24
|
+
)
|
|
25
|
+
from .wrapper import LLMClientWrapper
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"Conversation",
|
|
29
|
+
"GeneratedImage",
|
|
30
|
+
"ImageGenerationResponse",
|
|
31
|
+
"ImageInput",
|
|
32
|
+
"ImageURLPart",
|
|
33
|
+
"LLMClient",
|
|
34
|
+
"LLMClientProtocol",
|
|
35
|
+
"LLMClientWrapper",
|
|
36
|
+
"Message",
|
|
37
|
+
"MessageContent",
|
|
38
|
+
"MessageInput",
|
|
39
|
+
"build_multimodal_user_message",
|
|
40
|
+
"ensure_structured_support",
|
|
41
|
+
"filter_parameters",
|
|
42
|
+
"get_unsupported_parameters",
|
|
43
|
+
"normalize_message_input",
|
|
44
|
+
"parse_structured_content",
|
|
45
|
+
"supports_structured_output",
|
|
46
|
+
]
|