hyperpocket 0.3.6__py3-none-any.whl → 0.4.0__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.
- hyperpocket/auth/provider.py +2 -0
- hyperpocket/auth/weaviate/context.py +12 -0
- hyperpocket/auth/weaviate/token_context.py +11 -0
- hyperpocket/auth/weaviate/token_handler.py +68 -0
- hyperpocket/auth/weaviate/token_schema.py +7 -0
- hyperpocket/auth/zinc/__init__.py +0 -0
- hyperpocket/auth/zinc/context.py +12 -0
- hyperpocket/auth/zinc/token_context.py +11 -0
- hyperpocket/auth/zinc/token_handler.py +64 -0
- hyperpocket/auth/zinc/token_schema.py +7 -0
- hyperpocket/cli/eject.py +2 -7
- hyperpocket/cli/pull.py +2 -7
- hyperpocket/config/settings.py +2 -1
- hyperpocket/pocket_core.py +41 -68
- hyperpocket/pocket_main.py +37 -16
- hyperpocket/repository/__init__.py +3 -4
- hyperpocket/repository/repository.py +6 -41
- hyperpocket/repository/tool_reference.py +28 -0
- hyperpocket/server/auth/weaviate.py +27 -0
- hyperpocket/server/auth/zinc.py +27 -0
- hyperpocket/server/server.py +127 -61
- hyperpocket/session/in_memory.py +13 -3
- hyperpocket/tool/__init__.py +0 -3
- hyperpocket/tool/dock/__init__.py +3 -0
- hyperpocket/tool/dock/dock.py +34 -0
- hyperpocket/tool/function/__init__.py +1 -1
- hyperpocket/tool/function/tool.py +62 -32
- hyperpocket/tool/tool.py +1 -9
- hyperpocket/tool_like.py +2 -1
- hyperpocket/util/generate_slug.py +4 -0
- hyperpocket/util/json_schema_to_model.py +5 -1
- {hyperpocket-0.3.6.dist-info → hyperpocket-0.4.0.dist-info}/METADATA +4 -1
- {hyperpocket-0.3.6.dist-info → hyperpocket-0.4.0.dist-info}/RECORD +36 -36
- hyperpocket/cli/sync.py +0 -17
- hyperpocket/repository/lock.py +0 -240
- hyperpocket/repository/lockfile.py +0 -62
- hyperpocket/server/tool/__init__.py +0 -10
- hyperpocket/server/tool/dto/script.py +0 -33
- hyperpocket/server/tool/wasm.py +0 -46
- hyperpocket/tool/wasm/README.md +0 -166
- hyperpocket/tool/wasm/__init__.py +0 -3
- hyperpocket/tool/wasm/browser.py +0 -63
- hyperpocket/tool/wasm/invoker.py +0 -41
- hyperpocket/tool/wasm/script.py +0 -134
- hyperpocket/tool/wasm/templates/__init__.py +0 -35
- hyperpocket/tool/wasm/templates/node.py +0 -87
- hyperpocket/tool/wasm/templates/python.py +0 -93
- hyperpocket/tool/wasm/tool.py +0 -163
- /hyperpocket/{server/tool/dto → auth/weaviate}/__init__.py +0 -0
- {hyperpocket-0.3.6.dist-info → hyperpocket-0.4.0.dist-info}/WHEEL +0 -0
- {hyperpocket-0.3.6.dist-info → hyperpocket-0.4.0.dist-info}/entry_points.txt +0 -0
hyperpocket/server/server.py
CHANGED
@@ -10,7 +10,6 @@ from uvicorn import Config, Server
|
|
10
10
|
from hyperpocket.config import config, pocket_logger
|
11
11
|
from hyperpocket.pocket_core import PocketCore
|
12
12
|
from hyperpocket.server.auth import auth_router
|
13
|
-
from hyperpocket.server.tool import tool_router
|
14
13
|
|
15
14
|
|
16
15
|
class PocketServerOperations(enum.Enum):
|
@@ -18,10 +17,12 @@ class PocketServerOperations(enum.Enum):
|
|
18
17
|
PREPARE_AUTH = "prepare_auth"
|
19
18
|
AUTHENTICATE = "authenticate"
|
20
19
|
TOOL_CALL = "tool_call"
|
20
|
+
PLUG_CORE = "plug_core"
|
21
21
|
|
22
22
|
|
23
23
|
class PocketServer(object):
|
24
|
-
|
24
|
+
fastapi_app: Optional[FastAPI]
|
25
|
+
main_server: Optional[Server]
|
25
26
|
internal_server_port: int
|
26
27
|
proxy_server: Optional[Server]
|
27
28
|
proxy_port: int
|
@@ -29,15 +30,64 @@ class PocketServer(object):
|
|
29
30
|
process: mp.Process
|
30
31
|
future_store: dict[str, asyncio.Future]
|
31
32
|
torn_down: bool = False
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
self.
|
39
|
-
self.
|
33
|
+
_uidset: set
|
34
|
+
_cores: dict[str, PocketCore]
|
35
|
+
|
36
|
+
def __init__(self):
|
37
|
+
self._initialized = False
|
38
|
+
self.internal_server_port = config().internal_server_port
|
39
|
+
self.proxy_port = config().public_server_port
|
40
|
+
self._uidset = set()
|
40
41
|
self.future_store = dict()
|
42
|
+
self.fastapi_app = None
|
43
|
+
self.main_server = None
|
44
|
+
self._cores = dict()
|
45
|
+
|
46
|
+
# should be called in child process
|
47
|
+
def _plug_core(self, pocket_uid: str, pocket_core: PocketCore, *_a, **_kw):
|
48
|
+
# extend http routers from each docks
|
49
|
+
dock_routes = set([str(r) for r in self.fastapi_app.routes])
|
50
|
+
|
51
|
+
for dock in pocket_core.docks:
|
52
|
+
# check duplicated api route
|
53
|
+
dock_route = set([str(r) for r in dock.router.routes])
|
54
|
+
if dock_route in dock_routes:
|
55
|
+
continue
|
56
|
+
|
57
|
+
dock_routes.update(dock_route)
|
58
|
+
self.fastapi_app.include_router(dock.router)
|
59
|
+
|
60
|
+
# keep pocket core
|
61
|
+
self._cores[pocket_uid] = pocket_core
|
62
|
+
|
63
|
+
# should be called in parent process
|
64
|
+
async def plug_core(self, pocket_uid: str, pocket_core: PocketCore):
|
65
|
+
await self.call_in_subprocess(
|
66
|
+
PocketServerOperations.PLUG_CORE,
|
67
|
+
pocket_uid,
|
68
|
+
tuple(),
|
69
|
+
{
|
70
|
+
"pocket_uid": pocket_uid,
|
71
|
+
"pocket_core": pocket_core,
|
72
|
+
},
|
73
|
+
)
|
74
|
+
|
75
|
+
@classmethod
|
76
|
+
def get_instance_and_refcnt_up(cls, uid: str):
|
77
|
+
if cls.__dict__.get("_instance") is None:
|
78
|
+
cls._instance = cls()
|
79
|
+
cls._instance.run()
|
80
|
+
cls._instance.refcnt_up(uid)
|
81
|
+
return cls._instance
|
82
|
+
|
83
|
+
def refcnt_up(self, uid: str):
|
84
|
+
self._uidset.add(uid)
|
85
|
+
|
86
|
+
def refcnt_down(self, uid: str):
|
87
|
+
if uid in self._uidset:
|
88
|
+
self._uidset.remove(uid)
|
89
|
+
if len(self._uidset) == 0:
|
90
|
+
self._instance.teardown()
|
41
91
|
|
42
92
|
def teardown(self):
|
43
93
|
# @XXX(seokju) is it ok to call this method both in __del__ and __exit__?
|
@@ -63,20 +113,21 @@ class PocketServer(object):
|
|
63
113
|
loop = asyncio.get_running_loop()
|
64
114
|
_, conn = self.pipe
|
65
115
|
|
66
|
-
async def _acall(_conn,
|
116
|
+
async def _acall(_conn, _future_uid, _core_uid, _args, _kwargs):
|
67
117
|
try:
|
68
|
-
|
118
|
+
core = self._cores[_core_uid]
|
119
|
+
result = await core.acall(*_args, **_kwargs)
|
69
120
|
error = None
|
70
121
|
except Exception as e:
|
71
|
-
pocket_logger.error(f"failed
|
122
|
+
pocket_logger.error(f"failed in pocket subprocess. error: {e}")
|
72
123
|
result = None
|
73
124
|
error = e
|
125
|
+
_conn.send((_future_uid, result, error))
|
74
126
|
|
75
|
-
|
76
|
-
|
77
|
-
async def _prepare(_conn, _op, _uid, a, kw):
|
127
|
+
async def _prepare(_conn, _future_uid, _core_uid, a, kw):
|
78
128
|
try:
|
79
|
-
|
129
|
+
core = self._cores[_core_uid]
|
130
|
+
result = core.prepare_auth(*a, **kw)
|
80
131
|
error = None
|
81
132
|
except Exception as e:
|
82
133
|
pocket_logger.error(
|
@@ -85,11 +136,12 @@ class PocketServer(object):
|
|
85
136
|
result = None
|
86
137
|
error = e
|
87
138
|
|
88
|
-
_conn.send((
|
139
|
+
_conn.send((_future_uid, result, error))
|
89
140
|
|
90
|
-
async def _authenticate(_conn,
|
141
|
+
async def _authenticate(_conn, _future_uid, _core_uid, a, kw):
|
91
142
|
try:
|
92
|
-
|
143
|
+
core = self._cores[_core_uid]
|
144
|
+
result = await core.authenticate(*a, **kw)
|
93
145
|
error = None
|
94
146
|
except Exception as e:
|
95
147
|
pocket_logger.error(
|
@@ -98,11 +150,12 @@ class PocketServer(object):
|
|
98
150
|
result = None
|
99
151
|
error = e
|
100
152
|
|
101
|
-
_conn.send((
|
153
|
+
_conn.send((_future_uid, result, error))
|
102
154
|
|
103
|
-
async def _tool_call(_conn,
|
155
|
+
async def _tool_call(_conn, _future_uid, _core_uid, a, kw):
|
104
156
|
try:
|
105
|
-
|
157
|
+
core = self._cores[_core_uid]
|
158
|
+
result = await core.tool_call(*a, **kw)
|
106
159
|
error = None
|
107
160
|
except Exception as e:
|
108
161
|
pocket_logger.error(
|
@@ -111,38 +164,50 @@ class PocketServer(object):
|
|
111
164
|
result = None
|
112
165
|
error = e
|
113
166
|
|
114
|
-
_conn.send((
|
167
|
+
_conn.send((_future_uid, result, error))
|
168
|
+
|
169
|
+
async def _plug_core(_conn, _future_uid, _core_uid, a, kw):
|
170
|
+
try:
|
171
|
+
self._plug_core(*a, **kw)
|
172
|
+
_conn.send((_future_uid, None, None))
|
173
|
+
except Exception as e:
|
174
|
+
pocket_logger.error(
|
175
|
+
f"failed to plug_core in pocket subprocess. error: {e}"
|
176
|
+
)
|
177
|
+
_conn.send((_future_uid, None, e))
|
115
178
|
|
116
179
|
while True:
|
117
180
|
if conn.poll():
|
118
|
-
op,
|
119
|
-
if op == PocketServerOperations.CALL
|
120
|
-
loop.create_task(_acall(conn,
|
121
|
-
elif op == PocketServerOperations.PREPARE_AUTH
|
122
|
-
loop.create_task(_prepare(conn,
|
123
|
-
elif op == PocketServerOperations.AUTHENTICATE
|
124
|
-
loop.create_task(_authenticate(conn,
|
125
|
-
elif op == PocketServerOperations.TOOL_CALL
|
126
|
-
loop.create_task(_tool_call(conn,
|
181
|
+
op, future_uid, core_uid, args, kwargs = conn.recv()
|
182
|
+
if op == PocketServerOperations.CALL:
|
183
|
+
loop.create_task(_acall(conn, future_uid, core_uid, args, kwargs))
|
184
|
+
elif op == PocketServerOperations.PREPARE_AUTH:
|
185
|
+
loop.create_task(_prepare(conn, future_uid, core_uid, args, kwargs))
|
186
|
+
elif op == PocketServerOperations.AUTHENTICATE:
|
187
|
+
loop.create_task(_authenticate(conn, future_uid, core_uid, args, kwargs))
|
188
|
+
elif op == PocketServerOperations.TOOL_CALL:
|
189
|
+
loop.create_task(_tool_call(conn, future_uid, core_uid, args, kwargs))
|
190
|
+
elif op == PocketServerOperations.PLUG_CORE:
|
191
|
+
loop.create_task(_plug_core(conn, future_uid, core_uid, args, kwargs))
|
127
192
|
else:
|
128
|
-
raise
|
193
|
+
raise ValueError(f"Unknown operation: {op}")
|
129
194
|
else:
|
130
195
|
await asyncio.sleep(0)
|
131
196
|
|
132
|
-
def send_in_parent(self, op: PocketServerOperations, args: tuple, kwargs: dict):
|
197
|
+
def send_in_parent(self, op: PocketServerOperations, pocket_uid: str, args: tuple, kwargs: dict):
|
133
198
|
conn, _ = self.pipe
|
134
|
-
|
135
|
-
message = (op
|
199
|
+
future_uid = str(uuid.uuid4())
|
200
|
+
message = (op, future_uid, pocket_uid, args, kwargs)
|
136
201
|
future = asyncio.Future()
|
137
|
-
self.future_store[
|
202
|
+
self.future_store[future_uid] = future
|
138
203
|
conn.send(message)
|
139
|
-
return
|
204
|
+
return future_uid
|
140
205
|
|
141
206
|
async def poll_in_parent(self):
|
142
207
|
conn, _ = self.pipe
|
143
208
|
while True:
|
144
209
|
if conn.poll():
|
145
|
-
|
210
|
+
uid, result, error = conn.recv()
|
146
211
|
future = self.future_store[uid]
|
147
212
|
if error:
|
148
213
|
future.set_exception(error)
|
@@ -153,19 +218,21 @@ class PocketServer(object):
|
|
153
218
|
await asyncio.sleep(0)
|
154
219
|
|
155
220
|
async def call_in_subprocess(
|
156
|
-
self, op: PocketServerOperations, args: tuple, kwargs: dict
|
221
|
+
self, op: PocketServerOperations, pocket_uid: str, args: tuple, kwargs: dict
|
157
222
|
):
|
158
|
-
uid = self.send_in_parent(op, args, kwargs)
|
223
|
+
uid = self.send_in_parent(op, pocket_uid, args, kwargs)
|
159
224
|
loop = asyncio.get_running_loop()
|
160
225
|
loop.create_task(self.poll_in_parent())
|
161
226
|
return await self.future_store[uid]
|
162
227
|
|
163
|
-
def run(self
|
228
|
+
def run(self):
|
164
229
|
self._set_mp_start_method()
|
165
230
|
|
166
231
|
error_queue = mp.Queue()
|
167
232
|
self.pipe = mp.Pipe()
|
168
|
-
self.process = mp.Process(
|
233
|
+
self.process = mp.Process(
|
234
|
+
target=self._run
|
235
|
+
)
|
169
236
|
self.process.start() # process start
|
170
237
|
|
171
238
|
if not error_queue.empty():
|
@@ -174,27 +241,25 @@ class PocketServer(object):
|
|
174
241
|
|
175
242
|
def _report_initialized(self, error: Optional[Exception] = None):
|
176
243
|
_, conn = self.pipe
|
177
|
-
conn.send(
|
178
|
-
(
|
179
|
-
"server-initialization",
|
180
|
-
error,
|
181
|
-
)
|
182
|
-
)
|
244
|
+
conn.send(('server-initialization', error,))
|
183
245
|
|
184
246
|
def wait_initialized(self):
|
247
|
+
if self._initialized:
|
248
|
+
return
|
185
249
|
conn, _ = self.pipe
|
186
250
|
while True:
|
187
251
|
if conn.poll():
|
188
252
|
_, error = conn.recv()
|
189
253
|
if error:
|
190
254
|
raise error
|
191
|
-
|
255
|
+
break
|
256
|
+
self._initialized = True
|
192
257
|
|
193
|
-
def _run(self
|
258
|
+
def _run(self):
|
194
259
|
try:
|
195
260
|
# init process
|
196
|
-
self.
|
197
|
-
self.main_server = self._create_main_server()
|
261
|
+
self.fastapi_app = self._create_fastapi_app()
|
262
|
+
self.main_server = self._create_main_server(self.fastapi_app)
|
198
263
|
self.proxy_server = self._create_https_proxy_server()
|
199
264
|
self._report_initialized()
|
200
265
|
|
@@ -204,20 +269,21 @@ class PocketServer(object):
|
|
204
269
|
except Exception as error:
|
205
270
|
self._report_initialized(error)
|
206
271
|
|
207
|
-
def
|
272
|
+
def _create_fastapi_app(self) -> FastAPI:
|
208
273
|
app = FastAPI()
|
274
|
+
app.include_router(auth_router)
|
275
|
+
app.add_api_route("/health", lambda: {"status": "ok"}, methods=["GET"])
|
276
|
+
return app
|
277
|
+
|
278
|
+
def _create_main_server(self, app: FastAPI) -> Server:
|
209
279
|
_config = Config(
|
210
280
|
app,
|
211
281
|
host="0.0.0.0",
|
212
282
|
port=self.internal_server_port,
|
213
283
|
log_level=config().log_level,
|
214
284
|
)
|
215
|
-
|
216
|
-
|
217
|
-
app.add_api_route("/health", lambda: {"status": "ok"}, methods=["GET"])
|
218
|
-
|
219
|
-
app = Server(_config)
|
220
|
-
return app
|
285
|
+
server = Server(_config)
|
286
|
+
return server
|
221
287
|
|
222
288
|
def _create_https_proxy_server(self) -> Optional[Server]:
|
223
289
|
if not config().enable_local_callback_proxy:
|
hyperpocket/session/in_memory.py
CHANGED
@@ -19,10 +19,20 @@ InMemorySessionValue = BaseSessionValue
|
|
19
19
|
class InMemorySessionStorage(
|
20
20
|
SessionStorageInterface[InMemorySessionKey, InMemorySessionValue]
|
21
21
|
):
|
22
|
-
|
22
|
+
_instance = None
|
23
|
+
_is_initialized = False
|
24
|
+
|
25
|
+
def __new__(cls, *args, **kwargs):
|
26
|
+
if cls._instance is None:
|
27
|
+
cls._instance = super(InMemorySessionStorage, cls).__new__(cls)
|
28
|
+
cls._instance._is_initialized = False
|
29
|
+
return cls._instance
|
30
|
+
|
23
31
|
def __init__(self, session_config: SessionConfigInMemory):
|
24
|
-
|
25
|
-
|
32
|
+
if not self._is_initialized:
|
33
|
+
super().__init__()
|
34
|
+
self.storage: Dict[InMemorySessionKey, InMemorySessionValue] = {}
|
35
|
+
self._is_initialized = True
|
26
36
|
|
27
37
|
@classmethod
|
28
38
|
def session_storage_type(cls) -> SessionType:
|
hyperpocket/tool/__init__.py
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
from hyperpocket.tool.function import from_dock, from_func, function_tool
|
2
2
|
from hyperpocket.tool.tool import Tool, ToolAuth, ToolRequest
|
3
|
-
from hyperpocket.tool.wasm.tool import from_git, from_local
|
4
3
|
|
5
4
|
__all__ = [
|
6
5
|
"Tool",
|
7
6
|
"ToolAuth",
|
8
7
|
"ToolRequest",
|
9
|
-
"from_local",
|
10
|
-
"from_git",
|
11
8
|
"from_dock",
|
12
9
|
"from_func",
|
13
10
|
"function_tool",
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import abc
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from fastapi import APIRouter
|
5
|
+
|
6
|
+
from hyperpocket.tool import ToolRequest
|
7
|
+
from hyperpocket.tool.function import FunctionTool
|
8
|
+
|
9
|
+
|
10
|
+
class Dock(abc.ABC):
|
11
|
+
_tool_requests: list[ToolRequest]
|
12
|
+
_dock_http_router: APIRouter
|
13
|
+
_dock_vars: dict[str, str]
|
14
|
+
|
15
|
+
def __init__(self, dock_vars: dict[str, str] = None):
|
16
|
+
self._dock_http_router = APIRouter()
|
17
|
+
self._tool_requests = []
|
18
|
+
self._dock_vars = dock_vars if dock_vars is not None else {}
|
19
|
+
|
20
|
+
@property
|
21
|
+
def router(self):
|
22
|
+
return self._dock_http_router
|
23
|
+
|
24
|
+
@abc.abstractmethod
|
25
|
+
def plug(self, req_like: Any, **kwargs):
|
26
|
+
raise NotImplementedError
|
27
|
+
|
28
|
+
@abc.abstractmethod
|
29
|
+
def tools(self) -> list[FunctionTool]:
|
30
|
+
raise NotImplementedError
|
31
|
+
|
32
|
+
@abc.abstractmethod
|
33
|
+
async def teardown(self):
|
34
|
+
raise NotImplementedError
|
@@ -17,19 +17,36 @@ class FunctionTool(Tool):
|
|
17
17
|
|
18
18
|
func: Optional[Callable[..., str]]
|
19
19
|
afunc: Optional[Callable[..., Coroutine[Any, Any, str]]]
|
20
|
+
keep_structured_arguments: bool = False
|
20
21
|
|
21
22
|
def invoke(self, **kwargs) -> str:
|
22
23
|
binding_args = self._get_binding_args(kwargs)
|
23
24
|
if self.func is None:
|
24
25
|
if self.afunc is None:
|
25
26
|
raise ValueError("Both func and afunc are None")
|
27
|
+
try:
|
28
|
+
loop = asyncio.get_running_loop()
|
29
|
+
return str(loop.run_until_complete(self.afunc(**binding_args)))
|
30
|
+
except RuntimeError:
|
31
|
+
pass
|
32
|
+
except Exception as e:
|
33
|
+
import traceback
|
34
|
+
traceback.print_exc()
|
35
|
+
traceback.print_stack()
|
36
|
+
return "There was an error while executing the tool: " + str(e)
|
26
37
|
try:
|
27
38
|
return str(asyncio.run(self.afunc(**binding_args)))
|
28
39
|
except Exception as e:
|
40
|
+
import traceback
|
41
|
+
traceback.print_exc()
|
42
|
+
traceback.print_stack()
|
29
43
|
return "There was an error while executing the tool: " + str(e)
|
30
44
|
try:
|
31
45
|
return str(self.func(**binding_args))
|
32
46
|
except Exception as e:
|
47
|
+
import traceback
|
48
|
+
traceback.print_exc()
|
49
|
+
traceback.print_stack()
|
33
50
|
return "There was an error while executing the tool: " + str(e)
|
34
51
|
|
35
52
|
async def ainvoke(self, **kwargs) -> str:
|
@@ -39,9 +56,16 @@ class FunctionTool(Tool):
|
|
39
56
|
binding_args = self._get_binding_args(kwargs)
|
40
57
|
return str(await self.afunc(**binding_args))
|
41
58
|
except Exception as e:
|
59
|
+
import traceback
|
60
|
+
traceback.print_exc()
|
61
|
+
traceback.print_stack()
|
42
62
|
return "There was an error while executing the tool: " + str(e)
|
43
63
|
|
44
64
|
def _get_binding_args(self, kwargs):
|
65
|
+
if self.keep_structured_arguments:
|
66
|
+
if kwargs.get("envs") is not None:
|
67
|
+
kwargs["envs"] |= self.tool_vars
|
68
|
+
return kwargs
|
45
69
|
_kwargs = copy.deepcopy(kwargs)
|
46
70
|
|
47
71
|
# make body args to model
|
@@ -54,28 +78,23 @@ class FunctionTool(Tool):
|
|
54
78
|
|
55
79
|
# binding args
|
56
80
|
binding_args = {}
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
else:
|
62
|
-
sig = inspect.signature(self.func)
|
63
|
-
for param_name, param in sig.parameters.items():
|
64
|
-
if param_name not in args:
|
65
|
-
continue
|
81
|
+
sig = inspect.signature(self.func)
|
82
|
+
for param_name, param in sig.parameters.items():
|
83
|
+
if param_name not in args:
|
84
|
+
continue
|
66
85
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
86
|
+
if param.kind == param.VAR_KEYWORD:
|
87
|
+
# var keyword args should be passed by plain dict
|
88
|
+
binding_args |= args[param_name]
|
89
|
+
binding_args |= _kwargs.get("envs", {}) | self.tool_vars
|
71
90
|
|
72
|
-
|
73
|
-
|
91
|
+
if "envs" in _kwargs:
|
92
|
+
_kwargs.pop("envs")
|
74
93
|
|
75
|
-
|
76
|
-
|
94
|
+
binding_args |= _kwargs # add other kwargs
|
95
|
+
continue
|
77
96
|
|
78
|
-
|
97
|
+
binding_args[param_name] = args[param_name]
|
79
98
|
|
80
99
|
return binding_args
|
81
100
|
|
@@ -89,11 +108,15 @@ class FunctionTool(Tool):
|
|
89
108
|
|
90
109
|
@classmethod
|
91
110
|
def from_func(
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
111
|
+
cls,
|
112
|
+
func: Callable | "FunctionTool",
|
113
|
+
afunc: Callable[..., Coroutine[Any, Any, str]] | "FunctionTool" = None,
|
114
|
+
name: str = None,
|
115
|
+
description: str = None,
|
116
|
+
json_schema: dict[str, Any] = None,
|
117
|
+
auth: Optional[ToolAuth] = None,
|
118
|
+
tool_vars: dict[str, str] = None,
|
119
|
+
keep_structured_arguments: bool = False,
|
97
120
|
) -> "FunctionTool":
|
98
121
|
if tool_vars is None:
|
99
122
|
tool_vars = dict()
|
@@ -109,28 +132,35 @@ class FunctionTool(Tool):
|
|
109
132
|
elif not callable(func) and not callable(afunc):
|
110
133
|
raise ValueError("FunctionTool can only be created from a callable")
|
111
134
|
|
112
|
-
|
113
|
-
|
135
|
+
name = name or (func and func.__name__) or (afunc and afunc.__name__)
|
136
|
+
description = description or (func and func.__doc__) or (afunc and func.__doc__)
|
137
|
+
schema = json_schema or \
|
138
|
+
(func and function_to_model(func).model_json_schema()) or \
|
139
|
+
(afunc and function_to_model(afunc).model_json_schema())
|
140
|
+
argument_json_schema = flatten_json_schema(schema)
|
114
141
|
|
115
142
|
return cls(
|
116
143
|
func=func,
|
117
144
|
afunc=afunc,
|
118
|
-
name=
|
119
|
-
description=
|
145
|
+
name=name,
|
146
|
+
description=description,
|
120
147
|
argument_json_schema=argument_json_schema,
|
121
148
|
auth=auth,
|
122
149
|
default_tool_vars=tool_vars,
|
150
|
+
keep_structured_arguments=keep_structured_arguments,
|
123
151
|
)
|
124
152
|
|
125
153
|
@classmethod
|
126
154
|
def from_dock(
|
127
|
-
|
128
|
-
|
129
|
-
|
155
|
+
cls,
|
156
|
+
dock: list[Callable[..., str]],
|
157
|
+
tool_vars: Optional[dict[str, str]] = None,
|
130
158
|
) -> list["FunctionTool"]:
|
131
159
|
if tool_vars is None:
|
132
160
|
tool_vars = dict()
|
133
161
|
tools = []
|
162
|
+
|
163
|
+
# @moon: will be refactored.
|
134
164
|
for func in dock:
|
135
165
|
if (_model := func.__dict__.get("__model__")) is not None:
|
136
166
|
model = _model
|
@@ -155,7 +185,7 @@ class FunctionTool(Tool):
|
|
155
185
|
argument_json_schema=argument_json_schema,
|
156
186
|
auth=auth,
|
157
187
|
default_tool_vars=(
|
158
|
-
|
188
|
+
tool_vars | func.__dict__.get("__vars__", {})
|
159
189
|
),
|
160
190
|
)
|
161
191
|
)
|
@@ -169,7 +199,7 @@ class FunctionTool(Tool):
|
|
169
199
|
argument_json_schema=argument_json_schema,
|
170
200
|
auth=auth,
|
171
201
|
default_tool_vars=(
|
172
|
-
|
202
|
+
tool_vars | func.__dict__.get("__vars__", {})
|
173
203
|
),
|
174
204
|
)
|
175
205
|
)
|
hyperpocket/tool/tool.py
CHANGED
@@ -116,21 +116,13 @@ class Tool(BaseModel, abc.ABC):
|
|
116
116
|
return self.description
|
117
117
|
|
118
118
|
def override_tool_variables(self, override_vars: dict[str, str]) -> "Tool":
|
119
|
-
self.overridden_tool_vars
|
119
|
+
self.overridden_tool_vars |= override_vars
|
120
120
|
return self
|
121
121
|
|
122
122
|
@property
|
123
123
|
def tool_vars(self) -> dict[str, str]:
|
124
124
|
return self.default_tool_vars | self.overridden_tool_vars
|
125
125
|
|
126
|
-
@classmethod
|
127
|
-
def from_tool_request(cls, tool_req: ToolRequest, **kwargs) -> "Tool":
|
128
|
-
from hyperpocket.tool.wasm.tool import WasmTool, WasmToolRequest
|
129
|
-
|
130
|
-
if isinstance(tool_req, WasmToolRequest):
|
131
|
-
return WasmTool.from_tool_request(tool_req, **kwargs)
|
132
|
-
raise ValueError("Unknown tool request type")
|
133
|
-
|
134
126
|
@classmethod
|
135
127
|
def _get_schema_model(
|
136
128
|
cls, name: str, json_schema: Optional[dict], use_profile: bool
|
hyperpocket/tool_like.py
CHANGED
@@ -60,13 +60,17 @@ def json_schema_to_model(
|
|
60
60
|
fields["additional_properties"] = (dict[str, additional_model], {})
|
61
61
|
|
62
62
|
# Create the model
|
63
|
-
model = create_model(model_name, **fields)
|
63
|
+
model = create_model(f"{model_name}", **fields)
|
64
64
|
|
65
65
|
# Add custom Config class to handle extra properties
|
66
66
|
class Config:
|
67
67
|
extra = config_extra
|
68
68
|
|
69
69
|
model.Config = Config
|
70
|
+
|
71
|
+
# workaround for pickling dynamic classes
|
72
|
+
model.__module__ = "__main__"
|
73
|
+
model.__qualname__ = model.__name__.split('.')[-1]
|
70
74
|
|
71
75
|
return model
|
72
76
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hyperpocket
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: Building AI agent with hyperpocket tool in a flash
|
5
5
|
Project-URL: Homepage, https://vessl-ai.github.io/hyperpocket
|
6
6
|
Project-URL: Repository, https://github.com/vessl-ai/hyperpocket
|
@@ -13,6 +13,7 @@ Requires-Dist: gitpython>=3.1.43
|
|
13
13
|
Requires-Dist: httpx==0.27
|
14
14
|
Requires-Dist: jinja2>=3.1.4
|
15
15
|
Requires-Dist: multiprocess>=0.70.17
|
16
|
+
Requires-Dist: nest-asyncio>=1.6.0
|
16
17
|
Requires-Dist: playwright>=1.49.0
|
17
18
|
Requires-Dist: pydantic>=2.10.2
|
18
19
|
Requires-Dist: pygithub>=2.5.0
|
@@ -21,6 +22,8 @@ Requires-Dist: redis>=5.2.1
|
|
21
22
|
Requires-Dist: requests>=2.32.3
|
22
23
|
Requires-Dist: toml>=0.10.2
|
23
24
|
Requires-Dist: uvicorn>=0.32.1
|
25
|
+
Provides-Extra: standard
|
26
|
+
Requires-Dist: hyperdock-container; extra == 'standard'
|
24
27
|
Description-Content-Type: text/markdown
|
25
28
|
|
26
29
|
<p align="center">
|