grasp_agents 0.3.11__py3-none-any.whl → 0.4.2__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/cloud_llm.py +57 -74
- grasp_agents/comm_processor.py +21 -11
- grasp_agents/errors.py +34 -0
- grasp_agents/http_client.py +7 -5
- grasp_agents/llm.py +3 -9
- grasp_agents/llm_agent.py +92 -103
- grasp_agents/llm_agent_memory.py +36 -27
- grasp_agents/llm_policy_executor.py +73 -66
- grasp_agents/memory.py +3 -1
- grasp_agents/openai/completion_chunk_converters.py +4 -3
- grasp_agents/openai/openai_llm.py +14 -20
- grasp_agents/openai/tool_converters.py +0 -1
- grasp_agents/packet_pool.py +1 -1
- grasp_agents/printer.py +6 -6
- grasp_agents/processor.py +182 -48
- grasp_agents/prompt_builder.py +41 -55
- grasp_agents/run_context.py +1 -5
- grasp_agents/typing/completion_chunk.py +10 -5
- grasp_agents/typing/content.py +3 -2
- grasp_agents/typing/io.py +4 -4
- grasp_agents/typing/message.py +3 -8
- grasp_agents/typing/tool.py +5 -23
- grasp_agents/usage_tracker.py +2 -4
- grasp_agents/utils.py +37 -15
- grasp_agents/workflow/looped_workflow.py +14 -9
- grasp_agents/workflow/sequential_workflow.py +11 -6
- grasp_agents/workflow/workflow_processor.py +30 -13
- {grasp_agents-0.3.11.dist-info → grasp_agents-0.4.2.dist-info}/METADATA +3 -2
- grasp_agents-0.4.2.dist-info/RECORD +50 -0
- grasp_agents/message_history.py +0 -140
- grasp_agents/workflow/parallel_processor.py +0 -95
- grasp_agents-0.3.11.dist-info/RECORD +0 -51
- {grasp_agents-0.3.11.dist-info → grasp_agents-0.4.2.dist-info}/WHEEL +0 -0
- {grasp_agents-0.3.11.dist-info → grasp_agents-0.4.2.dist-info}/licenses/LICENSE.md +0 -0
grasp_agents/typing/message.py
CHANGED
@@ -42,12 +42,10 @@ class UserMessage(MessageBase):
|
|
42
42
|
def from_formatted_prompt(
|
43
43
|
cls,
|
44
44
|
prompt_template: str,
|
45
|
-
prompt_args: Mapping[str, str | int | bool | ImageData] | None = None,
|
46
45
|
name: str | None = None,
|
46
|
+
prompt_args: Mapping[str, str | int | bool | ImageData] | None = None,
|
47
47
|
) -> "UserMessage":
|
48
|
-
content = Content.from_formatted_prompt(
|
49
|
-
prompt_template=prompt_template, prompt_args=prompt_args
|
50
|
-
)
|
48
|
+
content = Content.from_formatted_prompt(prompt_template, **(prompt_args or {}))
|
51
49
|
|
52
50
|
return cls(content=content, name=name)
|
53
51
|
|
@@ -74,10 +72,7 @@ class ToolMessage(MessageBase):
|
|
74
72
|
|
75
73
|
@classmethod
|
76
74
|
def from_tool_output(
|
77
|
-
cls,
|
78
|
-
tool_output: Any,
|
79
|
-
tool_call: ToolCall,
|
80
|
-
indent: int = 2,
|
75
|
+
cls, tool_output: Any, tool_call: ToolCall, indent: int = 2
|
81
76
|
) -> "ToolMessage":
|
82
77
|
return cls(
|
83
78
|
content=json.dumps(tool_output, default=pydantic_encoder, indent=indent),
|
grasp_agents/typing/tool.py
CHANGED
@@ -24,7 +24,7 @@ else:
|
|
24
24
|
"""Runtime placeholder so RunContext[CtxT] works"""
|
25
25
|
|
26
26
|
|
27
|
-
|
27
|
+
_InT = TypeVar("_InT", bound=BaseModel)
|
28
28
|
_OutT_co = TypeVar("_OutT_co", covariant=True)
|
29
29
|
|
30
30
|
|
@@ -38,7 +38,7 @@ class BaseTool(
|
|
38
38
|
AutoInstanceAttributesMixin,
|
39
39
|
BaseModel,
|
40
40
|
ABC,
|
41
|
-
Generic[
|
41
|
+
Generic[_InT, _OutT_co, CtxT],
|
42
42
|
):
|
43
43
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {
|
44
44
|
0: "_in_type",
|
@@ -48,37 +48,19 @@ class BaseTool(
|
|
48
48
|
name: str
|
49
49
|
description: str
|
50
50
|
|
51
|
-
_in_type: type[
|
51
|
+
_in_type: type[_InT] = PrivateAttr()
|
52
52
|
_out_type: type[_OutT_co] = PrivateAttr()
|
53
53
|
|
54
|
-
# _in_type_adapter: TypeAdapter[_InT_contra] = PrivateAttr()
|
55
|
-
# _out_type_adapter: TypeAdapter[_OutT_co] = PrivateAttr()
|
56
|
-
|
57
|
-
# def model_post_init(self, context: Any) -> None:
|
58
|
-
# self._in_type_adapter = TypeAdapter(self._in_type)
|
59
|
-
# self._out_type_adapter = TypeAdapter(self._out_type)
|
60
|
-
|
61
54
|
@property
|
62
|
-
def in_type(self) -> type[
|
63
|
-
# Exposing the type of a contravariant variable only, should be type safe
|
55
|
+
def in_type(self) -> type[_InT]:
|
64
56
|
return self._in_type
|
65
57
|
|
66
58
|
@property
|
67
59
|
def out_type(self) -> type[_OutT_co]:
|
68
60
|
return self._out_type
|
69
61
|
|
70
|
-
# @property
|
71
|
-
# def in_type_adapter(self) -> TypeAdapter[_InT_contra]:
|
72
|
-
# return self._in_type_adapter
|
73
|
-
|
74
|
-
# @property
|
75
|
-
# def out_type_adapter(self) -> TypeAdapter[_OutT_co]:
|
76
|
-
# return self._out_type_adapter
|
77
|
-
|
78
62
|
@abstractmethod
|
79
|
-
async def run(
|
80
|
-
self, inp: _InT_contra, ctx: RunContext[CtxT] | None = None
|
81
|
-
) -> _OutT_co:
|
63
|
+
async def run(self, inp: _InT, ctx: RunContext[CtxT] | None = None) -> _OutT_co:
|
82
64
|
pass
|
83
65
|
|
84
66
|
async def __call__(
|
grasp_agents/usage_tracker.py
CHANGED
@@ -21,7 +21,6 @@ CostsDict: TypeAlias = dict[str, ModelCostsDict]
|
|
21
21
|
|
22
22
|
class UsageTracker(BaseModel):
|
23
23
|
# TODO: specify different costs per provider:model, not just per model
|
24
|
-
source_id: str
|
25
24
|
costs_dict_path: str | Path = COSTS_DICT_PATH
|
26
25
|
costs_dict: CostsDict | None = None
|
27
26
|
usages: dict[str, Usage] = Field(default_factory=dict)
|
@@ -92,8 +91,7 @@ class UsageTracker(BaseModel):
|
|
92
91
|
logger.debug("\n-------------------")
|
93
92
|
|
94
93
|
token_usage_str = (
|
95
|
-
f"Total
|
96
|
-
f"{usage.input_tokens}/{usage.output_tokens}"
|
94
|
+
f"Total I/O/(R)/(C) tokens: {usage.input_tokens}/{usage.output_tokens}"
|
97
95
|
)
|
98
96
|
if usage.reasoning_tokens is not None:
|
99
97
|
token_usage_str += f"/{usage.reasoning_tokens}"
|
@@ -104,7 +102,7 @@ class UsageTracker(BaseModel):
|
|
104
102
|
if usage.cost is not None:
|
105
103
|
logger.debug(
|
106
104
|
colored(
|
107
|
-
f"Total
|
105
|
+
f"Total cost: ${usage.cost:.4f}",
|
108
106
|
"light_grey",
|
109
107
|
)
|
110
108
|
)
|
grasp_agents/utils.py
CHANGED
@@ -6,11 +6,13 @@ 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, get_args, overload
|
9
|
+
from typing import Annotated, Any, TypeVar, get_args, get_origin, overload
|
10
10
|
|
11
11
|
from pydantic import TypeAdapter, ValidationError
|
12
12
|
from tqdm.autonotebook import tqdm
|
13
13
|
|
14
|
+
from .errors import OutputValidationError, StringParsingError
|
15
|
+
|
14
16
|
logger = getLogger(__name__)
|
15
17
|
|
16
18
|
_JSON_START_RE = re.compile(r"[{\[]")
|
@@ -25,35 +27,41 @@ def extract_json_substring(text: str) -> str | None:
|
|
25
27
|
try:
|
26
28
|
_, end = decoder.raw_decode(text, idx=start)
|
27
29
|
return text[start:end]
|
28
|
-
except
|
30
|
+
except json.JSONDecodeError:
|
29
31
|
continue
|
30
32
|
|
31
33
|
return None
|
32
34
|
|
33
35
|
|
34
36
|
def parse_json_or_py_string(
|
35
|
-
s: str, return_none_on_failure: bool = False
|
37
|
+
s: str, return_none_on_failure: bool = False, strip_language_markdown: bool = True
|
36
38
|
) -> dict[str, Any] | list[Any] | None:
|
37
|
-
|
39
|
+
s_orig = s
|
40
|
+
if strip_language_markdown:
|
41
|
+
s = re.sub(r"```[a-zA-Z0-9]*\n|```", "", s).strip()
|
38
42
|
try:
|
39
|
-
return ast.literal_eval(
|
43
|
+
return ast.literal_eval(s)
|
40
44
|
except (ValueError, SyntaxError):
|
41
45
|
try:
|
42
|
-
return json.loads(
|
46
|
+
return json.loads(s)
|
43
47
|
except json.JSONDecodeError as exc:
|
44
48
|
if return_none_on_failure:
|
45
49
|
return None
|
46
|
-
raise
|
50
|
+
raise StringParsingError(
|
47
51
|
"Invalid JSON/Python string - Both ast.literal_eval and json.loads "
|
48
|
-
f"failed to parse the following response:\n{
|
52
|
+
f"failed to parse the following response:\n{s_orig}"
|
49
53
|
) from exc
|
50
54
|
|
51
55
|
|
52
56
|
def parse_json_or_py_substring(
|
53
|
-
json_str: str,
|
57
|
+
json_str: str,
|
58
|
+
return_none_on_failure: bool = False,
|
59
|
+
strip_language_markdown: bool = True,
|
54
60
|
) -> dict[str, Any] | list[Any] | None:
|
55
61
|
return parse_json_or_py_string(
|
56
|
-
extract_json_substring(json_str) or "",
|
62
|
+
extract_json_substring(json_str) or "",
|
63
|
+
return_none_on_failure=return_none_on_failure,
|
64
|
+
strip_language_markdown=strip_language_markdown,
|
57
65
|
)
|
58
66
|
|
59
67
|
|
@@ -62,6 +70,7 @@ def validate_obj_from_json_or_py_string(
|
|
62
70
|
s: str,
|
63
71
|
adapter: TypeAdapter[T],
|
64
72
|
from_substring: bool = False,
|
73
|
+
strip_language_markdown: bool = True,
|
65
74
|
) -> T: ...
|
66
75
|
|
67
76
|
|
@@ -70,6 +79,7 @@ def validate_obj_from_json_or_py_string(
|
|
70
79
|
s: str,
|
71
80
|
adapter: Mapping[str, TypeAdapter[T]],
|
72
81
|
from_substring: bool = False,
|
82
|
+
strip_language_markdown: bool = True,
|
73
83
|
) -> T | str: ...
|
74
84
|
|
75
85
|
|
@@ -77,6 +87,7 @@ def validate_obj_from_json_or_py_string(
|
|
77
87
|
s: str,
|
78
88
|
adapter: TypeAdapter[T] | Mapping[str, TypeAdapter[T]],
|
79
89
|
from_substring: bool = False,
|
90
|
+
strip_language_markdown: bool = True,
|
80
91
|
) -> T | str:
|
81
92
|
_selected_adapter: TypeAdapter[T] | None = None
|
82
93
|
if isinstance(adapter, Mapping):
|
@@ -89,22 +100,33 @@ def validate_obj_from_json_or_py_string(
|
|
89
100
|
_selected_adapter = adapter
|
90
101
|
|
91
102
|
_type = _selected_adapter._type # type: ignore[attr-defined]
|
103
|
+
type_origin = get_origin(_type)
|
92
104
|
type_args = get_args(_type)
|
93
|
-
is_str_type = (_type is str) or (
|
105
|
+
is_str_type = (_type is str) or (
|
106
|
+
type_origin is Annotated and type_args and type_args[0] is str
|
107
|
+
)
|
94
108
|
|
95
109
|
try:
|
96
110
|
if not is_str_type:
|
97
111
|
if from_substring:
|
98
|
-
parsed = parse_json_or_py_substring(
|
112
|
+
parsed = parse_json_or_py_substring(
|
113
|
+
s,
|
114
|
+
return_none_on_failure=True,
|
115
|
+
strip_language_markdown=strip_language_markdown,
|
116
|
+
)
|
99
117
|
else:
|
100
|
-
parsed = parse_json_or_py_string(
|
118
|
+
parsed = parse_json_or_py_string(
|
119
|
+
s,
|
120
|
+
return_none_on_failure=True,
|
121
|
+
strip_language_markdown=strip_language_markdown,
|
122
|
+
)
|
101
123
|
if parsed is None:
|
102
124
|
parsed = s
|
103
125
|
else:
|
104
126
|
parsed = s
|
105
127
|
return _selected_adapter.validate_python(parsed)
|
106
|
-
except
|
107
|
-
raise
|
128
|
+
except ValidationError as exc:
|
129
|
+
raise OutputValidationError(
|
108
130
|
f"Invalid JSON or Python string:\n{s}\nExpected type: {_type}"
|
109
131
|
) from exc
|
110
132
|
|
@@ -3,10 +3,11 @@ from itertools import pairwise
|
|
3
3
|
from logging import getLogger
|
4
4
|
from typing import Any, ClassVar, Generic, Protocol, TypeVar, cast, final
|
5
5
|
|
6
|
+
from ..errors import WorkflowConstructionError
|
6
7
|
from ..packet_pool import Packet, PacketPool
|
7
8
|
from ..processor import Processor
|
8
9
|
from ..run_context import CtxT, RunContext
|
9
|
-
from ..typing.io import
|
10
|
+
from ..typing.io import InT, OutT_co, ProcName
|
10
11
|
from .workflow_processor import WorkflowProcessor
|
11
12
|
|
12
13
|
logger = getLogger(__name__)
|
@@ -24,7 +25,7 @@ class ExitWorkflowLoopHandler(Protocol[_OutT_contra, CtxT]):
|
|
24
25
|
|
25
26
|
|
26
27
|
class LoopedWorkflow(
|
27
|
-
WorkflowProcessor[
|
28
|
+
WorkflowProcessor[InT, OutT_co, CtxT], Generic[InT, OutT_co, CtxT]
|
28
29
|
):
|
29
30
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {
|
30
31
|
0: "_in_type",
|
@@ -38,6 +39,7 @@ class LoopedWorkflow(
|
|
38
39
|
exit_proc: Processor[Any, OutT_co, Any, CtxT],
|
39
40
|
packet_pool: PacketPool[CtxT] | None = None,
|
40
41
|
recipients: list[ProcName] | None = None,
|
42
|
+
num_par_run_retries: int = 0,
|
41
43
|
max_iterations: int = 10,
|
42
44
|
) -> None:
|
43
45
|
super().__init__(
|
@@ -47,17 +49,18 @@ class LoopedWorkflow(
|
|
47
49
|
end_proc=exit_proc,
|
48
50
|
packet_pool=packet_pool,
|
49
51
|
recipients=recipients,
|
52
|
+
num_par_run_retries=num_par_run_retries,
|
50
53
|
)
|
51
54
|
|
52
55
|
for prev_proc, proc in pairwise(subprocs):
|
53
56
|
if prev_proc.out_type != proc.in_type:
|
54
|
-
raise
|
57
|
+
raise WorkflowConstructionError(
|
55
58
|
f"Output type {prev_proc.out_type} of subprocessor "
|
56
59
|
f"{prev_proc.name} does not match input type {proc.in_type} of "
|
57
60
|
f"subprocessor {proc.name}"
|
58
61
|
)
|
59
62
|
if subprocs[-1].out_type != subprocs[0].in_type:
|
60
|
-
raise
|
63
|
+
raise WorkflowConstructionError(
|
61
64
|
"Looped workflow's last subprocessor output type "
|
62
65
|
f"{subprocs[-1].out_type} does not match first subprocessor input "
|
63
66
|
f"type {subprocs[0].in_type}"
|
@@ -80,7 +83,7 @@ class LoopedWorkflow(
|
|
80
83
|
|
81
84
|
return func
|
82
85
|
|
83
|
-
def
|
86
|
+
def _exit_workflow_loop(
|
84
87
|
self,
|
85
88
|
out_packet: Packet[OutT_co],
|
86
89
|
*,
|
@@ -97,10 +100,11 @@ class LoopedWorkflow(
|
|
97
100
|
self,
|
98
101
|
chat_inputs: Any | None = None,
|
99
102
|
*,
|
100
|
-
in_packet: Packet[
|
101
|
-
in_args:
|
102
|
-
|
103
|
+
in_packet: Packet[InT] | None = None,
|
104
|
+
in_args: InT | Sequence[InT] | None = None,
|
105
|
+
run_id: str | None = None,
|
103
106
|
forgetful: bool = False,
|
107
|
+
ctx: RunContext[CtxT] | None = None,
|
104
108
|
) -> Packet[OutT_co]:
|
105
109
|
packet = in_packet
|
106
110
|
num_iterations = 0
|
@@ -113,13 +117,14 @@ class LoopedWorkflow(
|
|
113
117
|
in_packet=packet,
|
114
118
|
in_args=in_args,
|
115
119
|
forgetful=forgetful,
|
120
|
+
run_id=self._generate_subproc_run_id(run_id, subproc=subproc),
|
116
121
|
ctx=ctx,
|
117
122
|
)
|
118
123
|
|
119
124
|
if subproc is self._end_proc:
|
120
125
|
num_iterations += 1
|
121
126
|
exit_packet = cast("Packet[OutT_co]", packet)
|
122
|
-
if self.
|
127
|
+
if self._exit_workflow_loop(exit_packet, ctx=ctx):
|
123
128
|
return exit_packet
|
124
129
|
if num_iterations >= self._max_iterations:
|
125
130
|
logger.info(
|
@@ -2,15 +2,16 @@ from collections.abc import Sequence
|
|
2
2
|
from itertools import pairwise
|
3
3
|
from typing import Any, ClassVar, Generic, cast, final
|
4
4
|
|
5
|
+
from ..errors import WorkflowConstructionError
|
5
6
|
from ..packet_pool import Packet, PacketPool
|
6
7
|
from ..processor import Processor
|
7
8
|
from ..run_context import CtxT, RunContext
|
8
|
-
from ..typing.io import
|
9
|
+
from ..typing.io import InT, OutT_co, ProcName
|
9
10
|
from .workflow_processor import WorkflowProcessor
|
10
11
|
|
11
12
|
|
12
13
|
class SequentialWorkflow(
|
13
|
-
WorkflowProcessor[
|
14
|
+
WorkflowProcessor[InT, OutT_co, CtxT], Generic[InT, OutT_co, CtxT]
|
14
15
|
):
|
15
16
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {
|
16
17
|
0: "_in_type",
|
@@ -23,6 +24,7 @@ class SequentialWorkflow(
|
|
23
24
|
subprocs: Sequence[Processor[Any, Any, Any, CtxT]],
|
24
25
|
packet_pool: PacketPool[CtxT] | None = None,
|
25
26
|
recipients: list[ProcName] | None = None,
|
27
|
+
num_par_run_retries: int = 0,
|
26
28
|
) -> None:
|
27
29
|
super().__init__(
|
28
30
|
subprocs=subprocs,
|
@@ -31,11 +33,12 @@ class SequentialWorkflow(
|
|
31
33
|
name=name,
|
32
34
|
packet_pool=packet_pool,
|
33
35
|
recipients=recipients,
|
36
|
+
num_par_run_retries=num_par_run_retries,
|
34
37
|
)
|
35
38
|
|
36
39
|
for prev_proc, proc in pairwise(subprocs):
|
37
40
|
if prev_proc.out_type != proc.in_type:
|
38
|
-
raise
|
41
|
+
raise WorkflowConstructionError(
|
39
42
|
f"Output type {prev_proc.out_type} of subprocessor {prev_proc.name}"
|
40
43
|
f" does not match input type {proc.in_type} of subprocessor"
|
41
44
|
f" {proc.name}"
|
@@ -46,10 +49,11 @@ class SequentialWorkflow(
|
|
46
49
|
self,
|
47
50
|
chat_inputs: Any | None = None,
|
48
51
|
*,
|
49
|
-
in_packet: Packet[
|
50
|
-
in_args:
|
51
|
-
ctx: RunContext[CtxT] | None = None,
|
52
|
+
in_packet: Packet[InT] | None = None,
|
53
|
+
in_args: InT | Sequence[InT] | None = None,
|
52
54
|
forgetful: bool = False,
|
55
|
+
run_id: str | None = None,
|
56
|
+
ctx: RunContext[CtxT] | None = None,
|
53
57
|
) -> Packet[OutT_co]:
|
54
58
|
packet = in_packet
|
55
59
|
for subproc in self.subprocs:
|
@@ -58,6 +62,7 @@ class SequentialWorkflow(
|
|
58
62
|
in_packet=packet,
|
59
63
|
in_args=in_args,
|
60
64
|
forgetful=forgetful,
|
65
|
+
run_id=self._generate_subproc_run_id(run_id, subproc),
|
61
66
|
ctx=ctx,
|
62
67
|
)
|
63
68
|
chat_inputs = None
|
@@ -3,17 +3,18 @@ from collections.abc import Sequence
|
|
3
3
|
from typing import Any, ClassVar, Generic
|
4
4
|
|
5
5
|
from ..comm_processor import CommProcessor
|
6
|
+
from ..errors import WorkflowConstructionError
|
6
7
|
from ..packet import Packet
|
7
8
|
from ..packet_pool import PacketPool
|
8
9
|
from ..processor import Processor
|
9
10
|
from ..run_context import CtxT, RunContext
|
10
|
-
from ..typing.io import
|
11
|
+
from ..typing.io import InT, OutT_co, ProcName
|
11
12
|
|
12
13
|
|
13
14
|
class WorkflowProcessor(
|
14
|
-
CommProcessor[
|
15
|
+
CommProcessor[InT, OutT_co, Any, CtxT],
|
15
16
|
ABC,
|
16
|
-
Generic[
|
17
|
+
Generic[InT, OutT_co, CtxT],
|
17
18
|
):
|
18
19
|
_generic_arg_to_instance_attr_map: ClassVar[dict[int, str]] = {
|
19
20
|
0: "_in_type",
|
@@ -24,27 +25,37 @@ class WorkflowProcessor(
|
|
24
25
|
self,
|
25
26
|
name: ProcName,
|
26
27
|
subprocs: Sequence[Processor[Any, Any, Any, CtxT]],
|
27
|
-
start_proc: Processor[
|
28
|
+
start_proc: Processor[InT, Any, Any, CtxT],
|
28
29
|
end_proc: Processor[Any, OutT_co, Any, CtxT],
|
29
30
|
packet_pool: PacketPool[CtxT] | None = None,
|
30
31
|
recipients: list[ProcName] | None = None,
|
32
|
+
num_par_run_retries: int = 0,
|
31
33
|
) -> None:
|
32
|
-
super().__init__(
|
34
|
+
super().__init__(
|
35
|
+
name=name,
|
36
|
+
packet_pool=packet_pool,
|
37
|
+
recipients=recipients,
|
38
|
+
num_par_run_retries=num_par_run_retries,
|
39
|
+
)
|
33
40
|
|
34
41
|
if len(subprocs) < 2:
|
35
|
-
raise
|
42
|
+
raise WorkflowConstructionError("At least two subprocessors are required")
|
36
43
|
if start_proc not in subprocs:
|
37
|
-
raise
|
44
|
+
raise WorkflowConstructionError(
|
45
|
+
"Start subprocessor must be in the subprocessors list"
|
46
|
+
)
|
38
47
|
if end_proc not in subprocs:
|
39
|
-
raise
|
48
|
+
raise WorkflowConstructionError(
|
49
|
+
"End subprocessor must be in the subprocessors list"
|
50
|
+
)
|
40
51
|
|
41
52
|
if start_proc.in_type != self.in_type:
|
42
|
-
raise
|
53
|
+
raise WorkflowConstructionError(
|
43
54
|
f"Start subprocessor's input type {start_proc.in_type} does not "
|
44
55
|
f"match workflow's input type {self._in_type}"
|
45
56
|
)
|
46
57
|
if end_proc.out_type != self.out_type:
|
47
|
-
raise
|
58
|
+
raise WorkflowConstructionError(
|
48
59
|
f"End subprocessor's output type {end_proc.out_type} does not "
|
49
60
|
f"match workflow's output type {self._out_type}"
|
50
61
|
)
|
@@ -58,21 +69,27 @@ class WorkflowProcessor(
|
|
58
69
|
return self._subprocs
|
59
70
|
|
60
71
|
@property
|
61
|
-
def start_proc(self) -> Processor[
|
72
|
+
def start_proc(self) -> Processor[InT, Any, Any, CtxT]:
|
62
73
|
return self._start_proc
|
63
74
|
|
64
75
|
@property
|
65
76
|
def end_proc(self) -> Processor[Any, OutT_co, Any, CtxT]:
|
66
77
|
return self._end_proc
|
67
78
|
|
79
|
+
def _generate_subproc_run_id(
|
80
|
+
self, run_id: str | None, subproc: Processor[Any, Any, Any, CtxT]
|
81
|
+
) -> str | None:
|
82
|
+
return f"{self._generate_run_id(run_id)}/{subproc.name}"
|
83
|
+
|
68
84
|
@abstractmethod
|
69
85
|
async def run(
|
70
86
|
self,
|
71
87
|
chat_inputs: Any | None = None,
|
72
88
|
*,
|
73
|
-
in_packet: Packet[
|
74
|
-
in_args:
|
89
|
+
in_packet: Packet[InT] | None = None,
|
90
|
+
in_args: InT | Sequence[InT] | None = None,
|
75
91
|
ctx: RunContext[CtxT] | None = None,
|
76
92
|
forgetful: bool = False,
|
93
|
+
run_id: str | None = None,
|
77
94
|
) -> Packet[OutT_co]:
|
78
95
|
pass
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: grasp_agents
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.2
|
4
4
|
Summary: Grasp Agents Library
|
5
5
|
License-File: LICENSE.md
|
6
6
|
Requires-Python: <4,>=3.11.4
|
@@ -45,7 +45,7 @@ Description-Content-Type: text/markdown
|
|
45
45
|
- Workflows (static communication topology), including loops
|
46
46
|
- Agents-as-tools for task delegation
|
47
47
|
- Freeform A2A communication via the in-process actor model
|
48
|
-
-
|
48
|
+
- Parallel processing with flexible retries and rate limiting
|
49
49
|
- Simple logging and usage/cost tracking
|
50
50
|
|
51
51
|
## Project Structure
|
@@ -139,6 +139,7 @@ You should first ask the student about their education, interests, and preferenc
|
|
139
139
|
* Provide your thinking before asking a question and after receiving a reply.
|
140
140
|
* Do not include your exact question as part of your thinking.
|
141
141
|
* The problem must have all the necessary data.
|
142
|
+
* Use the final answer tool to provide the problem.
|
142
143
|
"""
|
143
144
|
|
144
145
|
# Tool input must be a Pydantic model to infer the JSON schema used by the LLM APIs
|
@@ -0,0 +1,50 @@
|
|
1
|
+
grasp_agents/__init__.py,sha256=CIsyUasb9HBC3M4olg6ATAwKXtVNmmtpyGJrt7hpZW4,947
|
2
|
+
grasp_agents/cloud_llm.py,sha256=Pnvey9HaRCudbOCx8vtbRYVsiG-Fn-vIssyUafUSq-0,13641
|
3
|
+
grasp_agents/comm_processor.py,sha256=2xDZwv80velCyhK04xlQzlaAqj7sdnOfyYOHSaVC54g,7013
|
4
|
+
grasp_agents/costs_dict.yaml,sha256=2MFNWtkv5W5WSCcv1Cj13B1iQLVv5Ot9pS_KW2Gu2DA,2510
|
5
|
+
grasp_agents/errors.py,sha256=u-P8NZ3S7THQP5Bjv9SFC_JbHd3CKhX3dTWUObEBzmo,461
|
6
|
+
grasp_agents/generics_utils.py,sha256=5Pw3I9dlnKC2VGqYKC4ZZUO3Z_vTNT-NPFovNfPkl6I,6542
|
7
|
+
grasp_agents/grasp_logging.py,sha256=H1GYhXdQvVkmauFDZ-KDwvVmPQHZUUm9sRqX_ObK2xI,1111
|
8
|
+
grasp_agents/http_client.py,sha256=Es8NXGDkp4Nem7g24-jW0KFGA9Hp_o2Cv3cOvjup-iU,859
|
9
|
+
grasp_agents/llm.py,sha256=S5muzwTbbT048YyASG_BrMcGYX7IGB0q3KZwL3H26wo,5193
|
10
|
+
grasp_agents/llm_agent.py,sha256=tK6cOIPTQzH8GO_xDSLMwRiZX_YrGYNbHzZnURRs8NQ,13835
|
11
|
+
grasp_agents/llm_agent_memory.py,sha256=KPVnwF68acVNdSObSaRcO905YYx8vLHJ-kAEfZYs0sA,1860
|
12
|
+
grasp_agents/llm_policy_executor.py,sha256=C9qzSkF371-c15-HRQDaDfUaYXKRUCYTgq31b78p2RY,17593
|
13
|
+
grasp_agents/memory.py,sha256=QSWjpGTn_t3XFKDxycWUCNFFueQcajzduQGU1vkJFWQ,720
|
14
|
+
grasp_agents/packet.py,sha256=PZ1EpclniAoLk7z4ieZbWzgYH3JSRgnlTe_WfbJYG_4,707
|
15
|
+
grasp_agents/packet_pool.py,sha256=F29EWkKM-305Qqf3hK9jriYXj4vgAx9iAWTg-hfZONs,3035
|
16
|
+
grasp_agents/printer.py,sha256=qxvdUFUu3E5WSjToI4hnXsN0FM8-oIy-pjAybS50oF8,5482
|
17
|
+
grasp_agents/processor.py,sha256=DYc6A6z9JE5NU7VESzIfQbHcgu8uvNo6L_SWf_QqHwA,11102
|
18
|
+
grasp_agents/prompt_builder.py,sha256=wDcB1UaOH8vdxw1tmWZwVZS_bCdWU0VKQvHLpI8SnCk,7970
|
19
|
+
grasp_agents/run_context.py,sha256=pUi2a9WeHUg67cUTQ5T13mmJ3vzQfv-855fWLPeYRmo,1438
|
20
|
+
grasp_agents/usage_tracker.py,sha256=3gmgPcB7qHAl5W5Ffnmu_8GOcKBSv3xM1NLy-HMuSlo,3691
|
21
|
+
grasp_agents/utils.py,sha256=5WpMEZB42QmXGUwMJjtr3aJOMUZlQust3UtMGXs8Uq0,5501
|
22
|
+
grasp_agents/openai/__init__.py,sha256=wpTeew6EjhM6esHCKrEKUpwq0kygMN2QQDxYtmbRG8Y,4201
|
23
|
+
grasp_agents/openai/completion_chunk_converters.py,sha256=TFOA7MJniiSV6_lPZsPSg06GlfdWguTrYS2Hd45BjcU,2674
|
24
|
+
grasp_agents/openai/completion_converters.py,sha256=vzPEkUOX4l2hobKxZjEk_dyWfzeYesO0DlvWvNVb-Sg,2656
|
25
|
+
grasp_agents/openai/content_converters.py,sha256=r1D5uci5x7sbDyl0XN27y-l_jVigCauJruvSdZSnZcc,2510
|
26
|
+
grasp_agents/openai/converters.py,sha256=ncscVyPnPMMbyxAfFX3U73lnr_BZU-I89HA5Ld8BuxI,4691
|
27
|
+
grasp_agents/openai/message_converters.py,sha256=_fG4vI42rBzoajuC5iYgnUBalg8cQ1ckSt8xFBOuWVY,4111
|
28
|
+
grasp_agents/openai/openai_llm.py,sha256=fxJbZA4piNRtr0le6MH1tvOOnxq1o0-OY7gBZrH1G-Q,7993
|
29
|
+
grasp_agents/openai/tool_converters.py,sha256=rNH5t2Wir9nuy8Ei0jaxNuzDaXGqTLmLz3VyrnJhyn0,1196
|
30
|
+
grasp_agents/rate_limiting/__init__.py,sha256=KRgtF_E7R3YfA2cpYcFcZ7wycV0pWVJ0xRQC7YhiIEQ,158
|
31
|
+
grasp_agents/rate_limiting/rate_limiter_chunked.py,sha256=BPgkUXvhmZhTpZs2T6uujNFuxH_kYHiISuf6_-eNhUc,5544
|
32
|
+
grasp_agents/rate_limiting/types.py,sha256=PbnNhEAcYedQdIpPJWud8HUVcxa_xZS2RDZu4c5jr40,1003
|
33
|
+
grasp_agents/rate_limiting/utils.py,sha256=oEDWDNHYMUdxOOG49PlAJochkZq8nnVBCo6JxPc1iSo,2007
|
34
|
+
grasp_agents/typing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
+
grasp_agents/typing/completion.py,sha256=KrvdFZqOcw5GePdMhDoFuwCkMJ86nqRdz9mT9s2lFv4,2445
|
36
|
+
grasp_agents/typing/completion_chunk.py,sha256=eo9h2f3BphBz-sgnCetB9o6Ol6MOl6VH89fMM-NtxtE,6050
|
37
|
+
grasp_agents/typing/content.py,sha256=XFmLpNWkGhkw5JujO6UsYwhzTHkU67PfhzaXH2waLcQ,3659
|
38
|
+
grasp_agents/typing/converters.py,sha256=kHlocHQS8QnduZOzNPbj3aRD8JpvJd53oudYqWdOxKE,2978
|
39
|
+
grasp_agents/typing/events.py,sha256=QbrvXnDmXFr9_cSsdqL9f35eQLOfZ2O0h3a6yCRtKwY,2625
|
40
|
+
grasp_agents/typing/io.py,sha256=RtBnxOiEJkfCPz7bEu1T1JXU7o71MhHK3RkeedzWwX0,237
|
41
|
+
grasp_agents/typing/message.py,sha256=vB94CLGfNJOZ3pTKneVP_mbZpWrhC_981K5OhHUiLW4,2350
|
42
|
+
grasp_agents/typing/tool.py,sha256=mHodyJYbiGQAG7exyDh04n5eqpDEUnV3pFAbC23LHQM,1754
|
43
|
+
grasp_agents/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
44
|
+
grasp_agents/workflow/looped_workflow.py,sha256=eQkjCo6j3W5Xc7mw3AGmXpUhTkK2BmhrvCuht2UkZuI,4537
|
45
|
+
grasp_agents/workflow/sequential_workflow.py,sha256=UCHZXvTy47S0UG0WwuKp2G7Az6dAcE5tIFPaOXhxcWM,2347
|
46
|
+
grasp_agents/workflow/workflow_processor.py,sha256=lGW-Cy1QraU1AaCPVRs9-EtU5Z_3O3EAnuyIPzD6KQ8,3134
|
47
|
+
grasp_agents-0.4.2.dist-info/METADATA,sha256=RX_H6TsRQxb-V9JJxjgWu1qn63GPKfEkD2B8Y2cY-1Y,6868
|
48
|
+
grasp_agents-0.4.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
49
|
+
grasp_agents-0.4.2.dist-info/licenses/LICENSE.md,sha256=-nNNdWqGB8gJ2O-peFQ2Irshv5tW5pHKyTcYkwvH7CE,1201
|
50
|
+
grasp_agents-0.4.2.dist-info/RECORD,,
|