lionagi 0.17.10__py3-none-any.whl → 0.18.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.
- lionagi/__init__.py +1 -2
- lionagi/_class_registry.py +1 -2
- lionagi/_errors.py +1 -2
- lionagi/adapters/async_postgres_adapter.py +2 -10
- lionagi/config.py +1 -2
- lionagi/fields/action.py +1 -2
- lionagi/fields/base.py +3 -0
- lionagi/fields/code.py +3 -0
- lionagi/fields/file.py +3 -0
- lionagi/fields/instruct.py +1 -2
- lionagi/fields/reason.py +1 -2
- lionagi/fields/research.py +3 -0
- lionagi/libs/__init__.py +1 -2
- lionagi/libs/file/__init__.py +1 -2
- lionagi/libs/file/chunk.py +1 -2
- lionagi/libs/file/process.py +1 -2
- lionagi/libs/schema/__init__.py +1 -2
- lionagi/libs/schema/as_readable.py +1 -2
- lionagi/libs/schema/extract_code_block.py +1 -2
- lionagi/libs/schema/extract_docstring.py +1 -2
- lionagi/libs/schema/function_to_schema.py +1 -2
- lionagi/libs/schema/load_pydantic_model_from_schema.py +1 -2
- lionagi/libs/schema/minimal_yaml.py +98 -0
- lionagi/libs/validate/__init__.py +1 -2
- lionagi/libs/validate/common_field_validators.py +1 -2
- lionagi/libs/validate/validate_boolean.py +1 -2
- lionagi/ln/fuzzy/_string_similarity.py +1 -2
- lionagi/ln/types.py +32 -5
- lionagi/models/__init__.py +1 -2
- lionagi/models/field_model.py +9 -1
- lionagi/models/hashable_model.py +4 -2
- lionagi/models/model_params.py +1 -2
- lionagi/models/operable_model.py +1 -2
- lionagi/models/schema_model.py +1 -2
- lionagi/operations/ReAct/ReAct.py +475 -239
- lionagi/operations/ReAct/__init__.py +1 -2
- lionagi/operations/ReAct/utils.py +4 -2
- lionagi/operations/__init__.py +1 -2
- lionagi/operations/act/__init__.py +2 -0
- lionagi/operations/act/act.py +206 -0
- lionagi/operations/brainstorm/__init__.py +1 -2
- lionagi/operations/brainstorm/brainstorm.py +1 -2
- lionagi/operations/brainstorm/prompt.py +1 -2
- lionagi/operations/builder.py +1 -2
- lionagi/operations/chat/__init__.py +1 -2
- lionagi/operations/chat/chat.py +131 -116
- lionagi/operations/communicate/communicate.py +102 -44
- lionagi/operations/flow.py +5 -6
- lionagi/operations/instruct/__init__.py +1 -2
- lionagi/operations/instruct/instruct.py +1 -2
- lionagi/operations/interpret/__init__.py +1 -2
- lionagi/operations/interpret/interpret.py +66 -22
- lionagi/operations/operate/__init__.py +1 -2
- lionagi/operations/operate/operate.py +213 -108
- lionagi/operations/parse/__init__.py +1 -2
- lionagi/operations/parse/parse.py +171 -144
- lionagi/operations/plan/__init__.py +1 -2
- lionagi/operations/plan/plan.py +1 -2
- lionagi/operations/plan/prompt.py +1 -2
- lionagi/operations/select/__init__.py +1 -2
- lionagi/operations/select/select.py +79 -19
- lionagi/operations/select/utils.py +2 -3
- lionagi/operations/types.py +120 -25
- lionagi/operations/utils.py +1 -2
- lionagi/protocols/__init__.py +1 -2
- lionagi/protocols/_concepts.py +1 -2
- lionagi/protocols/action/__init__.py +1 -2
- lionagi/protocols/action/function_calling.py +3 -20
- lionagi/protocols/action/manager.py +34 -4
- lionagi/protocols/action/tool.py +1 -2
- lionagi/protocols/contracts.py +1 -2
- lionagi/protocols/forms/__init__.py +1 -2
- lionagi/protocols/forms/base.py +1 -2
- lionagi/protocols/forms/flow.py +1 -2
- lionagi/protocols/forms/form.py +1 -2
- lionagi/protocols/forms/report.py +1 -2
- lionagi/protocols/generic/__init__.py +1 -2
- lionagi/protocols/generic/element.py +17 -65
- lionagi/protocols/generic/event.py +1 -2
- lionagi/protocols/generic/log.py +17 -14
- lionagi/protocols/generic/pile.py +3 -4
- lionagi/protocols/generic/processor.py +1 -2
- lionagi/protocols/generic/progression.py +1 -2
- lionagi/protocols/graph/__init__.py +1 -2
- lionagi/protocols/graph/edge.py +1 -2
- lionagi/protocols/graph/graph.py +1 -2
- lionagi/protocols/graph/node.py +1 -2
- lionagi/protocols/ids.py +1 -2
- lionagi/protocols/mail/__init__.py +1 -2
- lionagi/protocols/mail/exchange.py +1 -2
- lionagi/protocols/mail/mail.py +1 -2
- lionagi/protocols/mail/mailbox.py +1 -2
- lionagi/protocols/mail/manager.py +1 -2
- lionagi/protocols/mail/package.py +1 -2
- lionagi/protocols/messages/__init__.py +28 -2
- lionagi/protocols/messages/action_request.py +87 -186
- lionagi/protocols/messages/action_response.py +74 -133
- lionagi/protocols/messages/assistant_response.py +131 -161
- lionagi/protocols/messages/base.py +27 -20
- lionagi/protocols/messages/instruction.py +281 -626
- lionagi/protocols/messages/manager.py +113 -64
- lionagi/protocols/messages/message.py +88 -199
- lionagi/protocols/messages/system.py +53 -125
- lionagi/protocols/operatives/__init__.py +1 -2
- lionagi/protocols/operatives/operative.py +1 -2
- lionagi/protocols/operatives/step.py +1 -2
- lionagi/protocols/types.py +1 -4
- lionagi/service/connections/__init__.py +1 -2
- lionagi/service/connections/api_calling.py +1 -2
- lionagi/service/connections/endpoint.py +1 -10
- lionagi/service/connections/endpoint_config.py +1 -2
- lionagi/service/connections/header_factory.py +1 -2
- lionagi/service/connections/match_endpoint.py +1 -2
- lionagi/service/connections/mcp/__init__.py +1 -2
- lionagi/service/connections/mcp/wrapper.py +1 -2
- lionagi/service/connections/providers/__init__.py +1 -2
- lionagi/service/connections/providers/anthropic_.py +1 -2
- lionagi/service/connections/providers/claude_code_cli.py +1 -2
- lionagi/service/connections/providers/exa_.py +1 -2
- lionagi/service/connections/providers/nvidia_nim_.py +2 -27
- lionagi/service/connections/providers/oai_.py +30 -96
- lionagi/service/connections/providers/ollama_.py +4 -4
- lionagi/service/connections/providers/perplexity_.py +1 -2
- lionagi/service/hooks/__init__.py +1 -1
- lionagi/service/hooks/_types.py +1 -1
- lionagi/service/hooks/_utils.py +1 -1
- lionagi/service/hooks/hook_event.py +1 -1
- lionagi/service/hooks/hook_registry.py +1 -1
- lionagi/service/hooks/hooked_event.py +3 -4
- lionagi/service/imodel.py +1 -2
- lionagi/service/manager.py +1 -2
- lionagi/service/rate_limited_processor.py +1 -2
- lionagi/service/resilience.py +1 -2
- lionagi/service/third_party/anthropic_models.py +1 -2
- lionagi/service/third_party/claude_code.py +4 -4
- lionagi/service/third_party/openai_models.py +433 -0
- lionagi/service/token_calculator.py +1 -2
- lionagi/session/__init__.py +1 -2
- lionagi/session/branch.py +171 -180
- lionagi/session/session.py +4 -11
- lionagi/tools/__init__.py +1 -2
- lionagi/tools/base.py +1 -2
- lionagi/tools/file/__init__.py +1 -2
- lionagi/tools/file/reader.py +3 -4
- lionagi/tools/types.py +1 -2
- lionagi/utils.py +1 -2
- lionagi/version.py +1 -1
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/METADATA +1 -2
- lionagi-0.18.0.dist-info/RECORD +191 -0
- lionagi/operations/_act/__init__.py +0 -3
- lionagi/operations/_act/act.py +0 -87
- 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/service/connections/providers/types.py +0 -28
- lionagi/service/third_party/openai_model_names.py +0 -198
- lionagi/service/types.py +0 -59
- lionagi-0.17.10.dist-info/RECORD +0 -199
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/WHEEL +0 -0
- {lionagi-0.17.10.dist-info → lionagi-0.18.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,4 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
4
3
|
|
5
4
|
from typing import ClassVar, Literal
|
@@ -102,6 +101,9 @@ class ReActAnalysis(HashableModel):
|
|
102
101
|
),
|
103
102
|
)
|
104
103
|
|
104
|
+
# Note: action_requests and action_responses are added dynamically by Step.request_operative()
|
105
|
+
# when actions=True, so they don't need to be defined here. The operate() function will add them.
|
106
|
+
|
105
107
|
|
106
108
|
class Analysis(HashableModel):
|
107
109
|
answer: str | None = None
|
lionagi/operations/__init__.py
CHANGED
@@ -0,0 +1,206 @@
|
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
3
|
+
|
4
|
+
import logging
|
5
|
+
from typing import TYPE_CHECKING, Literal
|
6
|
+
|
7
|
+
from pydantic import BaseModel
|
8
|
+
|
9
|
+
from lionagi.fields.action import ActionResponseModel
|
10
|
+
from lionagi.ln._async_call import AlcallParams
|
11
|
+
from lionagi.protocols.types import ActionRequest, ActionResponse
|
12
|
+
|
13
|
+
from ..types import ActionParam
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from lionagi.session.branch import Branch
|
17
|
+
|
18
|
+
_DEFAULT_ALCALL_PARAMS = None
|
19
|
+
|
20
|
+
|
21
|
+
async def _act(
|
22
|
+
branch: "Branch",
|
23
|
+
action_request: BaseModel | dict | ActionRequest,
|
24
|
+
suppress_errors: bool = False,
|
25
|
+
verbose_action: bool = False,
|
26
|
+
):
|
27
|
+
|
28
|
+
_request = action_request
|
29
|
+
if isinstance(action_request, ActionRequest):
|
30
|
+
_request = {
|
31
|
+
"function": action_request.function,
|
32
|
+
"arguments": action_request.arguments,
|
33
|
+
}
|
34
|
+
elif isinstance(action_request, BaseModel) and set(
|
35
|
+
action_request.__class__.model_fields.keys()
|
36
|
+
) >= {"function", "arguments"}:
|
37
|
+
_request = {
|
38
|
+
"function": action_request.function,
|
39
|
+
"arguments": action_request.arguments,
|
40
|
+
}
|
41
|
+
if not isinstance(_request, dict) or not {"function", "arguments"} <= set(
|
42
|
+
_request.keys()
|
43
|
+
):
|
44
|
+
raise ValueError(
|
45
|
+
"action_request must be an ActionRequest, BaseModel with 'function'"
|
46
|
+
" and 'arguments', or dict with 'function' and 'arguments'."
|
47
|
+
)
|
48
|
+
|
49
|
+
try:
|
50
|
+
if verbose_action:
|
51
|
+
args_ = str(_request["arguments"])
|
52
|
+
args_ = args_[:50] + "..." if len(args_) > 50 else args_
|
53
|
+
print(f"Invoking action {_request['function']} with {args_}.")
|
54
|
+
|
55
|
+
func_call = await branch._action_manager.invoke(_request)
|
56
|
+
if verbose_action:
|
57
|
+
print(
|
58
|
+
f"Action {_request['function']} invoked, status: {func_call.status}."
|
59
|
+
)
|
60
|
+
|
61
|
+
except Exception as e:
|
62
|
+
content = {
|
63
|
+
"error": str(e),
|
64
|
+
"function": _request.get("function"),
|
65
|
+
"arguments": _request.get("arguments"),
|
66
|
+
"branch": str(branch.id),
|
67
|
+
}
|
68
|
+
branch._log_manager.log(content)
|
69
|
+
if verbose_action:
|
70
|
+
print(f"Action {_request['function']} failed, error: {str(e)}.")
|
71
|
+
if suppress_errors:
|
72
|
+
error_msg = f"Error invoking action '{_request['function']}': {e}"
|
73
|
+
logging.error(error_msg)
|
74
|
+
|
75
|
+
# Return error as action response so model knows it failed
|
76
|
+
return ActionResponseModel(
|
77
|
+
function=_request.get("function", "unknown"),
|
78
|
+
arguments=_request.get("arguments", {}),
|
79
|
+
output={"error": str(e), "message": error_msg},
|
80
|
+
)
|
81
|
+
raise e
|
82
|
+
|
83
|
+
branch._log_manager.log(func_call)
|
84
|
+
|
85
|
+
if not isinstance(action_request, ActionRequest):
|
86
|
+
action_request = ActionRequest(
|
87
|
+
content=_request,
|
88
|
+
sender=branch.id,
|
89
|
+
recipient=func_call.func_tool.id,
|
90
|
+
)
|
91
|
+
|
92
|
+
# Add the action request/response to the message manager, if not present
|
93
|
+
if action_request not in branch.messages:
|
94
|
+
branch.msgs.add_message(action_request=action_request)
|
95
|
+
|
96
|
+
branch.msgs.add_message(
|
97
|
+
action_request=action_request,
|
98
|
+
action_output=func_call.response,
|
99
|
+
)
|
100
|
+
|
101
|
+
return ActionResponseModel(
|
102
|
+
function=action_request.function,
|
103
|
+
arguments=action_request.arguments,
|
104
|
+
output=func_call.response,
|
105
|
+
)
|
106
|
+
|
107
|
+
|
108
|
+
def prepare_act_kw(
|
109
|
+
branch: "Branch",
|
110
|
+
action_request: list | ActionRequest | BaseModel | dict,
|
111
|
+
*,
|
112
|
+
strategy: Literal["concurrent", "sequential"] = "concurrent",
|
113
|
+
verbose_action: bool = False,
|
114
|
+
suppress_errors: bool = True,
|
115
|
+
call_params: AlcallParams = None,
|
116
|
+
):
|
117
|
+
|
118
|
+
action_param = ActionParam(
|
119
|
+
action_call_params=call_params or _get_default_call_params(),
|
120
|
+
tools=None, # Not used in this context
|
121
|
+
strategy=strategy,
|
122
|
+
suppress_errors=suppress_errors,
|
123
|
+
verbose_action=verbose_action,
|
124
|
+
)
|
125
|
+
return {
|
126
|
+
"action_request": action_request,
|
127
|
+
"action_param": action_param,
|
128
|
+
}
|
129
|
+
|
130
|
+
|
131
|
+
async def act(
|
132
|
+
branch: "Branch",
|
133
|
+
action_request: list | ActionRequest | BaseModel | dict,
|
134
|
+
action_param: ActionParam,
|
135
|
+
) -> list[ActionResponse]:
|
136
|
+
"""Execute action requests with ActionParam."""
|
137
|
+
|
138
|
+
match action_param.strategy:
|
139
|
+
case "concurrent":
|
140
|
+
return await _concurrent_act(
|
141
|
+
branch,
|
142
|
+
action_request,
|
143
|
+
action_param.action_call_params,
|
144
|
+
suppress_errors=action_param.suppress_errors,
|
145
|
+
verbose_action=action_param.verbose_action,
|
146
|
+
)
|
147
|
+
case "sequential":
|
148
|
+
return await _sequential_act(
|
149
|
+
branch,
|
150
|
+
action_request,
|
151
|
+
suppress_errors=action_param.suppress_errors,
|
152
|
+
verbose_action=action_param.verbose_action,
|
153
|
+
)
|
154
|
+
case _:
|
155
|
+
raise ValueError(
|
156
|
+
"Invalid strategy. Choose 'concurrent' or 'sequential'."
|
157
|
+
)
|
158
|
+
|
159
|
+
|
160
|
+
async def _concurrent_act(
|
161
|
+
branch: "Branch",
|
162
|
+
action_request: list | ActionRequest | BaseModel | dict,
|
163
|
+
call_params: AlcallParams,
|
164
|
+
suppress_errors: bool = True,
|
165
|
+
verbose_action: bool = False,
|
166
|
+
) -> list:
|
167
|
+
"""Execute actions concurrently using AlcallParams."""
|
168
|
+
|
169
|
+
async def _wrapper(req):
|
170
|
+
return await _act(branch, req, suppress_errors, verbose_action)
|
171
|
+
|
172
|
+
# AlcallParams expects a list as first argument
|
173
|
+
action_request_list = (
|
174
|
+
action_request
|
175
|
+
if isinstance(action_request, list)
|
176
|
+
else [action_request]
|
177
|
+
)
|
178
|
+
|
179
|
+
return await call_params(action_request_list, _wrapper)
|
180
|
+
|
181
|
+
|
182
|
+
async def _sequential_act(
|
183
|
+
branch: "Branch",
|
184
|
+
action_request: list | ActionRequest | BaseModel | dict,
|
185
|
+
suppress_errors: bool = True,
|
186
|
+
verbose_action: bool = False,
|
187
|
+
) -> list:
|
188
|
+
"""Execute actions sequentially."""
|
189
|
+
action_request = (
|
190
|
+
action_request
|
191
|
+
if isinstance(action_request, list)
|
192
|
+
else [action_request]
|
193
|
+
)
|
194
|
+
results = []
|
195
|
+
for req in action_request:
|
196
|
+
result = await _act(branch, req, suppress_errors, verbose_action)
|
197
|
+
results.append(result)
|
198
|
+
return results
|
199
|
+
|
200
|
+
|
201
|
+
def _get_default_call_params() -> AlcallParams:
|
202
|
+
"""Get or create default AlcallParams."""
|
203
|
+
global _DEFAULT_ALCALL_PARAMS
|
204
|
+
if _DEFAULT_ALCALL_PARAMS is None:
|
205
|
+
_DEFAULT_ALCALL_PARAMS = AlcallParams(output_dropna=True)
|
206
|
+
return _DEFAULT_ALCALL_PARAMS
|
@@ -1,5 +1,4 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
4
3
|
|
5
4
|
PROMPT = """Perform a brainstorm session. Generate {num_instruct} concise and distinct instructions (Instruct), each representing a potential next step. We will run them in parallel under the same context. Ensure each idea:
|
lionagi/operations/builder.py
CHANGED
lionagi/operations/chat/chat.py
CHANGED
@@ -1,20 +1,18 @@
|
|
1
|
-
# Copyright (c) 2023
|
2
|
-
#
|
1
|
+
# Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
|
3
2
|
# SPDX-License-Identifier: Apache-2.0
|
4
3
|
|
5
|
-
from typing import TYPE_CHECKING
|
4
|
+
from typing import TYPE_CHECKING
|
6
5
|
|
7
|
-
from pydantic import
|
6
|
+
from pydantic import JsonValue
|
8
7
|
|
9
|
-
from lionagi.
|
8
|
+
from lionagi.ln._to_list import to_list
|
9
|
+
from lionagi.protocols.messages import (
|
10
10
|
ActionResponse,
|
11
11
|
AssistantResponse,
|
12
12
|
Instruction,
|
13
|
-
Log,
|
14
|
-
RoledMessage,
|
15
13
|
)
|
16
|
-
|
17
|
-
from
|
14
|
+
|
15
|
+
from ..types import ChatParam
|
18
16
|
|
19
17
|
if TYPE_CHECKING:
|
20
18
|
from lionagi.session.branch import Branch
|
@@ -22,98 +20,94 @@ if TYPE_CHECKING:
|
|
22
20
|
|
23
21
|
async def chat(
|
24
22
|
branch: "Branch",
|
25
|
-
instruction
|
26
|
-
|
27
|
-
context=None,
|
28
|
-
sender=None,
|
29
|
-
recipient=None,
|
30
|
-
request_fields=None,
|
31
|
-
response_format: type[BaseModel] = None,
|
32
|
-
progression=None,
|
33
|
-
imodel: iModel = None,
|
34
|
-
tool_schemas=None,
|
35
|
-
images: list = None,
|
36
|
-
image_detail: Literal["low", "high", "auto"] = None,
|
37
|
-
plain_content: str = None,
|
23
|
+
instruction: JsonValue | Instruction,
|
24
|
+
chat_param: ChatParam,
|
38
25
|
return_ins_res_message: bool = False,
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
recipient=recipient or branch.id,
|
48
|
-
response_format=response_format,
|
49
|
-
request_fields=request_fields,
|
50
|
-
images=images,
|
51
|
-
image_detail=image_detail,
|
52
|
-
tool_schemas=tool_schemas,
|
53
|
-
plain_content=plain_content,
|
26
|
+
) -> tuple[Instruction, AssistantResponse] | str:
|
27
|
+
params = chat_param.to_dict(
|
28
|
+
exclude={
|
29
|
+
"imodel",
|
30
|
+
"imodel_kw",
|
31
|
+
"include_token_usage_to_model",
|
32
|
+
"progression",
|
33
|
+
}
|
54
34
|
)
|
35
|
+
params["sender"] = chat_param.sender or branch.user or "user"
|
36
|
+
params["recipient"] = chat_param.recipient or branch.id
|
37
|
+
params["instruction"] = instruction
|
55
38
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
if isinstance(i, AssistantResponse):
|
69
|
-
j = AssistantResponse(
|
70
|
-
role=i.role,
|
71
|
-
content=copy(i.content),
|
72
|
-
sender=i.sender,
|
73
|
-
recipient=i.recipient,
|
74
|
-
template=i.template,
|
75
|
-
)
|
76
|
-
_to_use.append(j)
|
77
|
-
if isinstance(i, Instruction):
|
78
|
-
j = Instruction(
|
79
|
-
role=i.role,
|
80
|
-
content=copy(i.content),
|
81
|
-
sender=i.sender,
|
82
|
-
recipient=i.recipient,
|
83
|
-
template=i.template,
|
39
|
+
ins = branch.msgs.create_instruction(**params)
|
40
|
+
|
41
|
+
_use_ins, _use_msgs, _act_res = None, [], []
|
42
|
+
progression = chat_param.progression or branch.msgs.progression
|
43
|
+
|
44
|
+
for msg in (branch.msgs.messages[j] for j in progression):
|
45
|
+
if isinstance(msg, ActionResponse):
|
46
|
+
_act_res.append(msg)
|
47
|
+
|
48
|
+
if isinstance(msg, AssistantResponse):
|
49
|
+
_use_msgs.append(
|
50
|
+
msg.model_copy(update={"content": msg.content.with_updates()})
|
84
51
|
)
|
85
|
-
j.tool_schemas = None
|
86
|
-
j.respond_schema_info = None
|
87
|
-
j.request_response_format = None
|
88
|
-
|
89
|
-
if _action_responses:
|
90
|
-
d_ = [k.content for k in _action_responses]
|
91
|
-
for z in d_:
|
92
|
-
if z not in j.context:
|
93
|
-
j.context.append(z)
|
94
|
-
|
95
|
-
_to_use.append(j)
|
96
|
-
_action_responses = set()
|
97
|
-
else:
|
98
|
-
_to_use.append(j)
|
99
52
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
53
|
+
if isinstance(msg, Instruction):
|
54
|
+
j = msg.model_copy(update={"content": msg.content.with_updates()})
|
55
|
+
j.content.tool_schemas.clear()
|
56
|
+
j.content.response_format = None
|
57
|
+
j.content._schema_dict = None
|
58
|
+
j.content._model_class = None
|
59
|
+
|
60
|
+
if _act_res:
|
61
|
+
# Convert ActionResponseContent to dicts for proper rendering
|
62
|
+
d_ = []
|
63
|
+
for k in to_list(_act_res, flatten=True, unique=True):
|
64
|
+
if hasattr(k.content, "function"): # ActionResponseContent
|
65
|
+
d_.append(
|
66
|
+
{
|
67
|
+
"function": k.content.function,
|
68
|
+
"arguments": k.content.arguments,
|
69
|
+
"output": k.content.output,
|
70
|
+
}
|
71
|
+
)
|
72
|
+
else:
|
73
|
+
d_.append(k.content)
|
74
|
+
j.content.prompt_context.extend(
|
75
|
+
[z for z in d_ if z not in j.content.prompt_context]
|
76
|
+
)
|
77
|
+
_use_msgs.append(j)
|
78
|
+
_act_res = []
|
79
|
+
else:
|
80
|
+
_use_msgs.append(j)
|
81
|
+
|
82
|
+
if _act_res:
|
83
|
+
j = ins.model_copy(update={"content": ins.content.with_updates()})
|
84
|
+
# Convert ActionResponseContent to dicts for proper rendering
|
85
|
+
d_ = []
|
86
|
+
for k in to_list(_act_res, flatten=True, unique=True):
|
87
|
+
if hasattr(k.content, "function"): # ActionResponseContent
|
88
|
+
d_.append(
|
89
|
+
{
|
90
|
+
"function": k.content.function,
|
91
|
+
"arguments": k.content.arguments,
|
92
|
+
"output": k.content.output,
|
93
|
+
}
|
94
|
+
)
|
95
|
+
else:
|
96
|
+
d_.append(k.content)
|
97
|
+
j.content.prompt_context.extend(
|
98
|
+
[z for z in d_ if z not in j.content.prompt_context]
|
99
|
+
)
|
100
|
+
_use_ins = j
|
108
101
|
|
109
|
-
|
110
|
-
|
102
|
+
messages = _use_msgs
|
103
|
+
if _use_msgs and len(_use_msgs) > 1:
|
104
|
+
_msgs = [_use_msgs[0]]
|
111
105
|
|
112
|
-
for i in
|
106
|
+
for i in _use_msgs[1:]:
|
113
107
|
if isinstance(i, AssistantResponse):
|
114
108
|
if isinstance(_msgs[-1], AssistantResponse):
|
115
|
-
_msgs[-1].
|
116
|
-
f"{_msgs[-1].
|
109
|
+
_msgs[-1].content.assistant_response = (
|
110
|
+
f"{_msgs[-1].content.assistant_response}\n\n{i.content.assistant_response}"
|
117
111
|
)
|
118
112
|
else:
|
119
113
|
_msgs.append(i)
|
@@ -126,11 +120,10 @@ async def chat(
|
|
126
120
|
if branch.msgs.system:
|
127
121
|
messages = [msg for msg in messages if msg.role != "system"]
|
128
122
|
first_instruction = None
|
129
|
-
|
123
|
+
f = lambda x: branch.msgs.system.rendered + (x.content.guidance or "")
|
130
124
|
if len(messages) == 0:
|
131
|
-
first_instruction = ins.model_copy(
|
132
|
-
|
133
|
-
first_instruction.guidance or ""
|
125
|
+
first_instruction = ins.model_copy(
|
126
|
+
update={"content": ins.content.with_updates(guidance=f(ins))}
|
134
127
|
)
|
135
128
|
messages.append(first_instruction)
|
136
129
|
elif len(messages) >= 1:
|
@@ -139,37 +132,59 @@ async def chat(
|
|
139
132
|
raise ValueError(
|
140
133
|
"First message in progression must be an Instruction or System"
|
141
134
|
)
|
142
|
-
first_instruction = first_instruction.model_copy(
|
143
|
-
|
144
|
-
|
135
|
+
first_instruction = first_instruction.model_copy(
|
136
|
+
update={
|
137
|
+
"content": first_instruction.content.with_updates(
|
138
|
+
guidance=f(first_instruction)
|
139
|
+
)
|
140
|
+
}
|
145
141
|
)
|
146
142
|
messages[0] = first_instruction
|
147
|
-
|
143
|
+
msg_to_append = _use_ins or ins
|
144
|
+
if msg_to_append is not None:
|
145
|
+
messages.append(msg_to_append)
|
148
146
|
|
149
147
|
else:
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
148
|
+
msg_to_append = _use_ins or ins
|
149
|
+
if msg_to_append is not None:
|
150
|
+
messages.append(msg_to_append)
|
151
|
+
|
152
|
+
kw = (chat_param.imodel_kw or {}).copy()
|
153
|
+
|
154
|
+
# Filter out messages with None chat_msg
|
155
|
+
chat_msgs = []
|
156
|
+
for msg in messages:
|
157
|
+
if msg is not None and hasattr(msg, "chat_msg"):
|
158
|
+
chat_msg = msg.chat_msg
|
159
|
+
if chat_msg is not None:
|
160
|
+
chat_msgs.append(chat_msg)
|
161
|
+
|
162
|
+
kw["messages"] = chat_msgs
|
163
|
+
|
164
|
+
imodel = chat_param.imodel or branch.chat_model
|
165
|
+
meth = imodel.stream if "stream" in kw and kw["stream"] else imodel.invoke
|
166
|
+
|
167
|
+
if meth is imodel.invoke:
|
168
|
+
# Only set if it's not the Unset sentinel value
|
169
|
+
if not chat_param._is_sentinel(
|
170
|
+
chat_param.include_token_usage_to_model
|
171
|
+
):
|
172
|
+
kw["include_token_usage_to_model"] = (
|
173
|
+
chat_param.include_token_usage_to_model
|
174
|
+
)
|
175
|
+
api_call = await meth(**kw)
|
160
176
|
|
161
|
-
api_call
|
162
|
-
branch._log_manager.log(Log.create(api_call))
|
177
|
+
branch._log_manager.log(api_call)
|
163
178
|
|
164
179
|
if return_ins_res_message:
|
165
180
|
# Wrap result in `AssistantResponse` and return
|
166
|
-
return ins, AssistantResponse.
|
167
|
-
|
181
|
+
return ins, AssistantResponse.from_response(
|
182
|
+
api_call.response,
|
168
183
|
sender=branch.id,
|
169
184
|
recipient=branch.user,
|
170
185
|
)
|
171
|
-
return AssistantResponse.
|
172
|
-
|
186
|
+
return AssistantResponse.from_response(
|
187
|
+
api_call.response,
|
173
188
|
sender=branch.id,
|
174
189
|
recipient=branch.user,
|
175
190
|
).response
|