lionagi 0.17.11__py3-none-any.whl → 0.18.1__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.
- lionagi/_errors.py +0 -5
- lionagi/fields.py +83 -0
- lionagi/libs/schema/minimal_yaml.py +98 -0
- lionagi/ln/__init__.py +3 -1
- lionagi/ln/concurrency/primitives.py +4 -4
- lionagi/ln/concurrency/task.py +1 -0
- lionagi/ln/types.py +32 -5
- lionagi/models/field_model.py +21 -4
- lionagi/models/hashable_model.py +2 -3
- lionagi/operations/ReAct/ReAct.py +475 -238
- lionagi/operations/ReAct/utils.py +3 -0
- lionagi/operations/act/act.py +206 -0
- lionagi/operations/builder.py +5 -7
- lionagi/operations/chat/chat.py +130 -114
- lionagi/operations/communicate/communicate.py +101 -42
- lionagi/operations/fields.py +380 -0
- lionagi/operations/flow.py +8 -10
- lionagi/operations/interpret/interpret.py +65 -20
- lionagi/operations/node.py +4 -4
- lionagi/operations/operate/operate.py +216 -108
- lionagi/{protocols/operatives → operations/operate}/operative.py +4 -5
- lionagi/{protocols/operatives → operations/operate}/step.py +34 -39
- lionagi/operations/parse/parse.py +170 -142
- lionagi/operations/select/select.py +79 -18
- lionagi/operations/select/utils.py +8 -2
- lionagi/operations/types.py +119 -23
- lionagi/protocols/action/manager.py +5 -6
- lionagi/protocols/contracts.py +2 -2
- lionagi/protocols/generic/__init__.py +22 -0
- lionagi/protocols/generic/element.py +36 -127
- lionagi/protocols/generic/log.py +3 -2
- lionagi/protocols/generic/pile.py +9 -10
- lionagi/protocols/generic/progression.py +23 -22
- lionagi/protocols/graph/edge.py +6 -5
- lionagi/protocols/ids.py +6 -49
- lionagi/protocols/messages/__init__.py +29 -0
- lionagi/protocols/messages/action_request.py +86 -184
- lionagi/protocols/messages/action_response.py +73 -131
- lionagi/protocols/messages/assistant_response.py +130 -159
- lionagi/protocols/messages/base.py +31 -22
- lionagi/protocols/messages/instruction.py +280 -625
- lionagi/protocols/messages/manager.py +112 -62
- lionagi/protocols/messages/message.py +87 -197
- lionagi/protocols/messages/system.py +52 -123
- lionagi/protocols/types.py +1 -13
- lionagi/service/connections/__init__.py +3 -0
- lionagi/service/connections/endpoint.py +0 -8
- lionagi/service/connections/providers/claude_code_cli.py +3 -2
- lionagi/service/connections/providers/oai_.py +29 -94
- lionagi/service/connections/providers/ollama_.py +3 -2
- lionagi/service/hooks/_types.py +1 -1
- lionagi/service/hooks/_utils.py +1 -1
- lionagi/service/hooks/hook_event.py +3 -8
- lionagi/service/hooks/hook_registry.py +5 -5
- lionagi/service/hooks/hooked_event.py +63 -3
- lionagi/service/imodel.py +24 -20
- lionagi/service/third_party/claude_code.py +3 -3
- lionagi/service/third_party/openai_models.py +435 -0
- lionagi/service/token_calculator.py +1 -94
- lionagi/session/branch.py +190 -400
- lionagi/session/session.py +8 -99
- lionagi/tools/file/reader.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/METADATA +6 -6
- lionagi-0.18.1.dist-info/RECORD +164 -0
- lionagi/fields/__init__.py +0 -47
- lionagi/fields/action.py +0 -188
- lionagi/fields/base.py +0 -153
- lionagi/fields/code.py +0 -239
- lionagi/fields/file.py +0 -234
- lionagi/fields/instruct.py +0 -135
- lionagi/fields/reason.py +0 -55
- lionagi/fields/research.py +0 -52
- lionagi/operations/_act/act.py +0 -86
- lionagi/operations/brainstorm/__init__.py +0 -2
- lionagi/operations/brainstorm/brainstorm.py +0 -498
- lionagi/operations/brainstorm/prompt.py +0 -11
- lionagi/operations/instruct/__init__.py +0 -2
- lionagi/operations/instruct/instruct.py +0 -28
- lionagi/operations/plan/__init__.py +0 -6
- lionagi/operations/plan/plan.py +0 -386
- lionagi/operations/plan/prompt.py +0 -25
- lionagi/operations/utils.py +0 -45
- lionagi/protocols/forms/__init__.py +0 -2
- lionagi/protocols/forms/base.py +0 -85
- lionagi/protocols/forms/flow.py +0 -79
- lionagi/protocols/forms/form.py +0 -86
- lionagi/protocols/forms/report.py +0 -48
- lionagi/protocols/mail/__init__.py +0 -2
- lionagi/protocols/mail/exchange.py +0 -220
- lionagi/protocols/mail/mail.py +0 -51
- lionagi/protocols/mail/mailbox.py +0 -103
- lionagi/protocols/mail/manager.py +0 -218
- lionagi/protocols/mail/package.py +0 -101
- lionagi/protocols/messages/templates/README.md +0 -28
- lionagi/protocols/messages/templates/action_request.jinja2 +0 -5
- lionagi/protocols/messages/templates/action_response.jinja2 +0 -9
- lionagi/protocols/messages/templates/assistant_response.jinja2 +0 -6
- lionagi/protocols/messages/templates/instruction_message.jinja2 +0 -61
- lionagi/protocols/messages/templates/system_message.jinja2 +0 -11
- lionagi/protocols/messages/templates/tool_schemas.jinja2 +0 -7
- lionagi/protocols/operatives/__init__.py +0 -2
- lionagi/service/connections/providers/types.py +0 -28
- lionagi/service/third_party/openai_model_names.py +0 -198
- lionagi/service/types.py +0 -58
- lionagi-0.17.11.dist-info/RECORD +0 -199
- /lionagi/operations/{_act → act}/__init__.py +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/WHEEL +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
import asyncio
|
|
5
|
-
from collections import deque
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from lionagi._errors import ItemNotFoundError
|
|
9
|
-
|
|
10
|
-
from .._concepts import Manager, Observable
|
|
11
|
-
from ..generic.element import ID, IDType
|
|
12
|
-
from ..generic.pile import Pile, to_list_type
|
|
13
|
-
from .exchange import Exchange
|
|
14
|
-
from .mail import Mail, Package, PackageCategory
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class MailManager(Manager):
|
|
18
|
-
"""
|
|
19
|
-
A manager for mail operations across various observable sources
|
|
20
|
-
within LionAGI. Unlike `Exchange`, this class can manage the state
|
|
21
|
-
of multiple sources in a more general or higher-level context,
|
|
22
|
-
storing mail queues in a dictionary rather than individual buffers.
|
|
23
|
-
|
|
24
|
-
Attributes
|
|
25
|
-
----------
|
|
26
|
-
sources : Pile[Observable]
|
|
27
|
-
A concurrency-safe collection of known sources.
|
|
28
|
-
mails : dict[str, dict[str, deque]]
|
|
29
|
-
A nested mapping of recipient -> sender -> queue of mail.
|
|
30
|
-
execute_stop : bool
|
|
31
|
-
Controls the asynchronous execution loop; set to True to exit.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(self, sources: ID.Item | ID.ItemSeq = None) -> None:
|
|
35
|
-
"""
|
|
36
|
-
Initialize a MailManager instance.
|
|
37
|
-
|
|
38
|
-
Parameters
|
|
39
|
-
----------
|
|
40
|
-
sources : ID.Item | ID.ItemSeq, optional
|
|
41
|
-
Initial source(s) to manage. Each source must be an Observable.
|
|
42
|
-
"""
|
|
43
|
-
self.sources: Pile[Observable] = Pile()
|
|
44
|
-
self.mails: dict[str, dict[str, deque]] = {}
|
|
45
|
-
self.execute_stop: bool = False
|
|
46
|
-
|
|
47
|
-
if sources:
|
|
48
|
-
self.add_sources(sources)
|
|
49
|
-
|
|
50
|
-
def add_sources(self, sources: ID.Item | ID.ItemSeq, /) -> None:
|
|
51
|
-
"""
|
|
52
|
-
Register new sources in the MailManager.
|
|
53
|
-
|
|
54
|
-
Parameters
|
|
55
|
-
----------
|
|
56
|
-
sources : ID.Item | ID.ItemSeq
|
|
57
|
-
A single source or multiple sources to be added.
|
|
58
|
-
|
|
59
|
-
Raises
|
|
60
|
-
------
|
|
61
|
-
ValueError
|
|
62
|
-
If adding the sources fails for any reason.
|
|
63
|
-
"""
|
|
64
|
-
try:
|
|
65
|
-
sources = to_list_type(sources)
|
|
66
|
-
self.sources.include(sources)
|
|
67
|
-
for item in sources:
|
|
68
|
-
self.mails[item.id] = {}
|
|
69
|
-
except Exception as e:
|
|
70
|
-
raise ValueError("Failed to add source.") from e
|
|
71
|
-
|
|
72
|
-
@staticmethod
|
|
73
|
-
def create_mail(
|
|
74
|
-
sender: ID.Ref,
|
|
75
|
-
recipient: ID.Ref,
|
|
76
|
-
category: PackageCategory | str,
|
|
77
|
-
package: Any,
|
|
78
|
-
request_source: Any = None,
|
|
79
|
-
) -> Mail:
|
|
80
|
-
"""
|
|
81
|
-
Factory method to generate a Mail object.
|
|
82
|
-
|
|
83
|
-
Parameters
|
|
84
|
-
----------
|
|
85
|
-
sender : ID.Ref
|
|
86
|
-
Reference (ID or object) for the sender.
|
|
87
|
-
recipient : ID.Ref
|
|
88
|
-
Reference (ID or object) for the recipient.
|
|
89
|
-
category : PackageCategory | str
|
|
90
|
-
The category of this package.
|
|
91
|
-
package : Any
|
|
92
|
-
The payload or content in the mail.
|
|
93
|
-
request_source : Any, optional
|
|
94
|
-
Additional context about the request source.
|
|
95
|
-
|
|
96
|
-
Returns
|
|
97
|
-
-------
|
|
98
|
-
Mail
|
|
99
|
-
A new mail object with specified sender, recipient, and package.
|
|
100
|
-
"""
|
|
101
|
-
pack = Package(
|
|
102
|
-
category=category, package=package, request_source=request_source
|
|
103
|
-
)
|
|
104
|
-
return Mail(sender=sender, recipient=recipient, package=pack)
|
|
105
|
-
|
|
106
|
-
def delete_source(self, source_id: IDType) -> None:
|
|
107
|
-
"""
|
|
108
|
-
Remove a source from the manager, discarding any associated mail.
|
|
109
|
-
|
|
110
|
-
Parameters
|
|
111
|
-
----------
|
|
112
|
-
source_id : IDType
|
|
113
|
-
The ID of the source to be removed.
|
|
114
|
-
|
|
115
|
-
Raises
|
|
116
|
-
------
|
|
117
|
-
ItemNotFoundError
|
|
118
|
-
If the given source ID is not present.
|
|
119
|
-
"""
|
|
120
|
-
if source_id not in self.sources:
|
|
121
|
-
raise ItemNotFoundError(f"Source {source_id} does not exist.")
|
|
122
|
-
self.sources.pop(source_id)
|
|
123
|
-
self.mails.pop(source_id)
|
|
124
|
-
|
|
125
|
-
def collect(self, sender: IDType) -> None:
|
|
126
|
-
"""
|
|
127
|
-
Collect outbound mail from a single source.
|
|
128
|
-
|
|
129
|
-
Parameters
|
|
130
|
-
----------
|
|
131
|
-
sender : IDType
|
|
132
|
-
The ID of the sender whose outbound mail is retrieved.
|
|
133
|
-
|
|
134
|
-
Raises
|
|
135
|
-
------
|
|
136
|
-
ItemNotFoundError
|
|
137
|
-
If the sender is not recognized.
|
|
138
|
-
"""
|
|
139
|
-
if sender not in self.sources:
|
|
140
|
-
raise ItemNotFoundError(f"Sender source {sender} does not exist.")
|
|
141
|
-
mailbox: Exchange = (
|
|
142
|
-
self.sources[sender]
|
|
143
|
-
if isinstance(self.sources[sender], Exchange)
|
|
144
|
-
else self.sources[sender].mailbox
|
|
145
|
-
)
|
|
146
|
-
while mailbox.pending_outs.size() > 0:
|
|
147
|
-
mail_id = mailbox.pending_outs.popleft()
|
|
148
|
-
mail: Mail = mailbox.pile_.pop(mail_id)
|
|
149
|
-
if mail.recipient not in self.sources:
|
|
150
|
-
rec_ = mail.recipient
|
|
151
|
-
raise ItemNotFoundError(
|
|
152
|
-
f"Recipient source {rec_} does not exist"
|
|
153
|
-
)
|
|
154
|
-
if mail.sender not in self.mails[mail.recipient]:
|
|
155
|
-
self.mails[mail.recipient].update({mail.sender: deque()})
|
|
156
|
-
self.mails[mail.recipient][mail.sender].append(mail)
|
|
157
|
-
|
|
158
|
-
def send(self, recipient: IDType) -> None:
|
|
159
|
-
"""
|
|
160
|
-
Send any pending mail to a specified recipient.
|
|
161
|
-
|
|
162
|
-
Parameters
|
|
163
|
-
----------
|
|
164
|
-
recipient : IDType
|
|
165
|
-
The ID of the recipient to which mail should be delivered.
|
|
166
|
-
|
|
167
|
-
Raises
|
|
168
|
-
------
|
|
169
|
-
ItemNotFoundError
|
|
170
|
-
If the recipient ID is not recognized.
|
|
171
|
-
"""
|
|
172
|
-
if recipient not in self.sources:
|
|
173
|
-
raise ItemNotFoundError(
|
|
174
|
-
f"Recipient source {recipient} does not exist."
|
|
175
|
-
)
|
|
176
|
-
if not self.mails[recipient]:
|
|
177
|
-
return
|
|
178
|
-
for key in list(self.mails[recipient].keys()):
|
|
179
|
-
pending_mails = self.mails[recipient].pop(key)
|
|
180
|
-
mailbox: Exchange = (
|
|
181
|
-
self.sources[recipient]
|
|
182
|
-
if isinstance(self.sources[recipient], Exchange)
|
|
183
|
-
else self.sources[recipient].mailbox
|
|
184
|
-
)
|
|
185
|
-
while pending_mails:
|
|
186
|
-
mail = pending_mails.popleft()
|
|
187
|
-
mailbox.include(mail, direction="in")
|
|
188
|
-
|
|
189
|
-
def collect_all(self) -> None:
|
|
190
|
-
"""
|
|
191
|
-
Collect outbound mail from all known sources.
|
|
192
|
-
"""
|
|
193
|
-
for source in self.sources:
|
|
194
|
-
self.collect(sender=source.id)
|
|
195
|
-
|
|
196
|
-
def send_all(self) -> None:
|
|
197
|
-
"""
|
|
198
|
-
Send mail to all known recipients who have pending items.
|
|
199
|
-
"""
|
|
200
|
-
for source in self.sources:
|
|
201
|
-
self.send(recipient=source.id)
|
|
202
|
-
|
|
203
|
-
async def execute(self, refresh_time: int = 1) -> None:
|
|
204
|
-
"""
|
|
205
|
-
Continuously collect and send mail in an asynchronous loop.
|
|
206
|
-
|
|
207
|
-
Parameters
|
|
208
|
-
----------
|
|
209
|
-
refresh_time : int, optional
|
|
210
|
-
Delay (in seconds) between each collect/send cycle.
|
|
211
|
-
"""
|
|
212
|
-
while not self.execute_stop:
|
|
213
|
-
self.collect_all()
|
|
214
|
-
self.send_all()
|
|
215
|
-
await asyncio.sleep(refresh_time)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
# File: lion_core/communication/manager.py
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
|
2
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
|
|
4
|
-
from enum import Enum
|
|
5
|
-
from typing import Any
|
|
6
|
-
|
|
7
|
-
from lionagi.ln import now_utc
|
|
8
|
-
from lionagi.protocols.generic.element import ID, IDType
|
|
9
|
-
|
|
10
|
-
from .._concepts import Communicatable, Observable
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class PackageCategory(str, Enum):
|
|
14
|
-
"""
|
|
15
|
-
Enumeration of common package categories in LionAGI:
|
|
16
|
-
|
|
17
|
-
- MESSAGE: General message content
|
|
18
|
-
- TOOL: A tool or action to be invoked
|
|
19
|
-
- IMODEL: Some internal model reference
|
|
20
|
-
- NODE: A node in a graph
|
|
21
|
-
- NODE_LIST: A list of nodes
|
|
22
|
-
- NODE_ID: A node ID
|
|
23
|
-
- START: A 'start' signal
|
|
24
|
-
- END: An 'end' signal
|
|
25
|
-
- CONDITION: A condition or gating logic
|
|
26
|
-
- SIGNAL: A more generic signal or marker
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
MESSAGE = "message"
|
|
30
|
-
TOOL = "tool"
|
|
31
|
-
IMODEL = "imodel"
|
|
32
|
-
NODE = "node"
|
|
33
|
-
NODE_LIST = "node_list"
|
|
34
|
-
NODE_ID = "node_id"
|
|
35
|
-
START = "start"
|
|
36
|
-
END = "end"
|
|
37
|
-
CONDITION = "condition"
|
|
38
|
-
SIGNAL = "signal"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def validate_category(value: Any) -> PackageCategory:
|
|
42
|
-
"""
|
|
43
|
-
Validate and convert the input to a valid PackageCategory.
|
|
44
|
-
|
|
45
|
-
Parameters
|
|
46
|
-
----------
|
|
47
|
-
value : Any
|
|
48
|
-
The input to interpret as a `PackageCategory`.
|
|
49
|
-
|
|
50
|
-
Returns
|
|
51
|
-
-------
|
|
52
|
-
PackageCategory
|
|
53
|
-
The validated category.
|
|
54
|
-
|
|
55
|
-
Raises
|
|
56
|
-
------
|
|
57
|
-
ValueError
|
|
58
|
-
If the value cannot be converted into a valid package category.
|
|
59
|
-
"""
|
|
60
|
-
if isinstance(value, PackageCategory):
|
|
61
|
-
return value
|
|
62
|
-
try:
|
|
63
|
-
return PackageCategory(str(value))
|
|
64
|
-
except ValueError as e:
|
|
65
|
-
raise ValueError("Invalid value for category.") from e
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class Package(Observable):
|
|
69
|
-
"""
|
|
70
|
-
A self-contained package that can be attached to `Mail` items.
|
|
71
|
-
Includes a unique ID, creation timestamp, category, payload item,
|
|
72
|
-
and an optional request source for context.
|
|
73
|
-
|
|
74
|
-
Attributes
|
|
75
|
-
----------
|
|
76
|
-
category : PackageCategory
|
|
77
|
-
The classification or type of package.
|
|
78
|
-
item : Any
|
|
79
|
-
The main payload or data of this package.
|
|
80
|
-
request_source : ID[Communicatable] | None
|
|
81
|
-
An optional reference indicating the origin or context
|
|
82
|
-
for this package.
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
__slots__ = ("id", "created_at", "category", "item", "request_source")
|
|
86
|
-
|
|
87
|
-
def __init__(
|
|
88
|
-
self,
|
|
89
|
-
category: PackageCategory,
|
|
90
|
-
item: Any,
|
|
91
|
-
request_source: ID[Communicatable] = None,
|
|
92
|
-
):
|
|
93
|
-
super().__init__()
|
|
94
|
-
self.id = IDType.create()
|
|
95
|
-
self.created_at = now_utc().timestamp()
|
|
96
|
-
self.category = validate_category(category)
|
|
97
|
-
self.item = item
|
|
98
|
-
self.request_source = request_source
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# File: lionagi/protocols/mail/package.py
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
## Rendering Templates
|
|
2
|
-
|
|
3
|
-
Once templates are defined, you can load and render them using Jinja2:
|
|
4
|
-
|
|
5
|
-
```python
|
|
6
|
-
from jinja2 import Environment, FileSystemLoader
|
|
7
|
-
|
|
8
|
-
env = Environment(loader=FileSystemLoader('templates'))
|
|
9
|
-
|
|
10
|
-
# Example: Rendering an instruction message
|
|
11
|
-
template = env.get_template('instruction_message.jinja2')
|
|
12
|
-
args = {
|
|
13
|
-
"guidance": "Please ensure accuracy.",
|
|
14
|
-
"instruction": "Summarize the document",
|
|
15
|
-
"context": ["Doc1: ...", "Doc2: ..."],
|
|
16
|
-
"request_fields": {"summary": "...", "key_points": "..."}
|
|
17
|
-
}
|
|
18
|
-
message_text = template.render(**args)
|
|
19
|
-
print(message_text)
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Benefits and Customization
|
|
23
|
-
• You can easily rearrange sections within these templates without changing your code logic.
|
|
24
|
-
• Each message type is clearly separated, making it simpler to maintain or adjust one message format without affecting the others.
|
|
25
|
-
• If you find that you use some snippet (like rendering a schema) in multiple templates, you can factor it out into its own partial template (like tool_schemas.jinja2) and include it where needed.
|
|
26
|
-
• Over time, you can add more templates or split existing ones if certain messages become too complex.
|
|
27
|
-
|
|
28
|
-
By establishing this set of base templates and arguments, you have a starting point. You can expand or refine as your requirements evolve.
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
{%- set content = [] -%}
|
|
2
|
-
|
|
3
|
-
{# If plain_content is provided, we use it directly. Otherwise, we build a text block from guidance, instruction, context, etc. #}
|
|
4
|
-
{% if plain_content %}
|
|
5
|
-
{% set content = content + [{"type": "text", "text": plain_content}] %}
|
|
6
|
-
{% else %}
|
|
7
|
-
{# Build a text block from the available sections #}
|
|
8
|
-
{% set text_block = "" %}
|
|
9
|
-
|
|
10
|
-
{% if guidance %}
|
|
11
|
-
## Guidance
|
|
12
|
-
{{ guidance }}
|
|
13
|
-
|
|
14
|
-
{% endif %}
|
|
15
|
-
|
|
16
|
-
{% if instruction %}
|
|
17
|
-
## Instruction
|
|
18
|
-
{{ instruction }}
|
|
19
|
-
|
|
20
|
-
{% endif %}
|
|
21
|
-
|
|
22
|
-
{% if context %}
|
|
23
|
-
## Context
|
|
24
|
-
{% for item in context %}
|
|
25
|
-
- {{ item }}
|
|
26
|
-
{% endfor %}
|
|
27
|
-
{% endif %}
|
|
28
|
-
|
|
29
|
-
{% if tool_schemas %}
|
|
30
|
-
## Tool Schemas
|
|
31
|
-
{% include "tool_schemas.jinja2" %}
|
|
32
|
-
{% endif %}
|
|
33
|
-
|
|
34
|
-
{% if request_fields %}
|
|
35
|
-
## Requested Fields
|
|
36
|
-
Please return a JSON object with the following fields:
|
|
37
|
-
```json
|
|
38
|
-
{{ request_fields | tojson(indent=2) }}
|
|
39
|
-
|
|
40
|
-
{% endif %}
|
|
41
|
-
|
|
42
|
-
{% if request_response_format %}
|
|
43
|
-
|
|
44
|
-
Response Format
|
|
45
|
-
|
|
46
|
-
{{ request_response_format }}
|
|
47
|
-
{% endif %}
|
|
48
|
-
|
|
49
|
-
{# Append the built sections into text_block #}
|
|
50
|
-
{% set text_block = text_block + self %}
|
|
51
|
-
{% set content = content + [{"type": "text", "text": text_block.strip()}] %}
|
|
52
|
-
{% endif %}
|
|
53
|
-
|
|
54
|
-
{# If images are present, we append image_url items to content #}
|
|
55
|
-
{% if images %}
|
|
56
|
-
{% for img in images %}
|
|
57
|
-
{% set content = content + [{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64," ~ img, "detail": image_detail}}] %}
|
|
58
|
-
{% endfor %}
|
|
59
|
-
{% endif %}
|
|
60
|
-
|
|
61
|
-
{{ content | tojson(indent=2) }}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
from .anthropic_ import AnthropicMessagesEndpoint
|
|
2
|
-
from .claude_code_cli import ClaudeCodeCLIEndpoint, ClaudeCodeRequest
|
|
3
|
-
from .exa_ import ExaSearchEndpoint, ExaSearchRequest
|
|
4
|
-
from .oai_ import (
|
|
5
|
-
GroqChatEndpoint,
|
|
6
|
-
OpenaiChatEndpoint,
|
|
7
|
-
OpenaiEmbedEndpoint,
|
|
8
|
-
OpenaiResponseEndpoint,
|
|
9
|
-
OpenrouterChatEndpoint,
|
|
10
|
-
)
|
|
11
|
-
from .ollama_ import OllamaChatEndpoint
|
|
12
|
-
from .perplexity_ import PerplexityChatEndpoint, PerplexityChatRequest
|
|
13
|
-
|
|
14
|
-
__all__ = (
|
|
15
|
-
"AnthropicMessagesEndpoint",
|
|
16
|
-
"ClaudeCodeRequest",
|
|
17
|
-
"ClaudeCodeCLIEndpoint",
|
|
18
|
-
"ExaSearchEndpoint",
|
|
19
|
-
"ExaSearchRequest",
|
|
20
|
-
"OpenaiChatEndpoint",
|
|
21
|
-
"OpenaiEmbedEndpoint",
|
|
22
|
-
"OpenaiResponseEndpoint",
|
|
23
|
-
"OpenrouterChatEndpoint",
|
|
24
|
-
"GroqChatEndpoint",
|
|
25
|
-
"OllamaChatEndpoint",
|
|
26
|
-
"PerplexityChatEndpoint",
|
|
27
|
-
"PerplexityChatRequest",
|
|
28
|
-
)
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
OpenAI Model Names extracted from generated models.
|
|
3
|
-
|
|
4
|
-
This module provides lists of allowed model names for different OpenAI services,
|
|
5
|
-
extracted from the auto-generated openai_models.py file.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from typing import Literal, get_args
|
|
9
|
-
|
|
10
|
-
# Manually define the chat models from the ChatModel class in openai_models.py
|
|
11
|
-
# These are extracted from the Literal type definition
|
|
12
|
-
CHAT_MODELS = [
|
|
13
|
-
"gpt-5",
|
|
14
|
-
"gpt-5-mini",
|
|
15
|
-
"gpt-5-nano",
|
|
16
|
-
"gpt-5-2025-08-07",
|
|
17
|
-
"gpt-5-mini-2025-08-07",
|
|
18
|
-
"gpt-5-nano-2025-08-07",
|
|
19
|
-
"gpt-5-chat-latest",
|
|
20
|
-
"gpt-4.1",
|
|
21
|
-
"gpt-4.1-mini",
|
|
22
|
-
"gpt-4.1-nano",
|
|
23
|
-
"gpt-4.1-2025-04-14",
|
|
24
|
-
"gpt-4.1-mini-2025-04-14",
|
|
25
|
-
"gpt-4.1-nano-2025-04-14",
|
|
26
|
-
"o4-mini",
|
|
27
|
-
"o4-mini-2025-04-16",
|
|
28
|
-
"o3",
|
|
29
|
-
"o3-2025-04-16",
|
|
30
|
-
"o3-mini",
|
|
31
|
-
"o3-mini-2025-01-31",
|
|
32
|
-
"o1",
|
|
33
|
-
"o1-2024-12-17",
|
|
34
|
-
"o1-preview",
|
|
35
|
-
"o1-preview-2024-09-12",
|
|
36
|
-
"o1-mini",
|
|
37
|
-
"o1-mini-2024-09-12",
|
|
38
|
-
"gpt-4o",
|
|
39
|
-
"gpt-4o-2024-11-20",
|
|
40
|
-
"gpt-4o-2024-08-06",
|
|
41
|
-
"gpt-4o-2024-05-13",
|
|
42
|
-
"gpt-4o-audio-preview",
|
|
43
|
-
"gpt-4o-audio-preview-2024-10-01",
|
|
44
|
-
"gpt-4o-audio-preview-2024-12-17",
|
|
45
|
-
"gpt-4o-audio-preview-2025-06-03",
|
|
46
|
-
"gpt-4o-mini-audio-preview",
|
|
47
|
-
"gpt-4o-mini-audio-preview-2024-12-17",
|
|
48
|
-
"gpt-4o-search-preview",
|
|
49
|
-
"gpt-4o-mini-search-preview",
|
|
50
|
-
"gpt-4o-search-preview-2025-03-11",
|
|
51
|
-
"gpt-4o-mini-search-preview-2025-03-11",
|
|
52
|
-
"chatgpt-4o-latest",
|
|
53
|
-
"codex-mini-latest",
|
|
54
|
-
"gpt-4o-mini",
|
|
55
|
-
"gpt-4o-mini-2024-07-18",
|
|
56
|
-
"gpt-4-turbo",
|
|
57
|
-
"gpt-4-turbo-2024-04-09",
|
|
58
|
-
"gpt-4-0125-preview",
|
|
59
|
-
"gpt-4-turbo-preview",
|
|
60
|
-
"gpt-4-1106-preview",
|
|
61
|
-
"gpt-4-vision-preview",
|
|
62
|
-
"gpt-4",
|
|
63
|
-
"gpt-4-0314",
|
|
64
|
-
"gpt-4-0613",
|
|
65
|
-
"gpt-4-32k",
|
|
66
|
-
"gpt-4-32k-0314",
|
|
67
|
-
"gpt-4-32k-0613",
|
|
68
|
-
"gpt-3.5-turbo",
|
|
69
|
-
"gpt-3.5-turbo-16k",
|
|
70
|
-
"gpt-3.5-turbo-0301",
|
|
71
|
-
"gpt-3.5-turbo-0613",
|
|
72
|
-
"gpt-3.5-turbo-1106",
|
|
73
|
-
"gpt-3.5-turbo-0125",
|
|
74
|
-
"gpt-3.5-turbo-16k-0613",
|
|
75
|
-
]
|
|
76
|
-
|
|
77
|
-
# Reasoning models (o1, o3, o4 series)
|
|
78
|
-
# Note: Add o1-pro models that may not be in the generated list yet
|
|
79
|
-
ADDITIONAL_REASONING_MODELS = [
|
|
80
|
-
"o1-pro",
|
|
81
|
-
"o1-pro-2025-03-19",
|
|
82
|
-
"o3-pro",
|
|
83
|
-
"o3-pro-2025-06-10",
|
|
84
|
-
]
|
|
85
|
-
|
|
86
|
-
REASONING_MODELS = [
|
|
87
|
-
model
|
|
88
|
-
for model in CHAT_MODELS
|
|
89
|
-
if model.startswith(("o1", "o1-", "o3", "o3-", "o4", "o4-", "gpt-5"))
|
|
90
|
-
] + ADDITIONAL_REASONING_MODELS
|
|
91
|
-
|
|
92
|
-
# GPT models (excluding reasoning models)
|
|
93
|
-
GPT_MODELS = [
|
|
94
|
-
model
|
|
95
|
-
for model in CHAT_MODELS
|
|
96
|
-
if model.startswith("gpt")
|
|
97
|
-
or model.startswith("chatgpt")
|
|
98
|
-
or model.startswith("codex")
|
|
99
|
-
]
|
|
100
|
-
|
|
101
|
-
# Embedding models
|
|
102
|
-
EMBEDDING_MODELS = [
|
|
103
|
-
"text-embedding-ada-002",
|
|
104
|
-
"text-embedding-3-small",
|
|
105
|
-
"text-embedding-3-large",
|
|
106
|
-
]
|
|
107
|
-
|
|
108
|
-
# Audio models
|
|
109
|
-
AUDIO_MODELS = {
|
|
110
|
-
"tts": ["tts-1", "tts-1-hd", "gpt-4o-mini-tts"],
|
|
111
|
-
"transcription": [
|
|
112
|
-
"whisper-1",
|
|
113
|
-
"gpt-4o-transcribe",
|
|
114
|
-
"gpt-4o-mini-transcribe",
|
|
115
|
-
],
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# Image models
|
|
119
|
-
IMAGE_MODELS = ["dall-e-2", "dall-e-3", "gpt-image-1"]
|
|
120
|
-
|
|
121
|
-
# Moderation models
|
|
122
|
-
MODERATION_MODELS = ["text-moderation-latest", "text-moderation-stable"]
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def is_reasoning_model(model: str) -> bool:
|
|
126
|
-
"""Check if a model is a reasoning model (o1/o3/o4 series)."""
|
|
127
|
-
return model in REASONING_MODELS
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def is_valid_chat_model(model: str) -> bool:
|
|
131
|
-
"""Check if a model is a valid chat model."""
|
|
132
|
-
return model in CHAT_MODELS
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def is_valid_embedding_model(model: str) -> bool:
|
|
136
|
-
"""Check if a model is a valid embedding model."""
|
|
137
|
-
return model in EMBEDDING_MODELS
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def get_model_category(model: str) -> str:
|
|
141
|
-
"""Get the category of a model."""
|
|
142
|
-
if model in REASONING_MODELS:
|
|
143
|
-
return "reasoning"
|
|
144
|
-
elif model in GPT_MODELS:
|
|
145
|
-
return "gpt"
|
|
146
|
-
elif model in EMBEDDING_MODELS:
|
|
147
|
-
return "embedding"
|
|
148
|
-
elif model in AUDIO_MODELS["tts"]:
|
|
149
|
-
return "tts"
|
|
150
|
-
elif model in AUDIO_MODELS["transcription"]:
|
|
151
|
-
return "transcription"
|
|
152
|
-
elif model in IMAGE_MODELS:
|
|
153
|
-
return "image"
|
|
154
|
-
elif model in MODERATION_MODELS:
|
|
155
|
-
return "moderation"
|
|
156
|
-
else:
|
|
157
|
-
return "unknown"
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def validate_model(model: str, category: str = None) -> bool:
|
|
161
|
-
"""
|
|
162
|
-
Validate if a model is valid, optionally checking category.
|
|
163
|
-
|
|
164
|
-
Args:
|
|
165
|
-
model: The model name to validate
|
|
166
|
-
category: Optional category to check against ('chat', 'embedding', etc.)
|
|
167
|
-
|
|
168
|
-
Returns:
|
|
169
|
-
True if model is valid (and in the specified category if provided)
|
|
170
|
-
"""
|
|
171
|
-
if category == "chat":
|
|
172
|
-
return model in CHAT_MODELS or model in ADDITIONAL_REASONING_MODELS
|
|
173
|
-
elif category == "reasoning":
|
|
174
|
-
return is_reasoning_model(model)
|
|
175
|
-
elif category == "embedding":
|
|
176
|
-
return is_valid_embedding_model(model)
|
|
177
|
-
elif category:
|
|
178
|
-
return get_model_category(model) == category
|
|
179
|
-
else:
|
|
180
|
-
# Check if model exists in any category
|
|
181
|
-
return get_model_category(model) != "unknown"
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
# Export all model lists
|
|
185
|
-
__all__ = [
|
|
186
|
-
"CHAT_MODELS",
|
|
187
|
-
"REASONING_MODELS",
|
|
188
|
-
"GPT_MODELS",
|
|
189
|
-
"EMBEDDING_MODELS",
|
|
190
|
-
"AUDIO_MODELS",
|
|
191
|
-
"IMAGE_MODELS",
|
|
192
|
-
"MODERATION_MODELS",
|
|
193
|
-
"is_reasoning_model",
|
|
194
|
-
"is_valid_chat_model",
|
|
195
|
-
"is_valid_embedding_model",
|
|
196
|
-
"get_model_category",
|
|
197
|
-
"validate_model",
|
|
198
|
-
]
|