-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/native functions #867
Changes from 79 commits
46fef79
a405af0
1740d1d
c91f7ea
ad3a0e3
4665a8f
19929a5
95c5849
0b4b455
05269ea
9381332
c725b94
6914d40
0054312
f1e8088
032bc04
c4b9351
f4f0eed
e8a2dcb
a499374
be58aee
e83c143
06290e5
e0d09b1
05b45ae
c0ef8f4
c66d056
1637f4f
76da060
dc7af54
e0023a5
a9bdb2f
70778f7
af0f5e3
eeaf2df
b8ac3b3
88f85d9
8a05aa6
55a535f
9224a0e
e1fc021
ed8b935
c414839
8630c4d
5a7ae37
63b8da7
730156c
b9029a0
b91631e
0e1aacc
4c18b29
b0f9e36
47c0995
9605a8c
85bcc86
f270170
da95012
e431f5d
569792c
f1c5abd
dc46fa3
6e0d0cc
6766313
59ab49f
55d2cda
2bf3f77
c64d0af
061cc1b
db2136f
950c3b3
78e162d
b3fa757
888f6e2
f0198f0
a2bdbae
0e2939a
33aa25a
e76f906
5c07c99
ba8e2f6
68f865f
4be252b
09086ff
47940f1
29481f7
97d620f
d55ce6e
e2d1a03
9c44a62
3d4fd4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from __future__ import annotations | ||
|
||
from attrs import define, field | ||
from typing import TYPE_CHECKING | ||
|
||
from griptape.artifacts import BaseArtifact | ||
from griptape.mixins import SerializableMixin | ||
|
||
if TYPE_CHECKING: | ||
from griptape.common import Action | ||
|
||
|
||
@define() | ||
class ActionArtifact(BaseArtifact, SerializableMixin): | ||
dylanholmes marked this conversation as resolved.
Show resolved
Hide resolved
vasinov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""Represents an instance of an LLM calling a Action. | ||
|
||
Attributes: | ||
tag: The tag (unique identifier) of the action. | ||
name: The name (Tool name) of the action. | ||
path: The path (Tool activity name) of the action. | ||
input: The input (Tool params) of the action. | ||
tool: The matched Tool of the action. | ||
output: The output (Tool result) of the action. | ||
""" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This docstring should be in |
||
|
||
value: Action = field(metadata={"serializable": True}) | ||
|
||
def __add__(self, other: BaseArtifact) -> ActionArtifact: | ||
raise NotImplementedError |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from __future__ import annotations | ||
import json | ||
from typing import TYPE_CHECKING, Optional | ||
|
||
from attrs import define, field | ||
|
||
from griptape.artifacts import BaseArtifact | ||
from griptape.mixins import SerializableMixin | ||
|
||
if TYPE_CHECKING: | ||
from griptape.tools import BaseTool | ||
|
||
|
||
@define(kw_only=True) | ||
class Action(SerializableMixin): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add some prefix to this? I'm worried that we might have some other "action" in the future, unrelated to LLM actions, which will be confusing naming-wise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactored into |
||
tag: str = field(metadata={"serializable": True}) | ||
name: str = field(metadata={"serializable": True}) | ||
path: Optional[str] = field(default=None, metadata={"serializable": True}) | ||
input: dict = field(factory=dict, metadata={"serializable": True}) | ||
tool: Optional[BaseTool] = field(default=None) | ||
output: Optional[BaseArtifact] = field(default=None, metadata={"serializable": True}) | ||
|
||
def __str__(self) -> str: | ||
return json.dumps(self.to_dict()) | ||
|
||
def to_dict(self) -> dict: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you need to override this? Can't we just set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, updated. |
||
return {"tag": self.tag, "name": self.name, "path": self.path, "input": self.input} | ||
|
||
def to_native_tool_name(self) -> str: | ||
parts = [self.name] | ||
|
||
if self.path is not None: | ||
parts.append(self.path) | ||
|
||
return "_".join(parts) | ||
|
||
@classmethod | ||
def from_native_tool_name(cls, native_tool_name: str) -> tuple[str, Optional[str]]: | ||
parts = native_tool_name.split("_", 1) | ||
|
||
if len(parts) == 1: | ||
name, path = parts[0], None | ||
else: | ||
name, path = parts | ||
|
||
return name, path |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from __future__ import annotations | ||
from attrs import define, field | ||
from typing import Optional | ||
|
||
from griptape.common import BaseDeltaMessageContent | ||
|
||
|
||
@define | ||
class ActionCallDeltaMessageContent(BaseDeltaMessageContent): | ||
vasinov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tag: Optional[str] = field(default=None, metadata={"serializable": True}) | ||
name: Optional[str] = field(default=None, metadata={"serializable": True}) | ||
path: Optional[str] = field(default=None, metadata={"serializable": True}) | ||
partial_input: Optional[str] = field(default=None, metadata={"serializable": True}) | ||
|
||
def __str__(self) -> str: | ||
parts = [] | ||
|
||
if self.name: | ||
parts.append(self.name) | ||
if self.path: | ||
parts.append(f".{self.path}") | ||
if self.tag: | ||
parts.append(f" ({self.tag})") | ||
|
||
if self.partial_input: | ||
if parts: | ||
parts.append(f" {self.partial_input}") | ||
else: | ||
parts.append(self.partial_input) | ||
|
||
return "".join(parts) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from __future__ import annotations | ||
|
||
import json | ||
from collections.abc import Sequence | ||
|
||
from attrs import define, field | ||
|
||
from griptape.common import Action | ||
from griptape.artifacts import ActionArtifact | ||
from griptape.common import BaseDeltaMessageContent, BaseMessageContent, ActionCallDeltaMessageContent | ||
|
||
|
||
@define | ||
class ActionCallMessageContent(BaseMessageContent): | ||
artifact: ActionArtifact = field(metadata={"serializable": True}) | ||
|
||
@classmethod | ||
def from_deltas(cls, deltas: Sequence[BaseDeltaMessageContent]) -> ActionCallMessageContent: | ||
action_call_deltas = [delta for delta in deltas if isinstance(delta, ActionCallDeltaMessageContent)] | ||
|
||
tag = None | ||
name = None | ||
path = None | ||
input = "" | ||
|
||
for delta in action_call_deltas: | ||
if delta.tag is not None: | ||
tag = delta.tag | ||
if delta.name is not None: | ||
name = delta.name | ||
if delta.path is not None: | ||
path = delta.path | ||
if delta.partial_input is not None: | ||
input += delta.partial_input | ||
|
||
if tag is not None and name is not None and path is not None: | ||
try: | ||
parsed_input = json.loads(input) | ||
except json.JSONDecodeError as exc: | ||
raise ValueError("Invalid JSON input for Action") from exc | ||
action = Action(tag=tag, name=name, path=path, input=parsed_input) | ||
else: | ||
raise ValueError("Missing required fields for Action") | ||
|
||
artifact = ActionArtifact(value=action) | ||
|
||
return cls(artifact=artifact) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from __future__ import annotations | ||
|
||
from collections.abc import Sequence | ||
|
||
from attrs import define, field | ||
|
||
from griptape.artifacts import BaseArtifact | ||
from griptape.common import BaseDeltaMessageContent, BaseMessageContent, Action | ||
|
||
|
||
@define | ||
class ActionResultMessageContent(BaseMessageContent): | ||
artifact: BaseArtifact = field(metadata={"serializable": True}) | ||
action: Action = field(metadata={"serializable": True}) | ||
|
||
@classmethod | ||
def from_deltas(cls, deltas: Sequence[BaseDeltaMessageContent]) -> ActionResultMessageContent: | ||
raise NotImplementedError |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,15 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Optional | ||
|
||
from attrs import define, field | ||
|
||
from griptape.common.prompt_stack.contents.text_delta_message_content import TextDeltaMessageContent | ||
|
||
from griptape.common import BaseDeltaMessageContent | ||
|
||
from .base_message import BaseMessage | ||
|
||
|
||
@define | ||
class DeltaMessage(BaseMessage): | ||
role: Optional[str] = field(kw_only=True, default=None, metadata={"serializable": True}) | ||
content: Optional[TextDeltaMessageContent] = field(kw_only=True, default=None, metadata={"serializable": True}) | ||
content: Optional[BaseDeltaMessageContent] = field(kw_only=True, default=None, metadata={"serializable": True}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉