grasp_agents 0.3.3__py3-none-any.whl → 0.3.5__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.
- grasp_agents/llm.py +26 -23
- grasp_agents/llm_agent.py +34 -34
- grasp_agents/printer.py +1 -1
- grasp_agents/prompt_builder.py +2 -7
- grasp_agents/run_context.py +2 -2
- grasp_agents/utils.py +12 -9
- {grasp_agents-0.3.3.dist-info → grasp_agents-0.3.5.dist-info}/METADATA +1 -1
- {grasp_agents-0.3.3.dist-info → grasp_agents-0.3.5.dist-info}/RECORD +10 -10
- {grasp_agents-0.3.3.dist-info → grasp_agents-0.3.5.dist-info}/WHEEL +0 -0
- {grasp_agents-0.3.3.dist-info → grasp_agents-0.3.5.dist-info}/licenses/LICENSE.md +0 -0
grasp_agents/llm.py
CHANGED
@@ -39,7 +39,7 @@ class LLM(ABC, Generic[SettingsT_co, ConvertT_co]):
|
|
39
39
|
model_id: str | None = None,
|
40
40
|
llm_settings: SettingsT_co | None = None,
|
41
41
|
tools: list[BaseTool[BaseModel, Any, Any]] | None = None,
|
42
|
-
response_format:
|
42
|
+
response_format: Any | Mapping[str, Any] | None = None,
|
43
43
|
**kwargs: Any,
|
44
44
|
) -> None:
|
45
45
|
super().__init__()
|
@@ -51,15 +51,19 @@ class LLM(ABC, Generic[SettingsT_co, ConvertT_co]):
|
|
51
51
|
self._llm_settings: SettingsT_co = llm_settings or cast("SettingsT_co", {})
|
52
52
|
|
53
53
|
self._response_format = response_format
|
54
|
-
self._response_format_adapter:
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
self._response_format_adapter: (
|
55
|
+
TypeAdapter[Any] | Mapping[str, TypeAdapter[Any]]
|
56
|
+
) = self._get_response_format_adapter(response_format=response_format)
|
57
|
+
|
58
|
+
@staticmethod
|
59
|
+
def _get_response_format_adapter(
|
60
|
+
response_format: Any | Mapping[str, Any] | None = None,
|
61
|
+
) -> TypeAdapter[Any] | Mapping[str, TypeAdapter[Any]]:
|
62
|
+
if response_format is None:
|
63
|
+
return TypeAdapter(Any)
|
64
|
+
if isinstance(response_format, Mapping):
|
65
|
+
return {k: TypeAdapter(v) for k, v in response_format.items()} # type: ignore[return-value]
|
66
|
+
return TypeAdapter(response_format)
|
63
67
|
|
64
68
|
@property
|
65
69
|
def model_id(self) -> str:
|
@@ -74,23 +78,24 @@ class LLM(ABC, Generic[SettingsT_co, ConvertT_co]):
|
|
74
78
|
return self._llm_settings
|
75
79
|
|
76
80
|
@property
|
77
|
-
def
|
78
|
-
return self.
|
81
|
+
def response_format(self) -> Any | Mapping[str, Any] | None:
|
82
|
+
return self._response_format
|
83
|
+
|
84
|
+
@response_format.setter
|
85
|
+
def response_format(self, response_format: Any | Mapping[str, Any] | None) -> None:
|
86
|
+
self._response_format = response_format
|
87
|
+
self._response_format_adapter = self._get_response_format_adapter(
|
88
|
+
response_format
|
89
|
+
)
|
79
90
|
|
80
91
|
@property
|
81
|
-
def
|
82
|
-
return self.
|
92
|
+
def tools(self) -> dict[str, BaseTool[BaseModel, Any, Any]] | None:
|
93
|
+
return self._tools
|
83
94
|
|
84
95
|
@tools.setter
|
85
96
|
def tools(self, tools: list[BaseTool[BaseModel, Any, Any]] | None) -> None:
|
86
97
|
self._tools = {t.name: t for t in tools} if tools else None
|
87
98
|
|
88
|
-
@response_format.setter
|
89
|
-
def response_format(
|
90
|
-
self, response_format: type | Mapping[str, type] | None
|
91
|
-
) -> None:
|
92
|
-
self._response_format = response_format
|
93
|
-
|
94
99
|
def __repr__(self) -> str:
|
95
100
|
return (
|
96
101
|
f"{type(self).__name__}(model_id={self.model_id}; "
|
@@ -101,9 +106,7 @@ class LLM(ABC, Generic[SettingsT_co, ConvertT_co]):
|
|
101
106
|
for message in completion.messages:
|
102
107
|
if not message.tool_calls:
|
103
108
|
validate_obj_from_json_or_py_string(
|
104
|
-
message.content or "",
|
105
|
-
adapter=self._response_format_adapter,
|
106
|
-
from_substring=True,
|
109
|
+
message.content or "", adapter=self._response_format_adapter
|
107
110
|
)
|
108
111
|
|
109
112
|
def _validate_tool_calls(self, completion: Completion) -> None:
|
grasp_agents/llm_agent.py
CHANGED
@@ -63,9 +63,9 @@ class LLMAgent(
|
|
63
63
|
sys_prompt: LLMPrompt | None = None,
|
64
64
|
sys_prompt_path: str | Path | None = None,
|
65
65
|
# System args (static args provided via RunContext)
|
66
|
-
sys_args_schema: type[LLMPromptArgs] =
|
66
|
+
sys_args_schema: type[LLMPromptArgs] | None = None,
|
67
67
|
# User args (static args provided via RunContext)
|
68
|
-
usr_args_schema: type[LLMPromptArgs] =
|
68
|
+
usr_args_schema: type[LLMPromptArgs] | None = None,
|
69
69
|
# Agent loop settings
|
70
70
|
max_turns: int = 100,
|
71
71
|
react_mode: bool = False,
|
@@ -82,14 +82,13 @@ class LLMAgent(
|
|
82
82
|
|
83
83
|
self._memory: LLMAgentMemory = LLMAgentMemory()
|
84
84
|
self._reset_memory_on_run = reset_memory_on_run
|
85
|
-
self._set_memory_impl: SetMemoryHandler | None = None
|
86
85
|
|
87
86
|
# LLM policy executor
|
88
87
|
|
89
|
-
self.
|
88
|
+
self._used_default_llm_response_format: bool = False
|
90
89
|
if llm.response_format is None and tools is None:
|
91
90
|
llm.response_format = self.out_type
|
92
|
-
self.
|
91
|
+
self._used_default_llm_response_format = True
|
93
92
|
|
94
93
|
self._policy_executor: LLMPolicyExecutor[OutT_co, CtxT] = LLMPolicyExecutor[
|
95
94
|
self.out_type, CtxT
|
@@ -118,6 +117,10 @@ class LLMAgent(
|
|
118
117
|
|
119
118
|
self.no_tqdm = getattr(llm, "no_tqdm", False)
|
120
119
|
|
120
|
+
self._set_memory_impl: SetMemoryHandler | None = None
|
121
|
+
self._parse_output_impl: (
|
122
|
+
ParseOutputHandler[InT_contra, OutT_co, CtxT] | None
|
123
|
+
) = None
|
121
124
|
self._register_overridden_handlers()
|
122
125
|
|
123
126
|
@property
|
@@ -148,32 +151,6 @@ class LLMAgent(
|
|
148
151
|
def in_prompt(self) -> LLMPrompt | None:
|
149
152
|
return self._prompt_builder.in_prompt_template
|
150
153
|
|
151
|
-
def _parse_output(
|
152
|
-
self,
|
153
|
-
conversation: Messages,
|
154
|
-
*,
|
155
|
-
in_args: InT_contra | None = None,
|
156
|
-
batch_idx: int = 0,
|
157
|
-
ctx: RunContext[CtxT] | None = None,
|
158
|
-
) -> OutT_co:
|
159
|
-
if self._parse_output_impl:
|
160
|
-
if self._using_default_llm_response_format:
|
161
|
-
# When using custom output parsing, the required LLM response format
|
162
|
-
# can differ from the final agent output type ->
|
163
|
-
# set it back to None unless it was specified explicitly at init.
|
164
|
-
self._policy_executor.llm.response_format = None
|
165
|
-
# self._using_default_llm_response_format = False
|
166
|
-
|
167
|
-
return self._parse_output_impl(
|
168
|
-
conversation=conversation, in_args=in_args, batch_idx=batch_idx, ctx=ctx
|
169
|
-
)
|
170
|
-
|
171
|
-
return validate_obj_from_json_or_py_string(
|
172
|
-
str(conversation[-1].content or ""),
|
173
|
-
adapter=self._out_type_adapter,
|
174
|
-
from_substring=True,
|
175
|
-
)
|
176
|
-
|
177
154
|
def _memorize_inputs(
|
178
155
|
self,
|
179
156
|
chat_inputs: LLMPrompt | Sequence[str | ImageData] | None = None,
|
@@ -251,6 +228,25 @@ class LLMAgent(
|
|
251
228
|
|
252
229
|
return outputs
|
253
230
|
|
231
|
+
def _parse_output(
|
232
|
+
self,
|
233
|
+
conversation: Messages,
|
234
|
+
*,
|
235
|
+
in_args: InT_contra | None = None,
|
236
|
+
batch_idx: int = 0,
|
237
|
+
ctx: RunContext[CtxT] | None = None,
|
238
|
+
) -> OutT_co:
|
239
|
+
if self._parse_output_impl:
|
240
|
+
return self._parse_output_impl(
|
241
|
+
conversation=conversation, in_args=in_args, batch_idx=batch_idx, ctx=ctx
|
242
|
+
)
|
243
|
+
|
244
|
+
return validate_obj_from_json_or_py_string(
|
245
|
+
str(conversation[-1].content or ""),
|
246
|
+
adapter=self._out_type_adapter,
|
247
|
+
from_substring=True,
|
248
|
+
)
|
249
|
+
|
254
250
|
async def _process(
|
255
251
|
self,
|
256
252
|
chat_inputs: LLMPrompt | Sequence[str | ImageData] | None = None,
|
@@ -330,6 +326,8 @@ class LLMAgent(
|
|
330
326
|
def parse_output(
|
331
327
|
self, func: ParseOutputHandler[InT_contra, OutT_co, CtxT]
|
332
328
|
) -> ParseOutputHandler[InT_contra, OutT_co, CtxT]:
|
329
|
+
if self._used_default_llm_response_format:
|
330
|
+
self._policy_executor.llm.response_format = None
|
333
331
|
self._parse_output_impl = func
|
334
332
|
|
335
333
|
return func
|
@@ -376,9 +374,11 @@ class LLMAgent(
|
|
376
374
|
):
|
377
375
|
self._policy_executor.exit_tool_call_loop_impl = self._exit_tool_call_loop
|
378
376
|
|
379
|
-
|
380
|
-
|
381
|
-
|
377
|
+
if (
|
378
|
+
cur_cls._parse_output is not base_cls._parse_output # noqa: SLF001
|
379
|
+
and self._used_default_llm_response_format
|
380
|
+
):
|
381
|
+
self._policy_executor.llm.response_format = None
|
382
382
|
|
383
383
|
def _make_system_prompt(
|
384
384
|
self, sys_args: LLMPromptArgs | None, *, ctx: RunContext[CtxT] | None = None
|
grasp_agents/printer.py
CHANGED
@@ -135,7 +135,7 @@ class Printer:
|
|
135
135
|
elif self.color_by == "role":
|
136
136
|
tool_color = self.get_role_color(role=Role.TOOL)
|
137
137
|
logger.debug(
|
138
|
-
f"\n
|
138
|
+
f"\n<{agent_name}>[TOOL_CALL]\n{tool_call.tool_name} "
|
139
139
|
f"| {tool_call.id}\n{tool_call.tool_arguments}",
|
140
140
|
extra={"color": tool_color}, # type: ignore
|
141
141
|
)
|
grasp_agents/prompt_builder.py
CHANGED
@@ -79,9 +79,7 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT_contra, CtxT]):
|
|
79
79
|
if self.make_system_prompt_impl:
|
80
80
|
return self.make_system_prompt_impl(sys_args=val_sys_args, ctx=ctx)
|
81
81
|
|
82
|
-
sys_args_dict = (
|
83
|
-
val_sys_args.model_dump(exclude_unset=True) if val_sys_args else {}
|
84
|
-
)
|
82
|
+
sys_args_dict = val_sys_args.model_dump() if val_sys_args else {}
|
85
83
|
|
86
84
|
return self.sys_prompt_template.format(**sys_args_dict)
|
87
85
|
|
@@ -208,10 +206,7 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT_contra, CtxT]):
|
|
208
206
|
return formatted_args, contains_image_data
|
209
207
|
|
210
208
|
def _combine_args(
|
211
|
-
self,
|
212
|
-
*,
|
213
|
-
in_args: InT_contra | None,
|
214
|
-
usr_args: LLMPromptArgs | None,
|
209
|
+
self, *, in_args: InT_contra | None, usr_args: LLMPromptArgs | None
|
215
210
|
) -> Mapping[str, PromptArgumentType] | str:
|
216
211
|
fmt_usr_args, _ = (
|
217
212
|
self._format_pydantic_prompt_args(usr_args) if usr_args else ({}, False)
|
grasp_agents/run_context.py
CHANGED
@@ -13,8 +13,8 @@ from .usage_tracker import UsageTracker
|
|
13
13
|
|
14
14
|
|
15
15
|
class RunArgs(BaseModel):
|
16
|
-
sys: LLMPromptArgs =
|
17
|
-
usr: LLMPromptArgs =
|
16
|
+
sys: LLMPromptArgs | None = None
|
17
|
+
usr: LLMPromptArgs | None = None
|
18
18
|
|
19
19
|
model_config = ConfigDict(extra="forbid")
|
20
20
|
|
grasp_agents/utils.py
CHANGED
@@ -6,7 +6,7 @@ from collections.abc import Coroutine, Mapping
|
|
6
6
|
from datetime import UTC, datetime
|
7
7
|
from logging import getLogger
|
8
8
|
from pathlib import Path
|
9
|
-
from typing import Any, TypeVar, overload
|
9
|
+
from typing import Any, TypeVar, get_args, overload
|
10
10
|
|
11
11
|
from pydantic import TypeAdapter, ValidationError
|
12
12
|
from tqdm.autonotebook import tqdm
|
@@ -88,21 +88,24 @@ def validate_obj_from_json_or_py_string(
|
|
88
88
|
else:
|
89
89
|
_selected_adapter = adapter
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
_type = _selected_adapter._type # type: ignore[attr-defined]
|
92
|
+
type_args = get_args(_type)
|
93
|
+
is_str_type = (_type is str) or (len(type_args) == 1 and type_args[0] is str)
|
93
94
|
|
94
95
|
try:
|
95
|
-
if
|
96
|
-
|
96
|
+
if not is_str_type:
|
97
|
+
if from_substring:
|
98
|
+
parsed = parse_json_or_py_substring(s, return_none_on_failure=True)
|
99
|
+
else:
|
100
|
+
parsed = parse_json_or_py_string(s, return_none_on_failure=True)
|
101
|
+
if parsed is None:
|
102
|
+
parsed = s
|
97
103
|
else:
|
98
|
-
parsed = parse_json_or_py_string(s, return_none_on_failure=True)
|
99
|
-
if parsed is None:
|
100
104
|
parsed = s
|
101
105
|
return _selected_adapter.validate_python(parsed)
|
102
106
|
except (json.JSONDecodeError, ValidationError) as exc:
|
103
107
|
raise ValueError(
|
104
|
-
f"Invalid JSON or Python string:\n{s}\
|
105
|
-
f"Expected type: {_selected_adapter._type}", # type: ignore[arg-type]
|
108
|
+
f"Invalid JSON or Python string:\n{s}\nExpected type: {_type}"
|
106
109
|
) from exc
|
107
110
|
|
108
111
|
|
@@ -5,20 +5,20 @@ grasp_agents/costs_dict.yaml,sha256=2MFNWtkv5W5WSCcv1Cj13B1iQLVv5Ot9pS_KW2Gu2DA,
|
|
5
5
|
grasp_agents/generics_utils.py,sha256=5Pw3I9dlnKC2VGqYKC4ZZUO3Z_vTNT-NPFovNfPkl6I,6542
|
6
6
|
grasp_agents/grasp_logging.py,sha256=H1GYhXdQvVkmauFDZ-KDwvVmPQHZUUm9sRqX_ObK2xI,1111
|
7
7
|
grasp_agents/http_client.py,sha256=KZva2MjJjuI5ohUeU8RdTAImUnQYaqBrV2jDH8smbJw,738
|
8
|
-
grasp_agents/llm.py,sha256=
|
9
|
-
grasp_agents/llm_agent.py,sha256=
|
8
|
+
grasp_agents/llm.py,sha256=vVjELab9l0mK9bjO-IJebmmXUyUiws2fNjbXVQQNRvs,5392
|
9
|
+
grasp_agents/llm_agent.py,sha256=_Fb3PAfw5okbsybz-BsUkd4kN8K9D5Sjw3HCbDHJFGk,14697
|
10
10
|
grasp_agents/llm_agent_memory.py,sha256=kD_UIF8xVgbSgW6xN87TzkdQcbTWLB-C5ZQu1_2HLx8,1770
|
11
11
|
grasp_agents/llm_policy_executor.py,sha256=PVNuAejt3S-aSGsT7HvgYHyX_cZQSvrt1aUGPdkXtE4,17847
|
12
12
|
grasp_agents/memory.py,sha256=gPkVIIF6dI_xXzarIAw9kSEnSJcfW_teUsWA2JAih94,671
|
13
13
|
grasp_agents/message_history.py,sha256=-ZNy3C1z0yQeahjqR0oIoWDMySJ7vPS19jdutibW7OE,5408
|
14
14
|
grasp_agents/packet.py,sha256=PZ1EpclniAoLk7z4ieZbWzgYH3JSRgnlTe_WfbJYG_4,707
|
15
15
|
grasp_agents/packet_pool.py,sha256=9umHbi5FwuUYYhhodSR-Z-fRR6OYiZyYEzq5d4nZFK4,3036
|
16
|
-
grasp_agents/printer.py,sha256=
|
16
|
+
grasp_agents/printer.py,sha256=M-gkLrZMg0ll9T1MRmKOQbp65niFB5ZiZbm-tUT_EYw,5464
|
17
17
|
grasp_agents/processor.py,sha256=Atd_iTQNd3Nudb4mHqt3a5AQ31QUgpbrt1Fhn1sgpSk,6708
|
18
|
-
grasp_agents/prompt_builder.py,sha256=
|
19
|
-
grasp_agents/run_context.py,sha256=
|
18
|
+
grasp_agents/prompt_builder.py,sha256=1o7eMO4FxqRrrXFCj7aQKIajty6jZbBVaUZv7qOMIoY,8414
|
19
|
+
grasp_agents/run_context.py,sha256=9CidWWCKJ8umlhkRGtg_P3JQsRpH0K3_vhUjgVon4Wk,1597
|
20
20
|
grasp_agents/usage_tracker.py,sha256=SPwv6RpdoHRuMIKE2hCAWAvDbtR3uXuhr2jpHQuKWhI,3438
|
21
|
-
grasp_agents/utils.py,sha256=
|
21
|
+
grasp_agents/utils.py,sha256=WNA5b0IkAsth0XKHEjgTY3PIHdw5L3vEsYPkyDGw8Mw,4741
|
22
22
|
grasp_agents/openai/__init__.py,sha256=wpTeew6EjhM6esHCKrEKUpwq0kygMN2QQDxYtmbRG8Y,4201
|
23
23
|
grasp_agents/openai/completion_chunk_converters.py,sha256=i-1SvIWhRKtL0K8p5pb3jjACSnyHuJHTCoZovEERpxs,2628
|
24
24
|
grasp_agents/openai/completion_converters.py,sha256=vzPEkUOX4l2hobKxZjEk_dyWfzeYesO0DlvWvNVb-Sg,2656
|
@@ -45,7 +45,7 @@ grasp_agents/workflow/looped_workflow.py,sha256=QqXclXYxsW6C8Rxkf3dRaMHi-DfCvCbj
|
|
45
45
|
grasp_agents/workflow/parallel_processor.py,sha256=Xyzs2UR_mRe2GFgzzadHOhqgMu3rFjd3GUjvmZimt_k,3505
|
46
46
|
grasp_agents/workflow/sequential_workflow.py,sha256=Pl7jl9ZVDu-rC5UMfympEaQN8iG3kZurVF5eIPG62XA,2130
|
47
47
|
grasp_agents/workflow/workflow_processor.py,sha256=2-iaDIlgNXgj-ClGbiE3fYfSv-N_qRC49Gf_dF6M_40,2640
|
48
|
-
grasp_agents-0.3.
|
49
|
-
grasp_agents-0.3.
|
50
|
-
grasp_agents-0.3.
|
51
|
-
grasp_agents-0.3.
|
48
|
+
grasp_agents-0.3.5.dist-info/METADATA,sha256=O_mAQKcTBjZB5H9UoINxgkbnQyUUJE8TBEDSmFaEBVc,6806
|
49
|
+
grasp_agents-0.3.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
50
|
+
grasp_agents-0.3.5.dist-info/licenses/LICENSE.md,sha256=-nNNdWqGB8gJ2O-peFQ2Irshv5tW5pHKyTcYkwvH7CE,1201
|
51
|
+
grasp_agents-0.3.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|