grasp_agents 0.5.4__py3-none-any.whl → 0.5.6__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/__init__.py +6 -3
- grasp_agents/llm.py +5 -1
- grasp_agents/llm_agent.py +100 -107
- grasp_agents/llm_agent_memory.py +1 -1
- grasp_agents/llm_policy_executor.py +15 -13
- grasp_agents/packet_pool.py +6 -1
- grasp_agents/printer.py +8 -5
- grasp_agents/processors/base_processor.py +320 -0
- grasp_agents/processors/parallel_processor.py +244 -0
- grasp_agents/processors/processor.py +161 -0
- grasp_agents/prompt_builder.py +22 -60
- grasp_agents/run_context.py +3 -8
- grasp_agents/runner.py +20 -1
- grasp_agents/typing/events.py +4 -0
- grasp_agents/typing/io.py +0 -7
- grasp_agents/workflow/looped_workflow.py +35 -27
- grasp_agents/workflow/sequential_workflow.py +14 -3
- grasp_agents/workflow/workflow_processor.py +32 -11
- {grasp_agents-0.5.4.dist-info → grasp_agents-0.5.6.dist-info}/METADATA +1 -1
- {grasp_agents-0.5.4.dist-info → grasp_agents-0.5.6.dist-info}/RECORD +22 -20
- grasp_agents/processor.py +0 -512
- {grasp_agents-0.5.4.dist-info → grasp_agents-0.5.6.dist-info}/WHEEL +0 -0
- {grasp_agents-0.5.4.dist-info → grasp_agents-0.5.6.dist-info}/licenses/LICENSE.md +0 -0
grasp_agents/__init__.py
CHANGED
@@ -6,17 +6,20 @@ from .llm_agent import LLMAgent
|
|
6
6
|
from .llm_agent_memory import LLMAgentMemory
|
7
7
|
from .memory import Memory
|
8
8
|
from .packet import Packet
|
9
|
-
from .
|
9
|
+
from .processors.base_processor import BaseProcessor
|
10
|
+
from .processors.parallel_processor import ParallelProcessor
|
11
|
+
from .processors.processor import Processor
|
10
12
|
from .run_context import RunContext
|
11
13
|
from .typing.completion import Completion
|
12
14
|
from .typing.content import Content, ImageData
|
13
|
-
from .typing.io import LLMPrompt,
|
15
|
+
from .typing.io import LLMPrompt, ProcName
|
14
16
|
from .typing.message import AssistantMessage, Messages, SystemMessage, UserMessage
|
15
17
|
from .typing.tool import BaseTool
|
16
18
|
|
17
19
|
__all__ = [
|
18
20
|
"LLM",
|
19
21
|
"AssistantMessage",
|
22
|
+
"BaseProcessor",
|
20
23
|
"BaseTool",
|
21
24
|
"Completion",
|
22
25
|
"Content",
|
@@ -24,12 +27,12 @@ __all__ = [
|
|
24
27
|
"LLMAgent",
|
25
28
|
"LLMAgentMemory",
|
26
29
|
"LLMPrompt",
|
27
|
-
"LLMPromptArgs",
|
28
30
|
"LLMSettings",
|
29
31
|
"Memory",
|
30
32
|
"Messages",
|
31
33
|
"Packet",
|
32
34
|
"Packet",
|
35
|
+
"ParallelProcessor",
|
33
36
|
"ProcName",
|
34
37
|
"Processor",
|
35
38
|
"RunContext",
|
grasp_agents/llm.py
CHANGED
@@ -19,7 +19,11 @@ from .errors import (
|
|
19
19
|
)
|
20
20
|
from .typing.completion import Completion
|
21
21
|
from .typing.converters import Converters
|
22
|
-
from .typing.events import
|
22
|
+
from .typing.events import (
|
23
|
+
CompletionChunkEvent,
|
24
|
+
CompletionEvent,
|
25
|
+
LLMStreamingErrorEvent,
|
26
|
+
)
|
23
27
|
from .typing.message import Messages
|
24
28
|
from .typing.tool import BaseTool, ToolChoice
|
25
29
|
|
grasp_agents/llm_agent.py
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
from collections.abc import AsyncIterator, Sequence
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Any, ClassVar, Generic, Protocol, TypeVar, cast
|
3
|
+
from typing import Any, ClassVar, Generic, Protocol, TypeVar, cast, final
|
4
4
|
|
5
5
|
from pydantic import BaseModel
|
6
6
|
|
7
7
|
from .llm import LLM, LLMSettings
|
8
|
-
from .llm_agent_memory import LLMAgentMemory,
|
8
|
+
from .llm_agent_memory import LLMAgentMemory, MemoryPreparator
|
9
9
|
from .llm_policy_executor import (
|
10
|
-
ExitToolCallLoopHandler,
|
11
10
|
LLMPolicyExecutor,
|
12
|
-
|
11
|
+
MemoryManager,
|
12
|
+
ToolCallLoopTerminator,
|
13
13
|
)
|
14
|
-
from .
|
14
|
+
from .processors.parallel_processor import ParallelProcessor
|
15
15
|
from .prompt_builder import (
|
16
|
-
|
17
|
-
MakeSystemPromptHandler,
|
16
|
+
InputContentBuilder,
|
18
17
|
PromptBuilder,
|
18
|
+
SystemPromptBuilder,
|
19
19
|
)
|
20
20
|
from .run_context import CtxT, RunContext
|
21
21
|
from .typing.content import Content, ImageData
|
@@ -26,7 +26,7 @@ from .typing.events import (
|
|
26
26
|
SystemMessageEvent,
|
27
27
|
UserMessageEvent,
|
28
28
|
)
|
29
|
-
from .typing.io import InT, LLMPrompt,
|
29
|
+
from .typing.io import InT, LLMPrompt, OutT, ProcName
|
30
30
|
from .typing.message import Message, Messages, SystemMessage, UserMessage
|
31
31
|
from .typing.tool import BaseTool
|
32
32
|
from .utils import get_prompt, validate_obj_from_json_or_py_string
|
@@ -35,7 +35,7 @@ _InT_contra = TypeVar("_InT_contra", contravariant=True)
|
|
35
35
|
_OutT_co = TypeVar("_OutT_co", covariant=True)
|
36
36
|
|
37
37
|
|
38
|
-
class
|
38
|
+
class OutputParser(Protocol[_InT_contra, _OutT_co, CtxT]):
|
39
39
|
def __call__(
|
40
40
|
self,
|
41
41
|
conversation: Messages,
|
@@ -46,7 +46,7 @@ class ParseOutputHandler(Protocol[_InT_contra, _OutT_co, CtxT]):
|
|
46
46
|
|
47
47
|
|
48
48
|
class LLMAgent(
|
49
|
-
|
49
|
+
ParallelProcessor[InT, OutT, LLMAgentMemory, CtxT],
|
50
50
|
Generic[InT, OutT, CtxT],
|
51
51
|
):
|
52
52
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {
|
@@ -68,8 +68,6 @@ class LLMAgent(
|
|
68
68
|
# System prompt template
|
69
69
|
sys_prompt: LLMPrompt | None = None,
|
70
70
|
sys_prompt_path: str | Path | None = None,
|
71
|
-
# System args (static args provided via RunContext)
|
72
|
-
sys_args_schema: type[LLMPromptArgs] | None = None,
|
73
71
|
# Agent loop settings
|
74
72
|
max_turns: int = 100,
|
75
73
|
react_mode: bool = False,
|
@@ -88,10 +86,22 @@ class LLMAgent(
|
|
88
86
|
self._memory: LLMAgentMemory = LLMAgentMemory()
|
89
87
|
self._reset_memory_on_run = reset_memory_on_run
|
90
88
|
|
89
|
+
self.memory_preparator: MemoryPreparator | None
|
90
|
+
if not hasattr(type(self), "memory_preparator"):
|
91
|
+
self.memory_preparator = None
|
92
|
+
|
93
|
+
self.output_parser: OutputParser[InT, OutT, CtxT] | None
|
94
|
+
if not hasattr(type(self), "output_parser"):
|
95
|
+
self.output_parser = None
|
96
|
+
|
91
97
|
# LLM policy executor
|
92
98
|
|
93
99
|
self._used_default_llm_response_schema: bool = False
|
94
|
-
if
|
100
|
+
if (
|
101
|
+
llm.response_schema is None
|
102
|
+
and tools is None
|
103
|
+
and not hasattr(type(self), "output_parser")
|
104
|
+
):
|
95
105
|
llm.response_schema = self.out_type
|
96
106
|
self._used_default_llm_response_schema = True
|
97
107
|
|
@@ -119,17 +129,11 @@ class LLMAgent(
|
|
119
129
|
|
120
130
|
sys_prompt = get_prompt(prompt_text=sys_prompt, prompt_path=sys_prompt_path)
|
121
131
|
in_prompt = get_prompt(prompt_text=in_prompt, prompt_path=in_prompt_path)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
agent_name=self._name,
|
126
|
-
sys_prompt=sys_prompt,
|
127
|
-
in_prompt=in_prompt,
|
128
|
-
sys_args_schema=sys_args_schema,
|
132
|
+
|
133
|
+
self._prompt_builder = PromptBuilder[self.in_type, CtxT](
|
134
|
+
agent_name=self._name, sys_prompt=sys_prompt, in_prompt=in_prompt
|
129
135
|
)
|
130
136
|
|
131
|
-
self._prepare_memory_impl: PrepareMemoryHandler | None = None
|
132
|
-
self._parse_output_impl: ParseOutputHandler[InT, OutT, CtxT] | None = None
|
133
137
|
self._register_overridden_handlers()
|
134
138
|
|
135
139
|
@property
|
@@ -144,10 +148,6 @@ class LLMAgent(
|
|
144
148
|
def max_turns(self) -> int:
|
145
149
|
return self._policy_executor.max_turns
|
146
150
|
|
147
|
-
@property
|
148
|
-
def sys_args_schema(self) -> type[LLMPromptArgs] | None:
|
149
|
-
return self._prompt_builder.sys_args_schema
|
150
|
-
|
151
151
|
@property
|
152
152
|
def sys_prompt(self) -> LLMPrompt | None:
|
153
153
|
return self._prompt_builder.sys_prompt
|
@@ -156,6 +156,7 @@ class LLMAgent(
|
|
156
156
|
def in_prompt(self) -> LLMPrompt | None:
|
157
157
|
return self._prompt_builder.in_prompt
|
158
158
|
|
159
|
+
@final
|
159
160
|
def _prepare_memory(
|
160
161
|
self,
|
161
162
|
memory: LLMAgentMemory,
|
@@ -163,8 +164,8 @@ class LLMAgent(
|
|
163
164
|
sys_prompt: LLMPrompt | None = None,
|
164
165
|
ctx: RunContext[Any] | None = None,
|
165
166
|
) -> None:
|
166
|
-
if self.
|
167
|
-
return self.
|
167
|
+
if self.memory_preparator:
|
168
|
+
return self.memory_preparator(
|
168
169
|
memory=memory, in_args=in_args, sys_prompt=sys_prompt, ctx=ctx
|
169
170
|
)
|
170
171
|
|
@@ -175,16 +176,7 @@ class LLMAgent(
|
|
175
176
|
in_args: InT | None = None,
|
176
177
|
ctx: RunContext[CtxT] | None = None,
|
177
178
|
) -> tuple[SystemMessage | None, UserMessage | None]:
|
178
|
-
|
179
|
-
sys_args = ctx.sys_args.get(self.name) if ctx and ctx.sys_args else None
|
180
|
-
|
181
|
-
# 2. Make system prompt (can be None)
|
182
|
-
|
183
|
-
formatted_sys_prompt = self._prompt_builder.make_system_prompt(
|
184
|
-
sys_args=sys_args, ctx=ctx
|
185
|
-
)
|
186
|
-
|
187
|
-
# 3. Set agent memory
|
179
|
+
formatted_sys_prompt = self._prompt_builder.build_system_prompt(ctx=ctx)
|
188
180
|
|
189
181
|
system_message: SystemMessage | None = None
|
190
182
|
if self._reset_memory_on_run or memory.is_empty:
|
@@ -196,9 +188,7 @@ class LLMAgent(
|
|
196
188
|
memory=memory, in_args=in_args, sys_prompt=formatted_sys_prompt, ctx=ctx
|
197
189
|
)
|
198
190
|
|
199
|
-
|
200
|
-
|
201
|
-
input_message = self._prompt_builder.make_input_message(
|
191
|
+
input_message = self._prompt_builder.build_input_message(
|
202
192
|
chat_inputs=chat_inputs, in_args=in_args, ctx=ctx
|
203
193
|
)
|
204
194
|
if input_message:
|
@@ -206,18 +196,13 @@ class LLMAgent(
|
|
206
196
|
|
207
197
|
return system_message, input_message
|
208
198
|
|
209
|
-
def
|
199
|
+
def _parse_output_default(
|
210
200
|
self,
|
211
201
|
conversation: Messages,
|
212
202
|
*,
|
213
203
|
in_args: InT | None = None,
|
214
204
|
ctx: RunContext[CtxT] | None = None,
|
215
205
|
) -> OutT:
|
216
|
-
if self._parse_output_impl:
|
217
|
-
return self._parse_output_impl(
|
218
|
-
conversation=conversation, in_args=in_args, ctx=ctx
|
219
|
-
)
|
220
|
-
|
221
206
|
return validate_obj_from_json_or_py_string(
|
222
207
|
str(conversation[-1].content or ""),
|
223
208
|
schema=self._out_type,
|
@@ -225,6 +210,22 @@ class LLMAgent(
|
|
225
210
|
strip_language_markdown=True,
|
226
211
|
)
|
227
212
|
|
213
|
+
def _parse_output(
|
214
|
+
self,
|
215
|
+
conversation: Messages,
|
216
|
+
*,
|
217
|
+
in_args: InT | None = None,
|
218
|
+
ctx: RunContext[CtxT] | None = None,
|
219
|
+
) -> OutT:
|
220
|
+
if self.output_parser:
|
221
|
+
return self.output_parser(
|
222
|
+
conversation=conversation, in_args=in_args, ctx=ctx
|
223
|
+
)
|
224
|
+
|
225
|
+
return self._parse_output_default(
|
226
|
+
conversation=conversation, in_args=in_args, ctx=ctx
|
227
|
+
)
|
228
|
+
|
228
229
|
async def _process(
|
229
230
|
self,
|
230
231
|
chat_inputs: LLMPrompt | Sequence[str | ImageData] | None = None,
|
@@ -302,108 +303,100 @@ class LLMAgent(
|
|
302
303
|
cur_cls = type(self)
|
303
304
|
base_cls = LLMAgent[Any, Any, Any]
|
304
305
|
|
305
|
-
# Packet routing
|
306
|
-
if cur_cls._select_recipients is not base_cls._select_recipients: # noqa: SLF001
|
307
|
-
self.select_recipients_impl = self._select_recipients
|
308
|
-
|
309
306
|
# Prompt builder
|
310
307
|
|
311
|
-
if cur_cls.
|
312
|
-
self._prompt_builder.
|
308
|
+
if cur_cls.system_prompt_builder is not base_cls.system_prompt_builder:
|
309
|
+
self._prompt_builder.system_prompt_builder = self.system_prompt_builder
|
313
310
|
|
314
|
-
if cur_cls.
|
315
|
-
self._prompt_builder.
|
311
|
+
if cur_cls.input_content_builder is not base_cls.input_content_builder:
|
312
|
+
self._prompt_builder.input_content_builder = self.input_content_builder
|
316
313
|
|
317
314
|
# Policy executor
|
318
315
|
|
319
|
-
if
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
if cur_cls._manage_memory is not base_cls._manage_memory: # noqa: SLF001
|
325
|
-
self._policy_executor.manage_memory_impl = self._manage_memory
|
316
|
+
if cur_cls.tool_call_loop_terminator is not base_cls.tool_call_loop_terminator:
|
317
|
+
self._policy_executor.tool_call_loop_terminator = (
|
318
|
+
self.tool_call_loop_terminator
|
319
|
+
)
|
326
320
|
|
327
|
-
|
328
|
-
|
329
|
-
if (
|
330
|
-
cur_cls._parse_output is not base_cls._parse_output # noqa: SLF001
|
331
|
-
and self._used_default_llm_response_schema
|
332
|
-
):
|
333
|
-
self._policy_executor.llm.response_schema = None
|
321
|
+
if cur_cls.memory_manager is not base_cls.memory_manager:
|
322
|
+
self._policy_executor.memory_manager = self.memory_manager
|
334
323
|
|
335
|
-
def
|
336
|
-
self
|
337
|
-
|
338
|
-
|
324
|
+
def system_prompt_builder(self, ctx: RunContext[CtxT] | None = None) -> str | None:
|
325
|
+
if self._prompt_builder.system_prompt_builder is not None:
|
326
|
+
return self._prompt_builder.system_prompt_builder(ctx=ctx)
|
327
|
+
raise NotImplementedError("System prompt builder is not implemented.")
|
339
328
|
|
340
|
-
def
|
329
|
+
def input_content_builder(
|
341
330
|
self, in_args: InT | None = None, *, ctx: RunContext[CtxT] | None = None
|
342
331
|
) -> Content:
|
343
|
-
|
332
|
+
if self._prompt_builder.input_content_builder is not None:
|
333
|
+
return self._prompt_builder.input_content_builder(in_args=in_args, ctx=ctx)
|
334
|
+
raise NotImplementedError("Input content builder is not implemented.")
|
344
335
|
|
345
|
-
def
|
336
|
+
def tool_call_loop_terminator(
|
346
337
|
self,
|
347
338
|
conversation: Messages,
|
348
339
|
*,
|
349
340
|
ctx: RunContext[CtxT] | None = None,
|
350
341
|
**kwargs: Any,
|
351
342
|
) -> bool:
|
352
|
-
|
353
|
-
|
354
|
-
|
343
|
+
if self._policy_executor.tool_call_loop_terminator is not None:
|
344
|
+
return self._policy_executor.tool_call_loop_terminator(
|
345
|
+
conversation=conversation, ctx=ctx, **kwargs
|
346
|
+
)
|
347
|
+
raise NotImplementedError("Tool call loop terminator is not implemented.")
|
355
348
|
|
356
|
-
def
|
349
|
+
def memory_manager(
|
357
350
|
self,
|
358
351
|
memory: LLMAgentMemory,
|
359
352
|
*,
|
360
353
|
ctx: RunContext[CtxT] | None = None,
|
361
354
|
**kwargs: Any,
|
362
355
|
) -> None:
|
363
|
-
|
364
|
-
|
365
|
-
|
356
|
+
if self._policy_executor.memory_manager is not None:
|
357
|
+
return self._policy_executor.memory_manager(
|
358
|
+
memory=memory, ctx=ctx, **kwargs
|
359
|
+
)
|
360
|
+
raise NotImplementedError("Memory manager is not implemented.")
|
366
361
|
|
367
362
|
# Decorators for custom implementations as an alternative to overriding methods
|
368
363
|
|
369
|
-
def
|
370
|
-
self, func:
|
371
|
-
) ->
|
372
|
-
self._prompt_builder.
|
364
|
+
def add_system_prompt_builder(
|
365
|
+
self, func: SystemPromptBuilder[CtxT]
|
366
|
+
) -> SystemPromptBuilder[CtxT]:
|
367
|
+
self._prompt_builder.system_prompt_builder = func
|
373
368
|
|
374
369
|
return func
|
375
370
|
|
376
|
-
def
|
377
|
-
self, func:
|
378
|
-
) ->
|
379
|
-
self._prompt_builder.
|
371
|
+
def add_input_content_builder(
|
372
|
+
self, func: InputContentBuilder[InT, CtxT]
|
373
|
+
) -> InputContentBuilder[InT, CtxT]:
|
374
|
+
self._prompt_builder.input_content_builder = func
|
380
375
|
|
381
376
|
return func
|
382
377
|
|
383
|
-
def
|
384
|
-
self
|
385
|
-
) -> ParseOutputHandler[InT, OutT, CtxT]:
|
386
|
-
if self._used_default_llm_response_schema:
|
387
|
-
self._policy_executor.llm.response_schema = None
|
388
|
-
self._parse_output_impl = func
|
378
|
+
def add_memory_manager(self, func: MemoryManager[CtxT]) -> MemoryManager[CtxT]:
|
379
|
+
self._policy_executor.memory_manager = func
|
389
380
|
|
390
381
|
return func
|
391
382
|
|
392
|
-
def
|
393
|
-
self
|
383
|
+
def add_tool_call_loop_terminator(
|
384
|
+
self, func: ToolCallLoopTerminator[CtxT]
|
385
|
+
) -> ToolCallLoopTerminator[CtxT]:
|
386
|
+
self._policy_executor.tool_call_loop_terminator = func
|
394
387
|
|
395
388
|
return func
|
396
389
|
|
397
|
-
def
|
398
|
-
self, func:
|
399
|
-
) ->
|
400
|
-
self.
|
390
|
+
def add_output_parser(
|
391
|
+
self, func: OutputParser[InT, OutT, CtxT]
|
392
|
+
) -> OutputParser[InT, OutT, CtxT]:
|
393
|
+
if self._used_default_llm_response_schema:
|
394
|
+
self._policy_executor.llm.response_schema = None
|
395
|
+
self.output_parser = func
|
401
396
|
|
402
397
|
return func
|
403
398
|
|
404
|
-
def
|
405
|
-
self
|
406
|
-
) -> ExitToolCallLoopHandler[CtxT]:
|
407
|
-
self._policy_executor.exit_tool_call_loop_impl = func
|
399
|
+
def add_memory_preparator(self, func: MemoryPreparator) -> MemoryPreparator:
|
400
|
+
self.memory_preparator = func
|
408
401
|
|
409
402
|
return func
|
grasp_agents/llm_agent_memory.py
CHANGED
@@ -3,7 +3,7 @@ import json
|
|
3
3
|
from collections.abc import AsyncIterator, Coroutine, Sequence
|
4
4
|
from itertools import starmap
|
5
5
|
from logging import getLogger
|
6
|
-
from typing import Any, Generic, Protocol
|
6
|
+
from typing import Any, Generic, Protocol, final
|
7
7
|
|
8
8
|
from pydantic import BaseModel
|
9
9
|
|
@@ -29,7 +29,7 @@ from .typing.tool import BaseTool, NamedToolChoice, ToolCall, ToolChoice
|
|
29
29
|
logger = getLogger(__name__)
|
30
30
|
|
31
31
|
|
32
|
-
class
|
32
|
+
class ToolCallLoopTerminator(Protocol[CtxT]):
|
33
33
|
def __call__(
|
34
34
|
self,
|
35
35
|
conversation: Messages,
|
@@ -39,7 +39,7 @@ class ExitToolCallLoopHandler(Protocol[CtxT]):
|
|
39
39
|
) -> bool: ...
|
40
40
|
|
41
41
|
|
42
|
-
class
|
42
|
+
class MemoryManager(Protocol[CtxT]):
|
43
43
|
def __call__(
|
44
44
|
self,
|
45
45
|
memory: LLMAgentMemory,
|
@@ -78,8 +78,8 @@ class LLMPolicyExecutor(Generic[CtxT]):
|
|
78
78
|
self._max_turns = max_turns
|
79
79
|
self._react_mode = react_mode
|
80
80
|
|
81
|
-
self.
|
82
|
-
self.
|
81
|
+
self.tool_call_loop_terminator: ToolCallLoopTerminator[CtxT] | None = None
|
82
|
+
self.memory_manager: MemoryManager[CtxT] | None = None
|
83
83
|
|
84
84
|
@property
|
85
85
|
def agent_name(self) -> str:
|
@@ -97,18 +97,20 @@ class LLMPolicyExecutor(Generic[CtxT]):
|
|
97
97
|
def max_turns(self) -> int:
|
98
98
|
return self._max_turns
|
99
99
|
|
100
|
-
|
100
|
+
@final
|
101
|
+
def _terminate_tool_call_loop(
|
101
102
|
self,
|
102
103
|
conversation: Messages,
|
103
104
|
*,
|
104
105
|
ctx: RunContext[CtxT] | None = None,
|
105
106
|
**kwargs: Any,
|
106
107
|
) -> bool:
|
107
|
-
if self.
|
108
|
-
return self.
|
108
|
+
if self.tool_call_loop_terminator:
|
109
|
+
return self.tool_call_loop_terminator(conversation, ctx=ctx, **kwargs)
|
109
110
|
|
110
111
|
return False
|
111
112
|
|
113
|
+
@final
|
112
114
|
def _manage_memory(
|
113
115
|
self,
|
114
116
|
memory: LLMAgentMemory,
|
@@ -116,8 +118,8 @@ class LLMPolicyExecutor(Generic[CtxT]):
|
|
116
118
|
ctx: RunContext[CtxT] | None = None,
|
117
119
|
**kwargs: Any,
|
118
120
|
) -> None:
|
119
|
-
if self.
|
120
|
-
self.
|
121
|
+
if self.memory_manager:
|
122
|
+
self.memory_manager(memory=memory, ctx=ctx, **kwargs)
|
121
123
|
|
122
124
|
async def generate_message(
|
123
125
|
self,
|
@@ -309,8 +311,8 @@ class LLMPolicyExecutor(Generic[CtxT]):
|
|
309
311
|
# 2. Check if we should exit the tool call loop
|
310
312
|
|
311
313
|
# If a final answer is not provided via a tool call, we use
|
312
|
-
#
|
313
|
-
if not self._final_answer_as_tool_call and self.
|
314
|
+
# _terminate_tool_call_loop to determine whether to exit the loop.
|
315
|
+
if not self._final_answer_as_tool_call and self._terminate_tool_call_loop(
|
314
316
|
memory.message_history, ctx=ctx, num_turns=turns
|
315
317
|
):
|
316
318
|
return gen_message
|
@@ -390,7 +392,7 @@ class LLMPolicyExecutor(Generic[CtxT]):
|
|
390
392
|
turns = 0
|
391
393
|
|
392
394
|
while True:
|
393
|
-
if not self._final_answer_as_tool_call and self.
|
395
|
+
if not self._final_answer_as_tool_call and self._terminate_tool_call_loop(
|
394
396
|
memory.message_history, ctx=ctx, num_turns=turns
|
395
397
|
):
|
396
398
|
return
|
grasp_agents/packet_pool.py
CHANGED
@@ -68,6 +68,11 @@ class PacketPool(Generic[CtxT]):
|
|
68
68
|
finally:
|
69
69
|
await self.shutdown()
|
70
70
|
|
71
|
+
@property
|
72
|
+
def final_result_ready(self) -> bool:
|
73
|
+
fut = self._final_result_fut
|
74
|
+
return fut is not None and fut.done()
|
75
|
+
|
71
76
|
def register_packet_handler(
|
72
77
|
self,
|
73
78
|
proc_name: ProcName,
|
@@ -121,7 +126,7 @@ class PacketPool(Generic[CtxT]):
|
|
121
126
|
queue = self._packet_queues[proc_name]
|
122
127
|
handler = self._packet_handlers[proc_name]
|
123
128
|
|
124
|
-
while
|
129
|
+
while not self.final_result_ready:
|
125
130
|
packet = await queue.get()
|
126
131
|
if packet is None:
|
127
132
|
break
|
grasp_agents/printer.py
CHANGED
@@ -119,7 +119,7 @@ class Printer:
|
|
119
119
|
# Thinking
|
120
120
|
if isinstance(message, AssistantMessage) and message.reasoning_content:
|
121
121
|
thinking = message.reasoning_content.strip(" \n")
|
122
|
-
out += f"
|
122
|
+
out += f"<thinking>\n{thinking}\n</thinking>\n"
|
123
123
|
|
124
124
|
# Content
|
125
125
|
content = self.content_to_str(message.content or "", message.role)
|
@@ -232,11 +232,14 @@ async def print_event_stream(
|
|
232
232
|
text += f"<{src} output>\n"
|
233
233
|
for p in event.data.payloads:
|
234
234
|
if isinstance(p, BaseModel):
|
235
|
-
for field_info in type(p).model_fields.values():
|
236
|
-
|
237
|
-
|
238
|
-
|
235
|
+
# for field_info in type(p).model_fields.values():
|
236
|
+
# if field_info.exclude:
|
237
|
+
# field_info.exclude = False
|
238
|
+
# break
|
239
|
+
# type(p).model_rebuild(force=True)
|
239
240
|
p_str = p.model_dump_json(indent=2)
|
241
|
+
# field_info.exclude = True # type: ignore
|
242
|
+
# type(p).model_rebuild(force=True)
|
240
243
|
else:
|
241
244
|
try:
|
242
245
|
p_str = json.dumps(p, indent=2)
|