grasp_agents 0.5.4__tar.gz → 0.5.5__tar.gz
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-0.5.4 → grasp_agents-0.5.5}/PKG-INFO +1 -1
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/pyproject.toml +1 -1
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/__init__.py +1 -2
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/llm_agent.py +83 -101
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/llm_agent_memory.py +1 -1
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/llm_policy_executor.py +15 -13
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/printer.py +1 -1
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/processor.py +37 -31
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/prompt_builder.py +22 -60
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/run_context.py +3 -8
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/io.py +0 -7
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/workflow/workflow_processor.py +16 -1
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/.gitignore +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/LICENSE.md +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/README.md +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/cloud_llm.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/costs_dict.yaml +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/errors.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/generics_utils.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/grasp_logging.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/http_client.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/__init__.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/completion_chunk_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/completion_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/lite_llm.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/message_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/llm.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/memory.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/__init__.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/completion_chunk_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/completion_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/content_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/message_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/openai_llm.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/tool_converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/packet.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/packet_pool.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/rate_limiting/__init__.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/rate_limiting/rate_limiter_chunked.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/rate_limiting/types.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/rate_limiting/utils.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/runner.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/__init__.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/completion.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/completion_chunk.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/content.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/converters.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/events.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/message.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/typing/tool.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/usage_tracker.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/utils.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/workflow/__init__.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/workflow/looped_workflow.py +0 -0
- {grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/workflow/sequential_workflow.py +0 -0
@@ -10,7 +10,7 @@ from .processor import Processor
|
|
10
10
|
from .run_context import RunContext
|
11
11
|
from .typing.completion import Completion
|
12
12
|
from .typing.content import Content, ImageData
|
13
|
-
from .typing.io import LLMPrompt,
|
13
|
+
from .typing.io import LLMPrompt, ProcName
|
14
14
|
from .typing.message import AssistantMessage, Messages, SystemMessage, UserMessage
|
15
15
|
from .typing.tool import BaseTool
|
16
16
|
|
@@ -24,7 +24,6 @@ __all__ = [
|
|
24
24
|
"LLMAgent",
|
25
25
|
"LLMAgentMemory",
|
26
26
|
"LLMPrompt",
|
27
|
-
"LLMPromptArgs",
|
28
27
|
"LLMSettings",
|
29
28
|
"Memory",
|
30
29
|
"Messages",
|
@@ -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
14
|
from .processor import Processor
|
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,
|
@@ -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:
|
@@ -213,8 +203,8 @@ class LLMAgent(
|
|
213
203
|
in_args: InT | None = None,
|
214
204
|
ctx: RunContext[CtxT] | None = None,
|
215
205
|
) -> OutT:
|
216
|
-
if self.
|
217
|
-
return self.
|
206
|
+
if self.output_parser:
|
207
|
+
return self.output_parser(
|
218
208
|
conversation=conversation, in_args=in_args, ctx=ctx
|
219
209
|
)
|
220
210
|
|
@@ -302,108 +292,100 @@ class LLMAgent(
|
|
302
292
|
cur_cls = type(self)
|
303
293
|
base_cls = LLMAgent[Any, Any, Any]
|
304
294
|
|
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
295
|
# Prompt builder
|
310
296
|
|
311
|
-
if cur_cls.
|
312
|
-
self._prompt_builder.
|
297
|
+
if cur_cls.system_prompt_builder is not base_cls.system_prompt_builder:
|
298
|
+
self._prompt_builder.system_prompt_builder = self.system_prompt_builder
|
313
299
|
|
314
|
-
if cur_cls.
|
315
|
-
self._prompt_builder.
|
300
|
+
if cur_cls.input_content_builder is not base_cls.input_content_builder:
|
301
|
+
self._prompt_builder.input_content_builder = self.input_content_builder
|
316
302
|
|
317
303
|
# Policy executor
|
318
304
|
|
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
|
305
|
+
if cur_cls.tool_call_loop_terminator is not base_cls.tool_call_loop_terminator:
|
306
|
+
self._policy_executor.tool_call_loop_terminator = (
|
307
|
+
self.tool_call_loop_terminator
|
308
|
+
)
|
326
309
|
|
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
|
310
|
+
if cur_cls.memory_manager is not base_cls.memory_manager:
|
311
|
+
self._policy_executor.memory_manager = self.memory_manager
|
334
312
|
|
335
|
-
def
|
336
|
-
self
|
337
|
-
|
338
|
-
|
313
|
+
def system_prompt_builder(self, ctx: RunContext[CtxT] | None = None) -> str | None:
|
314
|
+
if self._prompt_builder.system_prompt_builder is not None:
|
315
|
+
return self._prompt_builder.system_prompt_builder(ctx=ctx)
|
316
|
+
raise NotImplementedError("System prompt builder is not implemented.")
|
339
317
|
|
340
|
-
def
|
318
|
+
def input_content_builder(
|
341
319
|
self, in_args: InT | None = None, *, ctx: RunContext[CtxT] | None = None
|
342
320
|
) -> Content:
|
343
|
-
|
321
|
+
if self._prompt_builder.input_content_builder is not None:
|
322
|
+
return self._prompt_builder.input_content_builder(in_args=in_args, ctx=ctx)
|
323
|
+
raise NotImplementedError("Input content builder is not implemented.")
|
344
324
|
|
345
|
-
def
|
325
|
+
def tool_call_loop_terminator(
|
346
326
|
self,
|
347
327
|
conversation: Messages,
|
348
328
|
*,
|
349
329
|
ctx: RunContext[CtxT] | None = None,
|
350
330
|
**kwargs: Any,
|
351
331
|
) -> bool:
|
352
|
-
|
353
|
-
|
354
|
-
|
332
|
+
if self._policy_executor.tool_call_loop_terminator is not None:
|
333
|
+
return self._policy_executor.tool_call_loop_terminator(
|
334
|
+
conversation=conversation, ctx=ctx, **kwargs
|
335
|
+
)
|
336
|
+
raise NotImplementedError("Tool call loop terminator is not implemented.")
|
355
337
|
|
356
|
-
def
|
338
|
+
def memory_manager(
|
357
339
|
self,
|
358
340
|
memory: LLMAgentMemory,
|
359
341
|
*,
|
360
342
|
ctx: RunContext[CtxT] | None = None,
|
361
343
|
**kwargs: Any,
|
362
344
|
) -> None:
|
363
|
-
|
364
|
-
|
365
|
-
|
345
|
+
if self._policy_executor.memory_manager is not None:
|
346
|
+
return self._policy_executor.memory_manager(
|
347
|
+
memory=memory, ctx=ctx, **kwargs
|
348
|
+
)
|
349
|
+
raise NotImplementedError("Memory manager is not implemented.")
|
366
350
|
|
367
351
|
# Decorators for custom implementations as an alternative to overriding methods
|
368
352
|
|
369
|
-
def
|
370
|
-
self, func:
|
371
|
-
) ->
|
372
|
-
self._prompt_builder.
|
353
|
+
def add_system_prompt_builder(
|
354
|
+
self, func: SystemPromptBuilder[CtxT]
|
355
|
+
) -> SystemPromptBuilder[CtxT]:
|
356
|
+
self._prompt_builder.system_prompt_builder = func
|
373
357
|
|
374
358
|
return func
|
375
359
|
|
376
|
-
def
|
377
|
-
self, func:
|
378
|
-
) ->
|
379
|
-
self._prompt_builder.
|
360
|
+
def add_input_content_builder(
|
361
|
+
self, func: InputContentBuilder[InT, CtxT]
|
362
|
+
) -> InputContentBuilder[InT, CtxT]:
|
363
|
+
self._prompt_builder.input_content_builder = func
|
380
364
|
|
381
365
|
return func
|
382
366
|
|
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
|
367
|
+
def add_memory_manager(self, func: MemoryManager[CtxT]) -> MemoryManager[CtxT]:
|
368
|
+
self._policy_executor.memory_manager = func
|
389
369
|
|
390
370
|
return func
|
391
371
|
|
392
|
-
def
|
393
|
-
self
|
372
|
+
def add_tool_call_loop_terminator(
|
373
|
+
self, func: ToolCallLoopTerminator[CtxT]
|
374
|
+
) -> ToolCallLoopTerminator[CtxT]:
|
375
|
+
self._policy_executor.tool_call_loop_terminator = func
|
394
376
|
|
395
377
|
return func
|
396
378
|
|
397
|
-
def
|
398
|
-
self, func:
|
399
|
-
) ->
|
400
|
-
self.
|
379
|
+
def add_output_parser(
|
380
|
+
self, func: OutputParser[InT, OutT, CtxT]
|
381
|
+
) -> OutputParser[InT, OutT, CtxT]:
|
382
|
+
if self._used_default_llm_response_schema:
|
383
|
+
self._policy_executor.llm.response_schema = None
|
384
|
+
self.output_parser = func
|
401
385
|
|
402
386
|
return func
|
403
387
|
|
404
|
-
def
|
405
|
-
self
|
406
|
-
) -> ExitToolCallLoopHandler[CtxT]:
|
407
|
-
self._policy_executor.exit_tool_call_loop_impl = func
|
388
|
+
def add_memory_preparator(self, func: MemoryPreparator) -> MemoryPreparator:
|
389
|
+
self.memory_preparator = func
|
408
390
|
|
409
391
|
return func
|
@@ -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
|
@@ -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)
|
@@ -34,7 +34,7 @@ logger = logging.getLogger(__name__)
|
|
34
34
|
_OutT_contra = TypeVar("_OutT_contra", contravariant=True)
|
35
35
|
|
36
36
|
|
37
|
-
class
|
37
|
+
class RecipientSelector(Protocol[_OutT_contra, CtxT]):
|
38
38
|
def __call__(
|
39
39
|
self, output: _OutT_contra, ctx: RunContext[CtxT] | None
|
40
40
|
) -> list[ProcName] | None: ...
|
@@ -61,8 +61,13 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
61
61
|
self._name: ProcName = name
|
62
62
|
self._memory: MemT = cast("MemT", DummyMemory())
|
63
63
|
self._max_retries: int = max_retries
|
64
|
+
|
64
65
|
self.recipients = recipients
|
65
|
-
|
66
|
+
|
67
|
+
self.recipient_selector: RecipientSelector[OutT, CtxT] | None
|
68
|
+
if not hasattr(type(self), "recipient_selector"):
|
69
|
+
# Set to None if not defined in the subclass
|
70
|
+
self.recipient_selector = None
|
66
71
|
|
67
72
|
@property
|
68
73
|
def in_type(self) -> type[InT]:
|
@@ -94,8 +99,8 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
94
99
|
call_id: str,
|
95
100
|
chat_inputs: Any | None = None,
|
96
101
|
in_packet: Packet[InT] | None = None,
|
97
|
-
in_args: InT |
|
98
|
-
) ->
|
102
|
+
in_args: InT | list[InT] | None = None,
|
103
|
+
) -> list[InT] | None:
|
99
104
|
mult_inputs_err_message = (
|
100
105
|
"Only one of chat_inputs, in_args, or in_message must be provided."
|
101
106
|
)
|
@@ -126,14 +131,14 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
126
131
|
if chat_inputs is not None:
|
127
132
|
return None
|
128
133
|
|
129
|
-
resolved_args:
|
134
|
+
resolved_args: list[InT]
|
130
135
|
|
131
|
-
if isinstance(in_args,
|
132
|
-
_in_args = cast("
|
136
|
+
if isinstance(in_args, list):
|
137
|
+
_in_args = cast("list[Any]", in_args)
|
133
138
|
if all(isinstance(x, self.in_type) for x in _in_args):
|
134
|
-
resolved_args = cast("
|
139
|
+
resolved_args = cast("list[InT]", _in_args)
|
135
140
|
elif isinstance(_in_args, self.in_type):
|
136
|
-
resolved_args = cast("
|
141
|
+
resolved_args = cast("list[InT]", [_in_args])
|
137
142
|
else:
|
138
143
|
raise ProcInputValidationError(
|
139
144
|
message=f"in_args are neither of type {self.in_type} "
|
@@ -142,11 +147,11 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
142
147
|
)
|
143
148
|
|
144
149
|
elif in_args is not None:
|
145
|
-
resolved_args = cast("
|
150
|
+
resolved_args = cast("list[InT]", [in_args])
|
146
151
|
|
147
152
|
else:
|
148
153
|
assert in_packet is not None
|
149
|
-
resolved_args = in_packet.payloads
|
154
|
+
resolved_args = cast("list[InT]", in_packet.payloads)
|
150
155
|
|
151
156
|
try:
|
152
157
|
for args in resolved_args:
|
@@ -167,7 +172,7 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
167
172
|
) from err
|
168
173
|
|
169
174
|
def _validate_recipients(
|
170
|
-
self, recipients:
|
175
|
+
self, recipients: list[ProcName] | None, call_id: str
|
171
176
|
) -> None:
|
172
177
|
for r in recipients or []:
|
173
178
|
if r not in (self.recipients or []):
|
@@ -191,6 +196,22 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
191
196
|
f"[proc_name={self.name}; call_id={call_id}]",
|
192
197
|
)
|
193
198
|
|
199
|
+
@final
|
200
|
+
def _select_recipients(
|
201
|
+
self, output: OutT, ctx: RunContext[CtxT] | None = None
|
202
|
+
) -> list[ProcName] | None:
|
203
|
+
if self.recipient_selector:
|
204
|
+
return self.recipient_selector(output=output, ctx=ctx)
|
205
|
+
|
206
|
+
return self.recipients
|
207
|
+
|
208
|
+
def add_recipient_selector(
|
209
|
+
self, func: RecipientSelector[OutT, CtxT]
|
210
|
+
) -> RecipientSelector[OutT, CtxT]:
|
211
|
+
self.recipient_selector = func
|
212
|
+
|
213
|
+
return func
|
214
|
+
|
194
215
|
async def _process(
|
195
216
|
self,
|
196
217
|
chat_inputs: Any | None = None,
|
@@ -275,7 +296,7 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
275
296
|
raise ProcRunError(proc_name=self.name, call_id=call_id)
|
276
297
|
|
277
298
|
async def _run_par(
|
278
|
-
self, in_args:
|
299
|
+
self, in_args: list[InT], call_id: str, ctx: RunContext[CtxT] | None = None
|
279
300
|
) -> Packet[OutT]:
|
280
301
|
tasks = [
|
281
302
|
self._run_single(
|
@@ -298,7 +319,7 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
298
319
|
chat_inputs: Any | None = None,
|
299
320
|
*,
|
300
321
|
in_packet: Packet[InT] | None = None,
|
301
|
-
in_args: InT |
|
322
|
+
in_args: InT | list[InT] | None = None,
|
302
323
|
forgetful: bool = False,
|
303
324
|
call_id: str | None = None,
|
304
325
|
ctx: RunContext[CtxT] | None = None,
|
@@ -406,7 +427,7 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
406
427
|
|
407
428
|
async def _run_par_stream(
|
408
429
|
self,
|
409
|
-
in_args:
|
430
|
+
in_args: list[InT],
|
410
431
|
call_id: str,
|
411
432
|
ctx: RunContext[CtxT] | None = None,
|
412
433
|
) -> AsyncIterator[Event[Any]]:
|
@@ -442,7 +463,7 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
442
463
|
chat_inputs: Any | None = None,
|
443
464
|
*,
|
444
465
|
in_packet: Packet[InT] | None = None,
|
445
|
-
in_args: InT |
|
466
|
+
in_args: InT | list[InT] | None = None,
|
446
467
|
forgetful: bool = False,
|
447
468
|
call_id: str | None = None,
|
448
469
|
ctx: RunContext[CtxT] | None = None,
|
@@ -469,21 +490,6 @@ class Processor(AutoInstanceAttributesMixin, ABC, Generic[InT, OutT, MemT, CtxT]
|
|
469
490
|
async for event in stream:
|
470
491
|
yield event
|
471
492
|
|
472
|
-
def _select_recipients(
|
473
|
-
self, output: OutT, ctx: RunContext[CtxT] | None = None
|
474
|
-
) -> list[ProcName] | None:
|
475
|
-
if self.select_recipients_impl:
|
476
|
-
return self.select_recipients_impl(output=output, ctx=ctx)
|
477
|
-
|
478
|
-
return self.recipients
|
479
|
-
|
480
|
-
def select_recipients(
|
481
|
-
self, func: SelectRecipientsHandler[OutT, CtxT]
|
482
|
-
) -> SelectRecipientsHandler[OutT, CtxT]:
|
483
|
-
self.select_recipients_impl = func
|
484
|
-
|
485
|
-
return func
|
486
|
-
|
487
493
|
@final
|
488
494
|
def as_tool(
|
489
495
|
self, tool_name: str, tool_description: str
|
@@ -1,34 +1,26 @@
|
|
1
1
|
import json
|
2
2
|
from collections.abc import Sequence
|
3
|
-
from typing import ClassVar, Generic, Protocol, TypeAlias, TypeVar
|
3
|
+
from typing import ClassVar, Generic, Protocol, TypeAlias, TypeVar, final
|
4
4
|
|
5
5
|
from pydantic import BaseModel, TypeAdapter
|
6
6
|
|
7
|
-
from .errors import InputPromptBuilderError
|
7
|
+
from .errors import InputPromptBuilderError
|
8
8
|
from .generics_utils import AutoInstanceAttributesMixin
|
9
9
|
from .run_context import CtxT, RunContext
|
10
10
|
from .typing.content import Content, ImageData
|
11
|
-
from .typing.io import InT, LLMPrompt
|
11
|
+
from .typing.io import InT, LLMPrompt
|
12
12
|
from .typing.message import UserMessage
|
13
13
|
|
14
14
|
_InT_contra = TypeVar("_InT_contra", contravariant=True)
|
15
15
|
|
16
16
|
|
17
|
-
class
|
18
|
-
def __call__(
|
19
|
-
self,
|
20
|
-
sys_args: LLMPromptArgs | None,
|
21
|
-
*,
|
22
|
-
ctx: RunContext[CtxT] | None,
|
23
|
-
) -> str | None: ...
|
17
|
+
class SystemPromptBuilder(Protocol[CtxT]):
|
18
|
+
def __call__(self, ctx: RunContext[CtxT] | None) -> str | None: ...
|
24
19
|
|
25
20
|
|
26
|
-
class
|
21
|
+
class InputContentBuilder(Protocol[_InT_contra, CtxT]):
|
27
22
|
def __call__(
|
28
|
-
self,
|
29
|
-
in_args: _InT_contra | None,
|
30
|
-
*,
|
31
|
-
ctx: RunContext[CtxT] | None,
|
23
|
+
self, in_args: _InT_contra | None, *, ctx: RunContext[CtxT] | None
|
32
24
|
) -> Content: ...
|
33
25
|
|
34
26
|
|
@@ -39,11 +31,7 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
39
31
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {0: "_in_type"}
|
40
32
|
|
41
33
|
def __init__(
|
42
|
-
self,
|
43
|
-
agent_name: str,
|
44
|
-
sys_prompt: LLMPrompt | None,
|
45
|
-
in_prompt: LLMPrompt | None,
|
46
|
-
sys_args_schema: type[LLMPromptArgs] | None = None,
|
34
|
+
self, agent_name: str, sys_prompt: LLMPrompt | None, in_prompt: LLMPrompt | None
|
47
35
|
):
|
48
36
|
self._in_type: type[InT]
|
49
37
|
super().__init__()
|
@@ -51,45 +39,17 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
51
39
|
self._agent_name = agent_name
|
52
40
|
self.sys_prompt = sys_prompt
|
53
41
|
self.in_prompt = in_prompt
|
54
|
-
self.
|
55
|
-
self.
|
56
|
-
self.make_input_content_impl: MakeInputContentHandler[InT, CtxT] | None = None
|
42
|
+
self.system_prompt_builder: SystemPromptBuilder[CtxT] | None = None
|
43
|
+
self.input_content_builder: InputContentBuilder[InT, CtxT] | None = None
|
57
44
|
|
58
45
|
self._in_args_type_adapter: TypeAdapter[InT] = TypeAdapter(self._in_type)
|
59
46
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
if sys_args is not None:
|
65
|
-
if self.sys_args_schema is not None:
|
66
|
-
val_sys_args = self.sys_args_schema.model_validate(sys_args)
|
67
|
-
else:
|
68
|
-
raise SystemPromptBuilderError(
|
69
|
-
proc_name=self._agent_name,
|
70
|
-
message="System prompt template and arguments is set, "
|
71
|
-
"but system arguments schema is not provided "
|
72
|
-
f"[agent_name={self._agent_name}]",
|
73
|
-
)
|
74
|
-
|
75
|
-
return val_sys_args
|
76
|
-
|
77
|
-
def make_system_prompt(
|
78
|
-
self,
|
79
|
-
sys_args: LLMPromptArgs | None = None,
|
80
|
-
ctx: RunContext[CtxT] | None = None,
|
81
|
-
) -> str | None:
|
82
|
-
if self.sys_prompt is None:
|
83
|
-
return None
|
84
|
-
|
85
|
-
val_sys_args = self._validate_sys_args(sys_args=sys_args)
|
86
|
-
|
87
|
-
if self.make_system_prompt_impl:
|
88
|
-
return self.make_system_prompt_impl(sys_args=val_sys_args, ctx=ctx)
|
89
|
-
|
90
|
-
sys_args_dict = val_sys_args.model_dump() if val_sys_args else {}
|
47
|
+
@final
|
48
|
+
def build_system_prompt(self, ctx: RunContext[CtxT] | None = None) -> str | None:
|
49
|
+
if self.system_prompt_builder:
|
50
|
+
return self.system_prompt_builder(ctx=ctx)
|
91
51
|
|
92
|
-
return self.sys_prompt
|
52
|
+
return self.sys_prompt
|
93
53
|
|
94
54
|
def _validate_input_args(self, in_args: InT) -> InT:
|
95
55
|
val_in_args = self._in_args_type_adapter.validate_python(in_args)
|
@@ -111,7 +71,8 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
111
71
|
|
112
72
|
return val_in_args
|
113
73
|
|
114
|
-
|
74
|
+
@final
|
75
|
+
def _build_input_content(
|
115
76
|
self,
|
116
77
|
in_args: InT | None = None,
|
117
78
|
ctx: RunContext[CtxT] | None = None,
|
@@ -120,8 +81,8 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
120
81
|
if in_args is not None:
|
121
82
|
val_in_args = self._validate_input_args(in_args=in_args)
|
122
83
|
|
123
|
-
if self.
|
124
|
-
return self.
|
84
|
+
if self.input_content_builder:
|
85
|
+
return self.input_content_builder(in_args=val_in_args, ctx=ctx)
|
125
86
|
|
126
87
|
if val_in_args is None:
|
127
88
|
raise InputPromptBuilderError(
|
@@ -141,7 +102,8 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
141
102
|
).decode("utf-8")
|
142
103
|
return Content.from_text(fmt_in_args)
|
143
104
|
|
144
|
-
|
105
|
+
@final
|
106
|
+
def build_input_message(
|
145
107
|
self,
|
146
108
|
chat_inputs: LLMPrompt | Sequence[str | ImageData] | None = None,
|
147
109
|
in_args: InT | None = None,
|
@@ -160,7 +122,7 @@ class PromptBuilder(AutoInstanceAttributesMixin, Generic[InT, CtxT]):
|
|
160
122
|
return UserMessage.from_content_parts(chat_inputs, name=self._agent_name)
|
161
123
|
|
162
124
|
return UserMessage(
|
163
|
-
content=self.
|
125
|
+
content=self._build_input_content(in_args=in_args, ctx=ctx),
|
164
126
|
name=self._agent_name,
|
165
127
|
)
|
166
128
|
|
@@ -6,7 +6,7 @@ from pydantic import BaseModel, ConfigDict, Field
|
|
6
6
|
from grasp_agents.typing.completion import Completion
|
7
7
|
|
8
8
|
from .printer import ColoringMode, Printer
|
9
|
-
from .typing.io import
|
9
|
+
from .typing.io import ProcName
|
10
10
|
from .usage_tracker import UsageTracker
|
11
11
|
|
12
12
|
CtxT = TypeVar("CtxT")
|
@@ -15,22 +15,17 @@ CtxT = TypeVar("CtxT")
|
|
15
15
|
class RunContext(BaseModel, Generic[CtxT]):
|
16
16
|
state: CtxT | None = None
|
17
17
|
|
18
|
-
sys_args: dict[ProcName, LLMPromptArgs] = Field(default_factory=dict)
|
19
|
-
|
20
|
-
is_streaming: bool = False
|
21
|
-
result: Any | None = None
|
22
|
-
|
23
18
|
completions: dict[ProcName, list[Completion]] = Field(
|
24
19
|
default_factory=lambda: defaultdict(list)
|
25
20
|
)
|
26
21
|
usage_tracker: UsageTracker = Field(default_factory=UsageTracker)
|
27
22
|
|
28
23
|
printer: Printer | None = None
|
29
|
-
|
24
|
+
log_messages: bool = False
|
30
25
|
color_messages_by: ColoringMode = "role"
|
31
26
|
|
32
27
|
def model_post_init(self, context: Any) -> None: # noqa: ARG002
|
33
|
-
if self.
|
28
|
+
if self.log_messages:
|
34
29
|
self.printer = Printer(color_by=self.color_messages_by)
|
35
30
|
|
36
31
|
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
|
@@ -4,7 +4,7 @@ from typing import Any, Generic
|
|
4
4
|
|
5
5
|
from ..errors import WorkflowConstructionError
|
6
6
|
from ..packet import Packet
|
7
|
-
from ..processor import Processor
|
7
|
+
from ..processor import Processor, RecipientSelector
|
8
8
|
from ..run_context import CtxT, RunContext
|
9
9
|
from ..typing.events import Event
|
10
10
|
from ..typing.io import InT, OutT, ProcName
|
@@ -44,6 +44,21 @@ class WorkflowProcessor(
|
|
44
44
|
self._start_proc = start_proc
|
45
45
|
self._end_proc = end_proc
|
46
46
|
|
47
|
+
self.recipients = end_proc.recipients
|
48
|
+
if recipients is not None:
|
49
|
+
self.recipients = recipients
|
50
|
+
|
51
|
+
if hasattr(type(self), "recipient_selector"):
|
52
|
+
self._end_proc.recipient_selector = self.recipient_selector
|
53
|
+
|
54
|
+
def add_recipient_selector(
|
55
|
+
self, func: RecipientSelector[OutT, CtxT]
|
56
|
+
) -> RecipientSelector[OutT, CtxT]:
|
57
|
+
self._end_proc.recipient_selector = func
|
58
|
+
self.recipient_selector = func
|
59
|
+
|
60
|
+
return func
|
61
|
+
|
47
62
|
@property
|
48
63
|
def subprocs(self) -> Sequence[Processor[Any, Any, Any, CtxT]]:
|
49
64
|
return self._subprocs
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/litellm/completion_chunk_converters.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/openai/completion_chunk_converters.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{grasp_agents-0.5.4 → grasp_agents-0.5.5}/src/grasp_agents/rate_limiting/rate_limiter_chunked.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|