hyperpocket-langgraph 0.1.9__tar.gz → 0.2.0__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.
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/.gitignore +1 -0
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/PKG-INFO +14 -16
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/README.md +13 -15
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/hyperpocket_langgraph/__init__.py +1 -1
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/hyperpocket_langgraph/pocket_langgraph.py +84 -43
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/pyproject.toml +4 -23
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/tests/test_pocket_langgraph_no_profile.py +21 -22
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/tests/test_pocket_langgraph_use_profile.py +24 -22
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/__init__.py +0 -0
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/tests/__init__.py +0 -0
- {hyperpocket_langgraph-0.1.9 → hyperpocket_langgraph-0.2.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hyperpocket-langgraph
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Author-email: Hyperpocket Team <hyperpocket@vessl.ai>
|
5
5
|
Requires-Python: >=3.10
|
6
6
|
Requires-Dist: hyperpocket>=0.0.3
|
@@ -17,13 +17,13 @@ Description-Content-Type: text/markdown
|
|
17
17
|
## Get Pocket Subgraph
|
18
18
|
|
19
19
|
```python
|
20
|
-
|
20
|
+
|
21
21
|
|
22
22
|
from hyperpocket_langgraph import PocketLanggraph
|
23
23
|
|
24
24
|
pocket = PocketLanggraph(tools=[
|
25
|
-
|
26
|
-
|
25
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
26
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
27
27
|
"https://github.com/my-org/some-awesome-tool",
|
28
28
|
])
|
29
29
|
|
@@ -36,14 +36,13 @@ pocket_node = pocket.get_tool_node()
|
|
36
36
|
```python
|
37
37
|
import os
|
38
38
|
|
39
|
-
from hyperpocket.tool import from_git
|
40
39
|
from langchain_openai import ChatOpenAI
|
41
40
|
|
42
41
|
from hyperpocket_langgraph import PocketLanggraph
|
43
42
|
|
44
43
|
pocket = PocketLanggraph(tools=[
|
45
|
-
|
46
|
-
|
44
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
45
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
47
46
|
])
|
48
47
|
|
49
48
|
# get tools from pocket to bind llm
|
@@ -60,7 +59,6 @@ llm_with_tools = llm.bind_tools(tools)
|
|
60
59
|
import os
|
61
60
|
from typing import Annotated
|
62
61
|
|
63
|
-
from hyperpocket.tool import from_git
|
64
62
|
from langchain_core.runnables import RunnableConfig
|
65
63
|
from langchain_openai import ChatOpenAI
|
66
64
|
from langgraph.checkpoint.memory import MemorySaver
|
@@ -73,8 +71,8 @@ from hyperpocket_langgraph import PocketLanggraph
|
|
73
71
|
|
74
72
|
# Define pocket tools
|
75
73
|
pocket = PocketLanggraph(tools=[
|
76
|
-
|
77
|
-
|
74
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
75
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
78
76
|
])
|
79
77
|
|
80
78
|
# Get Pocket ToolNode
|
@@ -131,14 +129,14 @@ by setting the `should_interrupt` flag when calling `get_tool_node`
|
|
131
129
|
Perform authentication in a multi-turn way
|
132
130
|
|
133
131
|
```python
|
134
|
-
|
132
|
+
|
135
133
|
|
136
134
|
from hyperpocket_langgraph import PocketLanggraph
|
137
135
|
|
138
136
|
# Define pocket tools
|
139
137
|
pocket = PocketLanggraph(tools=[
|
140
|
-
|
141
|
-
|
138
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
139
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
142
140
|
])
|
143
141
|
|
144
142
|
# Get Pocket ToolNode
|
@@ -148,14 +146,14 @@ pocket_node = pocket.get_tool_node(should_interrupt=False) # multi turn
|
|
148
146
|
### Human-in-the-loop Auth
|
149
147
|
|
150
148
|
```python
|
151
|
-
|
149
|
+
|
152
150
|
|
153
151
|
from hyperpocket_langgraph import PocketLanggraph
|
154
152
|
|
155
153
|
# Define pocket tools
|
156
154
|
pocket = PocketLanggraph(tools=[
|
157
|
-
|
158
|
-
|
155
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
156
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
159
157
|
])
|
160
158
|
|
161
159
|
# Get Pocket ToolNode
|
@@ -8,13 +8,13 @@
|
|
8
8
|
## Get Pocket Subgraph
|
9
9
|
|
10
10
|
```python
|
11
|
-
|
11
|
+
|
12
12
|
|
13
13
|
from hyperpocket_langgraph import PocketLanggraph
|
14
14
|
|
15
15
|
pocket = PocketLanggraph(tools=[
|
16
|
-
|
17
|
-
|
16
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
17
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
18
18
|
"https://github.com/my-org/some-awesome-tool",
|
19
19
|
])
|
20
20
|
|
@@ -27,14 +27,13 @@ pocket_node = pocket.get_tool_node()
|
|
27
27
|
```python
|
28
28
|
import os
|
29
29
|
|
30
|
-
from hyperpocket.tool import from_git
|
31
30
|
from langchain_openai import ChatOpenAI
|
32
31
|
|
33
32
|
from hyperpocket_langgraph import PocketLanggraph
|
34
33
|
|
35
34
|
pocket = PocketLanggraph(tools=[
|
36
|
-
|
37
|
-
|
35
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
36
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
38
37
|
])
|
39
38
|
|
40
39
|
# get tools from pocket to bind llm
|
@@ -51,7 +50,6 @@ llm_with_tools = llm.bind_tools(tools)
|
|
51
50
|
import os
|
52
51
|
from typing import Annotated
|
53
52
|
|
54
|
-
from hyperpocket.tool import from_git
|
55
53
|
from langchain_core.runnables import RunnableConfig
|
56
54
|
from langchain_openai import ChatOpenAI
|
57
55
|
from langgraph.checkpoint.memory import MemorySaver
|
@@ -64,8 +62,8 @@ from hyperpocket_langgraph import PocketLanggraph
|
|
64
62
|
|
65
63
|
# Define pocket tools
|
66
64
|
pocket = PocketLanggraph(tools=[
|
67
|
-
|
68
|
-
|
65
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
66
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
69
67
|
])
|
70
68
|
|
71
69
|
# Get Pocket ToolNode
|
@@ -122,14 +120,14 @@ by setting the `should_interrupt` flag when calling `get_tool_node`
|
|
122
120
|
Perform authentication in a multi-turn way
|
123
121
|
|
124
122
|
```python
|
125
|
-
|
123
|
+
|
126
124
|
|
127
125
|
from hyperpocket_langgraph import PocketLanggraph
|
128
126
|
|
129
127
|
# Define pocket tools
|
130
128
|
pocket = PocketLanggraph(tools=[
|
131
|
-
|
132
|
-
|
129
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
130
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
133
131
|
])
|
134
132
|
|
135
133
|
# Get Pocket ToolNode
|
@@ -139,14 +137,14 @@ pocket_node = pocket.get_tool_node(should_interrupt=False) # multi turn
|
|
139
137
|
### Human-in-the-loop Auth
|
140
138
|
|
141
139
|
```python
|
142
|
-
|
140
|
+
|
143
141
|
|
144
142
|
from hyperpocket_langgraph import PocketLanggraph
|
145
143
|
|
146
144
|
# Define pocket tools
|
147
145
|
pocket = PocketLanggraph(tools=[
|
148
|
-
|
149
|
-
|
146
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/get-message",
|
147
|
+
"https://github.com/vessl-ai/hyperpocket/tree/main/tools/slack/post-message",
|
150
148
|
])
|
151
149
|
|
152
150
|
# Get Pocket ToolNode
|
@@ -1,26 +1,21 @@
|
|
1
1
|
import copy
|
2
2
|
from typing import Optional
|
3
3
|
|
4
|
+
from hyperpocket.config import pocket_logger
|
4
5
|
from langchain_core.runnables import RunnableConfig
|
5
6
|
from langgraph.errors import NodeInterrupt
|
6
7
|
from pydantic import BaseModel
|
7
8
|
|
8
|
-
from hyperpocket.config import pocket_logger
|
9
|
-
|
10
9
|
try:
|
11
10
|
from langchain_core.messages import ToolMessage
|
12
11
|
from langchain_core.tools import BaseTool, StructuredTool
|
13
12
|
except ImportError:
|
14
|
-
raise ImportError(
|
15
|
-
"You need to install langchain to use pocket langgraph."
|
16
|
-
)
|
13
|
+
raise ImportError("You need to install langchain to use pocket langgraph.")
|
17
14
|
|
18
15
|
try:
|
19
16
|
from langgraph.graph import MessagesState
|
20
17
|
except ImportError:
|
21
|
-
raise ImportError(
|
22
|
-
"You need to install langgraph to use pocket langgraph"
|
23
|
-
)
|
18
|
+
raise ImportError("You need to install langgraph to use pocket langgraph")
|
24
19
|
|
25
20
|
from hyperpocket import Pocket
|
26
21
|
from hyperpocket.tool import Tool as PocketTool
|
@@ -34,16 +29,22 @@ class PocketLanggraph(Pocket):
|
|
34
29
|
def get_tools(self, use_profile: Optional[bool] = None):
|
35
30
|
if use_profile is not None:
|
36
31
|
self.use_profile = use_profile
|
37
|
-
return [
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
return [
|
33
|
+
self._get_langgraph_tool(tool_impl)
|
34
|
+
for tool_impl in self.core.tools.values()
|
35
|
+
]
|
36
|
+
|
37
|
+
def get_tool_node(
|
38
|
+
self, should_interrupt: bool = False, use_profile: Optional[bool] = None
|
39
|
+
):
|
41
40
|
if use_profile is not None:
|
42
41
|
self.use_profile = use_profile
|
43
42
|
|
44
|
-
async def _tool_node(
|
43
|
+
async def _tool_node(
|
44
|
+
state: PocketLanggraphBaseState, config: RunnableConfig
|
45
|
+
) -> dict:
|
45
46
|
thread_id = config.get("configurable", {}).get("thread_id", "default")
|
46
|
-
last_message = state[
|
47
|
+
last_message = state["messages"][-1]
|
47
48
|
tool_calls = last_message.tool_calls
|
48
49
|
|
49
50
|
# 01. prepare
|
@@ -54,9 +55,9 @@ class PocketLanggraph(Pocket):
|
|
54
55
|
pocket_logger.debug(f"prepare tool {tool_call}")
|
55
56
|
_tool_call = copy.deepcopy(tool_call)
|
56
57
|
|
57
|
-
tool_call_id = _tool_call[
|
58
|
-
tool_name = _tool_call[
|
59
|
-
tool_args = _tool_call[
|
58
|
+
tool_call_id = _tool_call["id"]
|
59
|
+
tool_name = _tool_call["name"]
|
60
|
+
tool_args = _tool_call["args"]
|
60
61
|
|
61
62
|
if self.use_profile:
|
62
63
|
body = tool_args.pop("body")
|
@@ -68,27 +69,42 @@ class PocketLanggraph(Pocket):
|
|
68
69
|
if isinstance(body, BaseModel):
|
69
70
|
body = body.model_dump()
|
70
71
|
|
71
|
-
prepare = await self.prepare_in_subprocess(
|
72
|
-
|
72
|
+
prepare = await self.prepare_in_subprocess(
|
73
|
+
tool_name, body=body, thread_id=thread_id, profile=profile
|
74
|
+
)
|
73
75
|
need_prepare |= True if prepare else False
|
74
76
|
|
75
77
|
if prepare is None:
|
76
|
-
prepare_done_list.append(
|
78
|
+
prepare_done_list.append(
|
79
|
+
ToolMessage(content="prepare done", tool_call_id=tool_call_id)
|
80
|
+
)
|
77
81
|
else:
|
78
|
-
prepare_list.append(
|
82
|
+
prepare_list.append(
|
83
|
+
ToolMessage(content=prepare, tool_call_id=tool_call_id)
|
84
|
+
)
|
79
85
|
|
80
86
|
if need_prepare:
|
81
87
|
pocket_logger.debug(f"need prepare : {prepare_list}")
|
82
88
|
if should_interrupt: # interrupt
|
83
|
-
pocket_logger.debug(
|
84
|
-
|
85
|
-
|
89
|
+
pocket_logger.debug(
|
90
|
+
f"{last_message.name}({last_message.id}) is interrupt."
|
91
|
+
)
|
92
|
+
result = "\n\t" + "\n\t".join(
|
93
|
+
set(msg.content for msg in prepare_list)
|
94
|
+
)
|
95
|
+
raise NodeInterrupt(
|
96
|
+
f"{result}\n\nThe tool execution interrupted. Please talk to me to resume."
|
97
|
+
)
|
86
98
|
|
87
99
|
else: # multi turn
|
88
|
-
pocket_logger.debug(
|
100
|
+
pocket_logger.debug(
|
101
|
+
f"{last_message.name}({last_message.id}) is multi-turn"
|
102
|
+
)
|
89
103
|
return {"messages": prepare_done_list + prepare_list}
|
90
104
|
|
91
|
-
pocket_logger.debug(
|
105
|
+
pocket_logger.debug(
|
106
|
+
f"no need prepare {last_message.name}({last_message.id})"
|
107
|
+
)
|
92
108
|
|
93
109
|
# 02. authenticate and tool call
|
94
110
|
tool_messages = []
|
@@ -96,9 +112,9 @@ class PocketLanggraph(Pocket):
|
|
96
112
|
pocket_logger.debug(f"authenticate and call {tool_call}")
|
97
113
|
_tool_call = copy.deepcopy(tool_call)
|
98
114
|
|
99
|
-
tool_call_id = _tool_call[
|
100
|
-
tool_name = _tool_call[
|
101
|
-
tool_args = _tool_call[
|
115
|
+
tool_call_id = _tool_call["id"]
|
116
|
+
tool_name = _tool_call["name"]
|
117
|
+
tool_args = _tool_call["args"]
|
102
118
|
if self.use_profile:
|
103
119
|
body = tool_args.pop("body")
|
104
120
|
profile = tool_args.pop("profile", "default")
|
@@ -111,27 +127,48 @@ class PocketLanggraph(Pocket):
|
|
111
127
|
|
112
128
|
try:
|
113
129
|
auth = await self.authenticate_in_subprocess(
|
114
|
-
tool_name, body=body, thread_id=thread_id, profile=profile
|
130
|
+
tool_name, body=body, thread_id=thread_id, profile=profile
|
131
|
+
)
|
115
132
|
except Exception as e:
|
116
|
-
pocket_logger.error(
|
133
|
+
pocket_logger.error(
|
134
|
+
f"occur exception during authenticate. error : {e}"
|
135
|
+
)
|
117
136
|
tool_messages.append(
|
118
|
-
ToolMessage(
|
119
|
-
|
137
|
+
ToolMessage(
|
138
|
+
content=f"occur exception during authenticate. error : {e}",
|
139
|
+
tool_name=tool_name,
|
140
|
+
tool_call_id=tool_call_id,
|
141
|
+
)
|
142
|
+
)
|
120
143
|
continue
|
121
144
|
|
122
145
|
try:
|
123
146
|
result = await self.tool_call_in_subprocess(
|
124
|
-
tool_name,
|
125
|
-
|
147
|
+
tool_name,
|
148
|
+
body=body,
|
149
|
+
envs=auth,
|
150
|
+
thread_id=thread_id,
|
151
|
+
profile=tool_args.get("profile", "default"),
|
152
|
+
)
|
126
153
|
except Exception as e:
|
127
|
-
pocket_logger.error(
|
154
|
+
pocket_logger.error(
|
155
|
+
f"occur exception during tool calling. error : {e}"
|
156
|
+
)
|
128
157
|
tool_messages.append(
|
129
|
-
ToolMessage(
|
130
|
-
|
158
|
+
ToolMessage(
|
159
|
+
content=f"occur exception during tool calling. error : {e}",
|
160
|
+
tool_name=tool_name,
|
161
|
+
tool_call_id=tool_call_id,
|
162
|
+
)
|
163
|
+
)
|
131
164
|
continue
|
132
165
|
|
133
166
|
pocket_logger.debug(f"{tool_name} tool result : {result}")
|
134
|
-
tool_messages.append(
|
167
|
+
tool_messages.append(
|
168
|
+
ToolMessage(
|
169
|
+
content=result, tool_name=tool_name, tool_call_id=tool_call_id
|
170
|
+
)
|
171
|
+
)
|
135
172
|
|
136
173
|
return {"messages": tool_messages}
|
137
174
|
|
@@ -151,10 +188,12 @@ class PocketLanggraph(Pocket):
|
|
151
188
|
if isinstance(body, BaseModel):
|
152
189
|
body = body.model_dump()
|
153
190
|
|
154
|
-
result, interrupted = self.invoke_with_state(
|
191
|
+
result, interrupted = self.invoke_with_state(
|
192
|
+
pocket_tool.name, body, thread_id, profile, **kwargs
|
193
|
+
)
|
155
194
|
say = result
|
156
195
|
if interrupted:
|
157
|
-
say = f
|
196
|
+
say = f"{say}\n\nThe tool execution interrupted. Please talk to me to resume."
|
158
197
|
return say
|
159
198
|
|
160
199
|
async def _ainvoke(**kwargs) -> str:
|
@@ -170,10 +209,12 @@ class PocketLanggraph(Pocket):
|
|
170
209
|
if isinstance(body, BaseModel):
|
171
210
|
body = body.model_dump()
|
172
211
|
|
173
|
-
result, interrupted = await self.ainvoke_with_state(
|
212
|
+
result, interrupted = await self.ainvoke_with_state(
|
213
|
+
pocket_tool.name, body, thread_id, profile, **kwargs
|
214
|
+
)
|
174
215
|
say = result
|
175
216
|
if interrupted:
|
176
|
-
say = f
|
217
|
+
say = f"{say}\n\nThe tool execution interrupted. Please talk to me to resume."
|
177
218
|
return say
|
178
219
|
|
179
220
|
return StructuredTool.from_function(
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
[project]
|
3
3
|
name = "hyperpocket-langgraph"
|
4
|
-
version = "0.
|
4
|
+
version = "0.2.0"
|
5
5
|
description = ""
|
6
6
|
authors = [{ name = "Hyperpocket Team", email = "hyperpocket@vessl.ai" }]
|
7
7
|
requires-python = ">=3.10"
|
@@ -12,31 +12,12 @@ dependencies = ["langgraph>=0.2.59", "hyperpocket>=0.0.3"]
|
|
12
12
|
hyperpocket = { path = "../../hyperpocket", editable = true }
|
13
13
|
|
14
14
|
[dependency-groups]
|
15
|
-
dev = [
|
16
|
-
|
17
|
-
"ruff>=0.8.6",
|
18
|
-
]
|
19
|
-
test = [
|
20
|
-
"langchain-openai>=0.3.1",
|
21
|
-
]
|
15
|
+
dev = ["pytest>=8.3.4", "ruff>=0.8.6"]
|
16
|
+
test = ["langchain-openai>=0.3.1"]
|
22
17
|
|
23
18
|
[build-system]
|
24
19
|
requires = ["hatchling"]
|
25
20
|
build-backend = "hatchling.build"
|
26
21
|
|
27
|
-
[tool.ruff.lint]
|
28
|
-
select = [
|
29
|
-
"E", # pycodestyle errors,
|
30
|
-
"F", # pyflakes errors,
|
31
|
-
"I", # isort errors,
|
32
|
-
]
|
33
|
-
ignore = [
|
34
|
-
"E501", # line too long, handled by formatting
|
35
|
-
]
|
36
|
-
|
37
22
|
[tool.ruff]
|
38
|
-
|
39
|
-
target-version = "py310"
|
40
|
-
|
41
|
-
[tool.ruff.lint.per-file-ignores]
|
42
|
-
"__init__.py" = ["F401"]
|
23
|
+
extend = "../../../.ruff.toml"
|
@@ -1,20 +1,18 @@
|
|
1
1
|
import ast
|
2
2
|
from unittest.async_case import IsolatedAsyncioTestCase
|
3
3
|
|
4
|
+
from hyperpocket.config import config, secret
|
5
|
+
from hyperpocket.tool import from_git
|
4
6
|
from langchain_openai import ChatOpenAI
|
5
|
-
from langgraph.constants import
|
7
|
+
from langgraph.constants import END, START
|
6
8
|
from langgraph.graph import MessagesState, StateGraph
|
7
9
|
from langgraph.prebuilt import tools_condition
|
8
10
|
from pydantic import BaseModel
|
9
11
|
|
10
|
-
from hyperpocket.config import config, secret
|
11
|
-
from hyperpocket.tool import from_git
|
12
12
|
from hyperpocket_langgraph import PocketLanggraph
|
13
13
|
|
14
14
|
|
15
15
|
class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
16
|
-
|
17
|
-
|
18
16
|
async def asyncSetUp(self):
|
19
17
|
config.public_server_port = "https"
|
20
18
|
config.public_hostname = "localhost"
|
@@ -24,15 +22,21 @@ class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
|
24
22
|
|
25
23
|
self.pocket = PocketLanggraph(
|
26
24
|
tools=[
|
27
|
-
from_git(
|
25
|
+
from_git(
|
26
|
+
"https://github.com/vessl-ai/hyperawesometools",
|
27
|
+
"main",
|
28
|
+
"managed-tools/none/simple-echo-tool",
|
29
|
+
),
|
28
30
|
self.add,
|
29
|
-
self.sub_pydantic_args
|
31
|
+
self.sub_pydantic_args,
|
30
32
|
],
|
31
|
-
use_profile=False
|
33
|
+
use_profile=False,
|
32
34
|
)
|
33
35
|
tools = self.pocket.get_tools()
|
34
36
|
tool_node = self.pocket.get_tool_node()
|
35
|
-
self.llm = ChatOpenAI(
|
37
|
+
self.llm = ChatOpenAI(
|
38
|
+
model="gpt-4o", api_key=secret["OPENAI_API_KEY"]
|
39
|
+
).bind_tools(tools=tools)
|
36
40
|
|
37
41
|
def chatbot(state: MessagesState):
|
38
42
|
return {"messages": [self.llm.invoke(state["messages"])]}
|
@@ -52,7 +56,6 @@ class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
|
52
56
|
async def asyncTearDown(self):
|
53
57
|
self.pocket._teardown_server()
|
54
58
|
|
55
|
-
|
56
59
|
async def test_function_tool_no_profile(self):
|
57
60
|
# when
|
58
61
|
response = await self.graph.ainvoke({"messages": [("user", "add 1, 2")]})
|
@@ -62,10 +65,7 @@ class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
|
62
65
|
|
63
66
|
# then
|
64
67
|
self.assertEqual(tool_call.tool_calls[0]["name"], "add")
|
65
|
-
self.assertEqual(tool_call.tool_calls[0]["args"], {
|
66
|
-
'a': 1,
|
67
|
-
'b': 2
|
68
|
-
})
|
68
|
+
self.assertEqual(tool_call.tool_calls[0]["args"], {"a": 1, "b": 2})
|
69
69
|
self.assertEqual(tool_result.content, "3")
|
70
70
|
|
71
71
|
async def test_pydantic_function_tool_no_profile(self):
|
@@ -77,15 +77,16 @@ class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
|
77
77
|
|
78
78
|
# then
|
79
79
|
self.assertEqual(tool_call.tool_calls[0]["name"], "sub_pydantic_args")
|
80
|
-
self.assertEqual(
|
81
|
-
|
82
|
-
|
83
|
-
})
|
80
|
+
self.assertEqual(
|
81
|
+
tool_call.tool_calls[0]["args"], {"a": {"first": 1}, "b": {"second": 2}}
|
82
|
+
)
|
84
83
|
self.assertEqual(tool_result.content, "-1")
|
85
84
|
|
86
85
|
async def test_wasm_tool_no_profile(self):
|
87
86
|
# when
|
88
|
-
response = await self.graph.ainvoke(
|
87
|
+
response = await self.graph.ainvoke(
|
88
|
+
{"messages": [("user", "echo 'hello world'")]}
|
89
|
+
)
|
89
90
|
|
90
91
|
tool_call = response["messages"][1]
|
91
92
|
tool_result = response["messages"][2]
|
@@ -94,9 +95,7 @@ class TestPocketLanggraphNoProfile(IsolatedAsyncioTestCase):
|
|
94
95
|
|
95
96
|
# then
|
96
97
|
self.assertEqual(tool_call.tool_calls[0]["name"], "simple_echo_text")
|
97
|
-
self.assertEqual(tool_call.tool_calls[0]["args"], {
|
98
|
-
'text': 'hello world'
|
99
|
-
})
|
98
|
+
self.assertEqual(tool_call.tool_calls[0]["args"], {"text": "hello world"})
|
100
99
|
self.assertTrue(output["stdout"].startswith("echo message : hello world"))
|
101
100
|
|
102
101
|
@staticmethod
|
@@ -1,20 +1,18 @@
|
|
1
1
|
import ast
|
2
2
|
from unittest.async_case import IsolatedAsyncioTestCase
|
3
3
|
|
4
|
+
from hyperpocket.config import config, secret
|
5
|
+
from hyperpocket.tool import from_git
|
4
6
|
from langchain_openai import ChatOpenAI
|
5
|
-
from langgraph.constants import
|
7
|
+
from langgraph.constants import END, START
|
6
8
|
from langgraph.graph import MessagesState, StateGraph
|
7
9
|
from langgraph.prebuilt import tools_condition
|
8
10
|
from pydantic import BaseModel
|
9
11
|
|
10
|
-
from hyperpocket.config import config, secret
|
11
|
-
from hyperpocket.tool import from_git
|
12
12
|
from hyperpocket_langgraph import PocketLanggraph
|
13
13
|
|
14
14
|
|
15
15
|
class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
16
|
-
|
17
|
-
|
18
16
|
async def asyncSetUp(self):
|
19
17
|
config.public_server_port = "https"
|
20
18
|
config.public_hostname = "localhost"
|
@@ -24,15 +22,21 @@ class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
|
24
22
|
|
25
23
|
self.pocket = PocketLanggraph(
|
26
24
|
tools=[
|
27
|
-
from_git(
|
25
|
+
from_git(
|
26
|
+
"https://github.com/vessl-ai/hyperawesometools",
|
27
|
+
"main",
|
28
|
+
"managed-tools/none/simple-echo-tool",
|
29
|
+
),
|
28
30
|
self.add,
|
29
|
-
self.sub_pydantic_args
|
31
|
+
self.sub_pydantic_args,
|
30
32
|
],
|
31
|
-
use_profile=True
|
33
|
+
use_profile=True,
|
32
34
|
)
|
33
35
|
tools = self.pocket.get_tools()
|
34
36
|
tool_node = self.pocket.get_tool_node()
|
35
|
-
self.llm = ChatOpenAI(
|
37
|
+
self.llm = ChatOpenAI(
|
38
|
+
model="gpt-4o", api_key=secret["OPENAI_API_KEY"]
|
39
|
+
).bind_tools(tools=tools)
|
36
40
|
|
37
41
|
def chatbot(state: MessagesState):
|
38
42
|
return {"messages": [self.llm.invoke(state["messages"])]}
|
@@ -52,7 +56,6 @@ class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
|
52
56
|
async def asyncTearDown(self):
|
53
57
|
self.pocket._teardown_server()
|
54
58
|
|
55
|
-
|
56
59
|
async def test_function_tool_use_profile(self):
|
57
60
|
# when
|
58
61
|
response = await self.graph.ainvoke({"messages": [("user", "add 1, 2")]})
|
@@ -62,10 +65,7 @@ class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
|
62
65
|
|
63
66
|
# then
|
64
67
|
self.assertEqual(tool_call.tool_calls[0]["name"], "add")
|
65
|
-
self.assertEqual(tool_call.tool_calls[0]["args"]["body"], {
|
66
|
-
'a': 1,
|
67
|
-
'b': 2
|
68
|
-
})
|
68
|
+
self.assertEqual(tool_call.tool_calls[0]["args"]["body"], {"a": 1, "b": 2})
|
69
69
|
self.assertEqual(tool_result.content, "3")
|
70
70
|
|
71
71
|
async def test_pydantic_function_tool_use_profile(self):
|
@@ -77,15 +77,17 @@ class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
|
77
77
|
|
78
78
|
# then
|
79
79
|
self.assertEqual(tool_call.tool_calls[0]["name"], "sub_pydantic_args")
|
80
|
-
self.assertEqual(
|
81
|
-
|
82
|
-
|
83
|
-
|
80
|
+
self.assertEqual(
|
81
|
+
tool_call.tool_calls[0]["args"]["body"],
|
82
|
+
{"a": {"first": 1}, "b": {"second": 2}},
|
83
|
+
)
|
84
84
|
self.assertEqual(tool_result.content, "-1")
|
85
85
|
|
86
86
|
async def test_wasm_tool_use_profile(self):
|
87
87
|
# when
|
88
|
-
response = await self.graph.ainvoke(
|
88
|
+
response = await self.graph.ainvoke(
|
89
|
+
{"messages": [("user", "echo 'hello world'")]}
|
90
|
+
)
|
89
91
|
|
90
92
|
tool_call = response["messages"][1]
|
91
93
|
tool_result = response["messages"][2]
|
@@ -94,9 +96,9 @@ class TestPocketLanggraphUseProfile(IsolatedAsyncioTestCase):
|
|
94
96
|
|
95
97
|
# then
|
96
98
|
self.assertEqual(tool_call.tool_calls[0]["name"], "simple_echo_text")
|
97
|
-
self.assertEqual(
|
98
|
-
|
99
|
-
|
99
|
+
self.assertEqual(
|
100
|
+
tool_call.tool_calls[0]["args"]["body"], {"text": "hello world"}
|
101
|
+
)
|
100
102
|
self.assertTrue(output["stdout"].startswith("echo message : hello world"))
|
101
103
|
|
102
104
|
@staticmethod
|
File without changes
|
File without changes
|
File without changes
|