hyperpocket 0.1.10__py3-none-any.whl → 0.2.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.
Files changed (92) hide show
  1. hyperpocket/__init__.py +4 -4
  2. hyperpocket/auth/__init__.py +12 -7
  3. hyperpocket/auth/calendly/oauth2_handler.py +24 -17
  4. hyperpocket/auth/calendly/oauth2_schema.py +3 -1
  5. hyperpocket/auth/context.py +2 -1
  6. hyperpocket/auth/github/oauth2_handler.py +13 -8
  7. hyperpocket/auth/github/token_handler.py +27 -21
  8. hyperpocket/auth/google/context.py +1 -3
  9. hyperpocket/auth/google/oauth2_context.py +1 -1
  10. hyperpocket/auth/google/oauth2_handler.py +22 -17
  11. hyperpocket/auth/gumloop/token_context.py +1 -4
  12. hyperpocket/auth/gumloop/token_handler.py +48 -20
  13. hyperpocket/auth/gumloop/token_schema.py +2 -1
  14. hyperpocket/auth/handler.py +21 -6
  15. hyperpocket/auth/linear/token_context.py +2 -5
  16. hyperpocket/auth/linear/token_handler.py +45 -21
  17. hyperpocket/auth/notion/context.py +2 -2
  18. hyperpocket/auth/notion/token_context.py +2 -4
  19. hyperpocket/auth/notion/token_handler.py +45 -21
  20. hyperpocket/auth/notion/token_schema.py +0 -1
  21. hyperpocket/auth/reddit/oauth2_handler.py +9 -10
  22. hyperpocket/auth/reddit/oauth2_schema.py +0 -2
  23. hyperpocket/auth/schema.py +4 -1
  24. hyperpocket/auth/slack/oauth2_context.py +3 -1
  25. hyperpocket/auth/slack/oauth2_handler.py +55 -35
  26. hyperpocket/auth/slack/token_context.py +2 -4
  27. hyperpocket/auth/slack/token_handler.py +42 -19
  28. hyperpocket/builtin.py +4 -2
  29. hyperpocket/cli/__main__.py +4 -2
  30. hyperpocket/cli/auth.py +59 -28
  31. hyperpocket/cli/codegen/auth/auth_context_template.py +3 -2
  32. hyperpocket/cli/codegen/auth/auth_token_context_template.py +3 -2
  33. hyperpocket/cli/codegen/auth/auth_token_handler_template.py +6 -5
  34. hyperpocket/cli/codegen/auth/auth_token_schema_template.py +3 -2
  35. hyperpocket/cli/codegen/auth/server_auth_template.py +3 -2
  36. hyperpocket/cli/pull.py +5 -5
  37. hyperpocket/config/__init__.py +3 -8
  38. hyperpocket/config/auth.py +3 -1
  39. hyperpocket/config/logger.py +20 -15
  40. hyperpocket/config/session.py +4 -2
  41. hyperpocket/config/settings.py +19 -2
  42. hyperpocket/futures/__init__.py +1 -1
  43. hyperpocket/futures/futurestore.py +3 -2
  44. hyperpocket/pocket_auth.py +171 -84
  45. hyperpocket/pocket_core.py +51 -33
  46. hyperpocket/pocket_main.py +122 -93
  47. hyperpocket/prompts.py +2 -2
  48. hyperpocket/repository/__init__.py +1 -1
  49. hyperpocket/repository/lock.py +47 -33
  50. hyperpocket/repository/lockfile.py +2 -2
  51. hyperpocket/repository/repository.py +1 -1
  52. hyperpocket/server/__init__.py +1 -1
  53. hyperpocket/server/auth/github.py +2 -1
  54. hyperpocket/server/auth/linear.py +1 -3
  55. hyperpocket/server/auth/notion.py +2 -5
  56. hyperpocket/server/auth/slack.py +1 -3
  57. hyperpocket/server/auth/token.py +17 -11
  58. hyperpocket/server/proxy.py +29 -13
  59. hyperpocket/server/server.py +75 -31
  60. hyperpocket/server/tool/dto/script.py +15 -10
  61. hyperpocket/server/tool/wasm.py +14 -11
  62. hyperpocket/session/__init__.py +6 -2
  63. hyperpocket/session/in_memory.py +44 -24
  64. hyperpocket/session/interface.py +42 -24
  65. hyperpocket/session/redis.py +48 -31
  66. hyperpocket/tool/__init__.py +10 -10
  67. hyperpocket/tool/function/__init__.py +1 -5
  68. hyperpocket/tool/function/annotation.py +11 -9
  69. hyperpocket/tool/function/tool.py +37 -27
  70. hyperpocket/tool/tool.py +59 -36
  71. hyperpocket/tool/wasm/__init__.py +1 -1
  72. hyperpocket/tool/wasm/browser.py +15 -10
  73. hyperpocket/tool/wasm/invoker.py +16 -16
  74. hyperpocket/tool/wasm/script.py +27 -14
  75. hyperpocket/tool/wasm/templates/__init__.py +22 -15
  76. hyperpocket/tool/wasm/templates/node.py +2 -2
  77. hyperpocket/tool/wasm/templates/python.py +2 -2
  78. hyperpocket/tool/wasm/tool.py +27 -14
  79. hyperpocket/tool_like.py +3 -3
  80. hyperpocket/util/__init__.py +1 -1
  81. hyperpocket/util/extract_func_param_desc_from_docstring.py +23 -7
  82. hyperpocket/util/find_all_leaf_class_in_package.py +4 -3
  83. hyperpocket/util/find_all_subclass_in_package.py +4 -2
  84. hyperpocket/util/flatten_json_schema.py +10 -6
  85. hyperpocket/util/function_to_model.py +33 -12
  86. hyperpocket/util/get_objects_from_subpackage.py +1 -1
  87. hyperpocket/util/json_schema_to_model.py +14 -5
  88. {hyperpocket-0.1.10.dist-info → hyperpocket-0.2.0.dist-info}/METADATA +11 -5
  89. hyperpocket-0.2.0.dist-info/RECORD +137 -0
  90. hyperpocket-0.1.10.dist-info/RECORD +0 -137
  91. {hyperpocket-0.1.10.dist-info → hyperpocket-0.2.0.dist-info}/WHEEL +0 -0
  92. {hyperpocket-0.1.10.dist-info → hyperpocket-0.2.0.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,18 @@
1
1
  import json
2
- from typing import List, Optional, Any
2
+ from typing import Any, List, Optional
3
3
 
4
4
  import redis
5
5
 
6
- from hyperpocket.auth import AuthProvider, AUTH_CONTEXT_MAP
6
+ from hyperpocket.auth import AUTH_CONTEXT_MAP, AuthProvider
7
7
  from hyperpocket.auth.context import AuthContext
8
- from hyperpocket.config.session import SessionConfigRedis
9
- from hyperpocket.config.session import SessionType
10
- from hyperpocket.session.interface import SessionStorageInterface, SESSION_KEY_DELIMITER, \
11
- BaseSessionValue, V, K
8
+ from hyperpocket.config.session import SessionConfigRedis, SessionType
9
+ from hyperpocket.session.interface import (
10
+ SESSION_KEY_DELIMITER,
11
+ BaseSessionValue,
12
+ K,
13
+ SessionStorageInterface,
14
+ V,
15
+ )
12
16
 
13
17
  RedisSessionKey = str
14
18
  RedisSessionValue = BaseSessionValue
@@ -24,7 +28,9 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
24
28
  def session_storage_type(cls) -> SessionType:
25
29
  return SessionType.REDIS
26
30
 
27
- def get(self, auth_provider: AuthProvider, thread_id: str, profile: str, **kwargs) -> Optional[V]:
31
+ def get(
32
+ self, auth_provider: AuthProvider, thread_id: str, profile: str, **kwargs
33
+ ) -> Optional[V]:
28
34
  key = self._make_session_key(auth_provider.name, thread_id, profile)
29
35
  raw_session: Any = self.client.get(key)
30
36
  if raw_session is None:
@@ -33,7 +39,9 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
33
39
  session = self._deserialize(raw_session)
34
40
  return session
35
41
 
36
- def get_by_thread_id(self, thread_id: str, auth_provider: Optional[AuthProvider] = None, **kwargs) -> List[V]:
42
+ def get_by_thread_id(
43
+ self, thread_id: str, auth_provider: Optional[AuthProvider] = None, **kwargs
44
+ ) -> List[V]:
37
45
  if auth_provider is None:
38
46
  auth_provider_name = "*"
39
47
  else:
@@ -57,19 +65,24 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
57
65
 
58
66
  return session_list
59
67
 
60
- def set(self, auth_provider: AuthProvider,
61
- thread_id: str,
62
- profile: str,
63
- auth_scopes: List[str],
64
- auth_resolve_uid: Optional[str],
65
- auth_context: Optional[AuthContext],
66
- is_auth_scope_universal: bool, **kwargs) -> V:
68
+ def set(
69
+ self,
70
+ auth_provider: AuthProvider,
71
+ thread_id: str,
72
+ profile: str,
73
+ auth_scopes: List[str],
74
+ auth_resolve_uid: Optional[str],
75
+ auth_context: Optional[AuthContext],
76
+ is_auth_scope_universal: bool,
77
+ **kwargs,
78
+ ) -> V:
67
79
  session = self._make_session(
68
80
  auth_provider_name=auth_provider.name,
69
81
  auth_scopes=auth_scopes,
70
82
  auth_context=auth_context,
71
83
  auth_resolve_uid=auth_resolve_uid,
72
- is_auth_scope_universal=is_auth_scope_universal)
84
+ is_auth_scope_universal=is_auth_scope_universal,
85
+ )
73
86
 
74
87
  key = self._make_session_key(auth_provider.name, thread_id, profile)
75
88
 
@@ -77,7 +90,9 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
77
90
  self.client.set(key, raw_session)
78
91
  return session
79
92
 
80
- def delete(self, auth_provider: AuthProvider, thread_id: str, profile: str, **kwargs) -> bool:
93
+ def delete(
94
+ self, auth_provider: AuthProvider, thread_id: str, profile: str, **kwargs
95
+ ) -> bool:
81
96
  key = self._make_session_key(auth_provider.name, thread_id, profile)
82
97
  return self.client.delete(key) == 1
83
98
 
@@ -92,17 +107,18 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
92
107
 
93
108
  @staticmethod
94
109
  def _make_session(
95
- auth_provider_name: str,
96
- auth_scopes: List[str],
97
- auth_context: AuthContext,
98
- auth_resolve_uid: str,
99
- is_auth_scope_universal: bool) -> V:
110
+ auth_provider_name: str,
111
+ auth_scopes: List[str],
112
+ auth_context: AuthContext,
113
+ auth_resolve_uid: str,
114
+ is_auth_scope_universal: bool,
115
+ ) -> V:
100
116
  return RedisSessionValue(
101
117
  auth_provider_name=auth_provider_name,
102
118
  auth_scopes=set(auth_scopes),
103
119
  auth_context=auth_context,
104
120
  auth_resolve_uid=auth_resolve_uid,
105
- scoped=is_auth_scope_universal
121
+ scoped=is_auth_scope_universal,
106
122
  )
107
123
 
108
124
  @staticmethod
@@ -116,13 +132,14 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
116
132
  if auth_scopes:
117
133
  auth_scopes = list(auth_scopes)
118
134
 
119
- serialized = {"auth_context_value": auth_context_value,
120
- "auth_context_type": auth_context_type,
121
- "auth_provider_name": session.auth_provider_name,
122
- "scoped": session.scoped,
123
- "auth_scopes": auth_scopes,
124
- "auth_resolve_uid": session.auth_resolve_uid,
125
- }
135
+ serialized = {
136
+ "auth_context_value": auth_context_value,
137
+ "auth_context_type": auth_context_type,
138
+ "auth_provider_name": session.auth_provider_name,
139
+ "scoped": session.scoped,
140
+ "auth_scopes": auth_scopes,
141
+ "auth_resolve_uid": session.auth_resolve_uid,
142
+ }
126
143
 
127
144
  return json.dumps(serialized)
128
145
 
@@ -146,5 +163,5 @@ class RedisSessionStorage(SessionStorageInterface[RedisSessionKey, RedisSessionV
146
163
  auth_scopes=auth_scopes,
147
164
  auth_resolve_uid=session_dict["auth_resolve_uid"],
148
165
  scoped=session_dict["scoped"],
149
- auth_context=auth_context
166
+ auth_context=auth_context,
150
167
  )
@@ -1,14 +1,14 @@
1
1
  from hyperpocket.tool.function import from_dock, from_func, function_tool
2
- from hyperpocket.tool.tool import Tool, ToolRequest, ToolAuth
3
- from hyperpocket.tool.wasm.tool import from_local, from_git
2
+ from hyperpocket.tool.tool import Tool, ToolAuth, ToolRequest
3
+ from hyperpocket.tool.wasm.tool import from_git, from_local
4
4
 
5
5
  __all__ = [
6
- 'Tool',
7
- 'ToolAuth',
8
- 'ToolRequest',
9
- 'from_local',
10
- 'from_git',
11
- 'from_dock',
12
- 'from_func',
13
- 'function_tool'
6
+ "Tool",
7
+ "ToolAuth",
8
+ "ToolRequest",
9
+ "from_local",
10
+ "from_git",
11
+ "from_dock",
12
+ "from_func",
13
+ "function_tool",
14
14
  ]
@@ -4,8 +4,4 @@ from hyperpocket.tool.function.tool import FunctionTool
4
4
  from_func = FunctionTool.from_func
5
5
  from_dock = FunctionTool.from_dock
6
6
 
7
- __all__ = [
8
- "from_func",
9
- "from_dock",
10
- "function_tool"
11
- ]
7
+ __all__ = ["from_func", "from_dock", "function_tool"]
@@ -1,12 +1,18 @@
1
- from typing import List, Callable, Optional
1
+ from typing import Callable, List, Optional
2
2
 
3
3
  from hyperpocket.auth import AuthProvider
4
4
  from hyperpocket.tool.function.tool import FunctionTool
5
5
  from hyperpocket.tool.tool import ToolAuth
6
6
 
7
7
 
8
- def function_tool(func: Optional[Callable] = None, *, auth_provider: AuthProvider = None, scopes: List[str] = None,
9
- auth_handler: str = None, tool_vars: dict[str, str] = None):
8
+ def function_tool(
9
+ func: Optional[Callable] = None,
10
+ *,
11
+ auth_provider: AuthProvider = None,
12
+ scopes: List[str] = None,
13
+ auth_handler: str = None,
14
+ tool_vars: dict[str, str] = None,
15
+ ):
10
16
  def decorator(inner_func: Callable):
11
17
  if not callable(inner_func):
12
18
  raise ValueError("FunctionTool can only be created from a callable")
@@ -15,14 +21,10 @@ def function_tool(func: Optional[Callable] = None, *, auth_provider: AuthProvide
15
21
  auth = ToolAuth(
16
22
  auth_provider=auth_provider,
17
23
  scopes=scopes if scopes else [],
18
- auth_handler=auth_handler
24
+ auth_handler=auth_handler,
19
25
  )
20
26
 
21
- return FunctionTool.from_func(
22
- func=inner_func,
23
- auth=auth,
24
- tool_vars=tool_vars
25
- )
27
+ return FunctionTool.from_func(func=inner_func, auth=auth, tool_vars=tool_vars)
26
28
 
27
29
  if func is not None:
28
30
  return decorator(func)
@@ -1,8 +1,7 @@
1
1
  import asyncio
2
2
  import copy
3
3
  import inspect
4
- from typing import Any, Coroutine
5
- from typing import Callable, Optional
4
+ from typing import Any, Callable, Coroutine, Optional
6
5
 
7
6
  from pydantic import BaseModel
8
7
 
@@ -15,6 +14,7 @@ class FunctionTool(Tool):
15
14
  """
16
15
  FunctionTool is Tool executing local python method.
17
16
  """
17
+
18
18
  func: Optional[Callable[..., str]]
19
19
  afunc: Optional[Callable[..., Coroutine[Any, Any, str]]]
20
20
 
@@ -90,14 +90,14 @@ class FunctionTool(Tool):
90
90
  @classmethod
91
91
  def from_func(
92
92
  cls,
93
- func: Callable | 'FunctionTool',
94
- afunc: Callable[..., Coroutine[Any, Any, str]] | 'FunctionTool' = None,
93
+ func: Callable | "FunctionTool",
94
+ afunc: Callable[..., Coroutine[Any, Any, str]] | "FunctionTool" = None,
95
95
  auth: Optional[ToolAuth] = None,
96
96
  tool_vars: dict[str, str] = None,
97
97
  ) -> "FunctionTool":
98
98
  if tool_vars is None:
99
99
  tool_vars = dict()
100
-
100
+
101
101
  if isinstance(func, FunctionTool):
102
102
  if tool_vars is not None:
103
103
  func.override_tool_variables(tool_vars)
@@ -108,7 +108,7 @@ class FunctionTool(Tool):
108
108
  return afunc
109
109
  elif not callable(func) and not callable(afunc):
110
110
  raise ValueError("FunctionTool can only be created from a callable")
111
-
111
+
112
112
  model = function_to_model(func)
113
113
  argument_json_schema = flatten_json_schema(model.model_json_schema())
114
114
 
@@ -119,9 +119,9 @@ class FunctionTool(Tool):
119
119
  description=func.__doc__ if func.__doc__ is not None else "",
120
120
  argument_json_schema=argument_json_schema,
121
121
  auth=auth,
122
- default_tool_vars=tool_vars
122
+ default_tool_vars=tool_vars,
123
123
  )
124
-
124
+
125
125
  @classmethod
126
126
  def from_dock(
127
127
  cls,
@@ -138,29 +138,39 @@ class FunctionTool(Tool):
138
138
  model = function_to_model(func)
139
139
  argument_json_schema = flatten_json_schema(model.model_json_schema())
140
140
  if not callable(func):
141
- raise ValueError(f"Dock element should be a list of functions, but found {func}")
141
+ raise ValueError(
142
+ f"Dock element should be a list of functions, but found {func}"
143
+ )
142
144
  is_coroutine = inspect.iscoroutinefunction(func)
143
145
  auth = None
144
146
  if func.__dict__.get("__auth__") is not None:
145
147
  auth = ToolAuth(**func.__dict__["__auth__"])
146
148
  if is_coroutine:
147
- tools.append(cls(
148
- func=None,
149
- afunc=func,
150
- name=func.__name__,
151
- description=func.__doc__,
152
- argument_json_schema=argument_json_schema,
153
- auth=auth,
154
- default_tool_vars=(tool_vars | func.__dict__.get("__vars__", {})),
155
- ))
149
+ tools.append(
150
+ cls(
151
+ func=None,
152
+ afunc=func,
153
+ name=func.__name__,
154
+ description=func.__doc__,
155
+ argument_json_schema=argument_json_schema,
156
+ auth=auth,
157
+ default_tool_vars=(
158
+ tool_vars | func.__dict__.get("__vars__", {})
159
+ ),
160
+ )
161
+ )
156
162
  else:
157
- tools.append(cls(
158
- func=func,
159
- afunc=None,
160
- name=func.__name__,
161
- description=func.__doc__,
162
- argument_json_schema=argument_json_schema,
163
- auth=auth,
164
- default_tool_vars=(tool_vars | func.__dict__.get("__vars__", {})),
165
- ))
163
+ tools.append(
164
+ cls(
165
+ func=func,
166
+ afunc=None,
167
+ name=func.__name__,
168
+ description=func.__doc__,
169
+ argument_json_schema=argument_json_schema,
170
+ auth=auth,
171
+ default_tool_vars=(
172
+ tool_vars | func.__dict__.get("__vars__", {})
173
+ ),
174
+ )
175
+ )
166
176
  return tools
hyperpocket/tool/tool.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import abc
2
- from typing import Optional, Type, Callable
2
+ from typing import Callable, Optional, Type
3
3
 
4
4
  from pydantic import BaseModel, Field
5
5
 
@@ -13,23 +13,29 @@ class ToolAuth(BaseModel):
13
13
  """
14
14
  ToolAuth is an object that represents the authentication information required to invoke a tool
15
15
  """
16
+
16
17
  scopes: list[str] = Field(
17
18
  default=None,
18
19
  description="Indicates which authentication provider’s credentials are required to invoke the tool. "
19
- "If auth_provider is not specified, the tool is considered to require no authentication.")
20
+ "If auth_provider is not specified, the tool is considered to require no authentication.",
21
+ )
20
22
  auth_provider: Optional[AuthProvider] = Field(
21
23
  default=None,
22
24
  description="Specifies which authentication handler should be used when invoking the tool. "
23
- "If auth_handler is not specified, the default handler of the authentication provider will be used.")
25
+ "If auth_handler is not specified, the default handler of the authentication provider will be used.",
26
+ )
24
27
  auth_handler: Optional[str] = Field(
25
28
  default=None,
26
29
  description="Indicates the authentication scopes required to invoke the tool. "
27
- "If authentication is not performed or the authentication handler is non-scoped, the value should be None.")
30
+ "If authentication is not performed or the authentication handler is non-scoped, the value should be None.",
31
+ )
28
32
 
29
33
 
30
34
  class ToolRequest(abc.ABC):
31
35
  postprocessings: Optional[list[Callable]] = None
32
- overridden_tool_vars: dict[str, str] = Field(default_factory=dict, description="overridden tool variables")
36
+ overridden_tool_vars: dict[str, str] = Field(
37
+ default_factory=dict, description="overridden tool variables"
38
+ )
33
39
 
34
40
  @abc.abstractmethod
35
41
  def __str__(self):
@@ -52,7 +58,7 @@ class ToolRequest(abc.ABC):
52
58
  self.postprocessings.extend(postprocessings)
53
59
  return self
54
60
 
55
- def override_tool_variables(self, override_vars: dict[str, str]) -> 'ToolRequest':
61
+ def override_tool_variables(self, override_vars: dict[str, str]) -> "ToolRequest":
56
62
  self.overridden_tool_vars = override_vars
57
63
  return self
58
64
 
@@ -61,14 +67,24 @@ class Tool(BaseModel, abc.ABC):
61
67
  """
62
68
  Pocket Tool Interface
63
69
  """
70
+
64
71
  name: str = Field(description="tool name")
65
72
  description: str = Field(description="tool description")
66
- argument_json_schema: Optional[dict] = Field(default=None, description="tool argument json schema")
67
- auth: Optional[ToolAuth] = Field(default=None, description="authentication information to invoke tool")
68
- postprocessings: Optional[list[Callable]] = Field(default=None,
69
- description="postprocessing functions after tool is invoked")
70
- default_tool_vars: dict[str, str] = Field(default_factory=dict, description="default tool variables")
71
- overridden_tool_vars: dict[str, str] = Field(default_factory=dict, description="overridden tool variables")
73
+ argument_json_schema: Optional[dict] = Field(
74
+ default=None, description="tool argument json schema"
75
+ )
76
+ auth: Optional[ToolAuth] = Field(
77
+ default=None, description="authentication information to invoke tool"
78
+ )
79
+ postprocessings: Optional[list[Callable]] = Field(
80
+ default=None, description="postprocessing functions after tool is invoked"
81
+ )
82
+ default_tool_vars: dict[str, str] = Field(
83
+ default_factory=dict, description="default tool variables"
84
+ )
85
+ overridden_tool_vars: dict[str, str] = Field(
86
+ default_factory=dict, description="overridden tool variables"
87
+ )
72
88
  use_profile: bool = False
73
89
 
74
90
  @abc.abstractmethod
@@ -89,7 +105,9 @@ class Tool(BaseModel, abc.ABC):
89
105
  Returns a schema_model that wraps the existing argument_json_schema
90
106
  to include profile and thread_id as arguments when the tool is invoked
91
107
  """
92
- return self._get_schema_model(self.name, self.argument_json_schema, use_profile=use_profile)
108
+ return self._get_schema_model(
109
+ self.name, self.argument_json_schema, use_profile=use_profile
110
+ )
93
111
 
94
112
  def get_description(self, use_profile: bool = False) -> str:
95
113
  if use_profile:
@@ -97,7 +115,7 @@ class Tool(BaseModel, abc.ABC):
97
115
  else:
98
116
  return self.description
99
117
 
100
- def override_tool_variables(self, override_vars: dict[str, str]) -> 'Tool':
118
+ def override_tool_variables(self, override_vars: dict[str, str]) -> "Tool":
101
119
  self.overridden_tool_vars = override_vars
102
120
  return self
103
121
 
@@ -106,50 +124,55 @@ class Tool(BaseModel, abc.ABC):
106
124
  return self.default_tool_vars | self.overridden_tool_vars
107
125
 
108
126
  @classmethod
109
- def from_tool_request(cls, tool_req: ToolRequest, **kwargs) -> 'Tool':
127
+ def from_tool_request(cls, tool_req: ToolRequest, **kwargs) -> "Tool":
110
128
  from hyperpocket.tool.wasm.tool import WasmTool, WasmToolRequest
129
+
111
130
  if isinstance(tool_req, WasmToolRequest):
112
131
  return WasmTool.from_tool_request(tool_req, **kwargs)
113
- raise ValueError('Unknown tool request type')
132
+ raise ValueError("Unknown tool request type")
114
133
 
115
134
  @classmethod
116
- def _get_schema_model(cls, name: str, json_schema: Optional[dict], use_profile: bool) -> Optional[Type[BaseModel]]:
135
+ def _get_schema_model(
136
+ cls, name: str, json_schema: Optional[dict], use_profile: bool
137
+ ) -> Optional[Type[BaseModel]]:
117
138
  try:
118
139
  if not json_schema:
119
140
  pocket_logger.info(f"{name} tool's json_schema is none.")
120
141
  return None
121
- if 'description' not in json_schema:
122
- json_schema['description'] = 'The argument of the tool.'
142
+ if "description" not in json_schema:
143
+ json_schema["description"] = "The argument of the tool."
123
144
 
124
145
  if use_profile:
125
146
  json_schema = {
126
- 'title': name,
127
- 'type': 'object',
128
- 'properties': {
129
- 'thread_id': {
130
- 'type': 'string',
131
- 'default': 'default',
132
- 'description': 'The ID of the chat thread where the tool is invoked. Omitted when unknown.',
147
+ "title": name,
148
+ "type": "object",
149
+ "properties": {
150
+ "thread_id": {
151
+ "type": "string",
152
+ "default": "default",
153
+ "description": "The ID of the chat thread where the tool is invoked. Omitted when unknown.",
133
154
  },
134
- 'profile': {
135
- 'type': 'string',
136
- 'default': 'default',
137
- 'description': '''The profile of the user invoking the tool. Inferred from user's messages.
155
+ "profile": {
156
+ "type": "string",
157
+ "default": "default",
158
+ "description": """The profile of the user invoking the tool. Inferred from user's messages.
138
159
  Users can request tools to be invoked in specific personas, which is called a profile.
139
160
  If the user's profile name can be inferred from the query, pass it as a string in the 'profile'
140
- JSON property. Omitted when unknown.''',
161
+ JSON property. Omitted when unknown.""",
141
162
  },
142
- 'body': json_schema
163
+ "body": json_schema,
143
164
  },
144
- 'required': [
145
- 'body',
146
- ]
165
+ "required": [
166
+ "body",
167
+ ],
147
168
  }
148
169
 
149
170
  model = json_schema_to_model(json_schema, name)
150
171
  return model
151
172
  except Exception as e:
152
- pocket_logger.warning(f"failed to get tool({name}) schema model. error : {e}")
173
+ pocket_logger.warning(
174
+ f"failed to get tool({name}) schema model. error : {e}"
175
+ )
153
176
  pass
154
177
 
155
178
  def with_postprocessing(self, postprocessing: Callable):
@@ -1,3 +1,3 @@
1
1
  from hyperpocket.tool.wasm.tool import WasmTool
2
2
 
3
- __all__ = ["WasmTool"]
3
+ __all__ = ["WasmTool"]
@@ -1,11 +1,16 @@
1
1
  import asyncio
2
- import os
3
2
 
4
- from playwright.async_api import async_playwright, Page, Playwright, BrowserContext, Route
3
+ from playwright.async_api import (
4
+ BrowserContext,
5
+ Page,
6
+ Playwright,
7
+ Route,
8
+ async_playwright,
9
+ )
5
10
 
6
11
 
7
12
  class InvokerBrowser(object):
8
- _instance: 'InvokerBrowser' = None
13
+ _instance: "InvokerBrowser" = None
9
14
  _lock = asyncio.Lock()
10
15
  playwright: Playwright
11
16
  browser_context: BrowserContext
@@ -18,9 +23,9 @@ class InvokerBrowser(object):
18
23
  self.browser_context = await self.playwright.chromium.launch_persistent_context(
19
24
  headless=True,
20
25
  args=[
21
- '--disable-web-security=True',
26
+ "--disable-web-security=True",
22
27
  ],
23
- user_data_dir='/tmp/chrome_dev_user',
28
+ user_data_dir="/tmp/chrome_dev_user",
24
29
  )
25
30
 
26
31
  @classmethod
@@ -44,13 +49,13 @@ class InvokerBrowser(object):
44
49
  body=body,
45
50
  headers={
46
51
  **response.headers,
47
- 'Cross-Origin-Opener-Policy': 'same-origin',
48
- 'Cross-Origin-Embedder-Policy': 'require-corp',
49
- 'Cross-Origin-Resource-Policy': 'cross-origin',
50
- }
52
+ "Cross-Origin-Opener-Policy": "same-origin",
53
+ "Cross-Origin-Embedder-Policy": "require-corp",
54
+ "Cross-Origin-Resource-Policy": "cross-origin",
55
+ },
51
56
  )
52
57
 
53
- await page.route('**/*', _hijack_route)
58
+ await page.route("**/*", _hijack_route)
54
59
  return page
55
60
 
56
61
  async def teardown(self):
@@ -7,34 +7,34 @@ from urllib.parse import urljoin
7
7
  from hyperpocket.config import config
8
8
  from hyperpocket.futures import FutureStore
9
9
  from hyperpocket.tool.wasm.browser import InvokerBrowser
10
- from hyperpocket.tool.wasm.script import ScriptRuntime, ScriptStore, Script
10
+ from hyperpocket.tool.wasm.script import Script, ScriptRuntime, ScriptStore
11
11
  from hyperpocket.tool.wasm.templates import render
12
12
 
13
13
 
14
14
  class WasmInvoker(object):
15
- def invoke(self,
16
- tool_path: str,
17
- runtime: ScriptRuntime,
18
- body: Any,
19
- envs: dict,
20
- **kwargs) -> str:
15
+ def invoke(
16
+ self, tool_path: str, runtime: ScriptRuntime, body: Any, envs: dict, **kwargs
17
+ ) -> str:
21
18
  loop = asyncio.get_running_loop()
22
- return loop.run_until_complete(self.ainvoke(tool_path, runtime, body, envs, **kwargs))
19
+ return loop.run_until_complete(
20
+ self.ainvoke(tool_path, runtime, body, envs, **kwargs)
21
+ )
23
22
 
24
- async def ainvoke(self,
25
- tool_path: str,
26
- runtime: ScriptRuntime,
27
- body: Any,
28
- envs: dict,
29
- **kwargs) -> str:
23
+ async def ainvoke(
24
+ self, tool_path: str, runtime: ScriptRuntime, body: Any, envs: dict, **kwargs
25
+ ) -> str:
30
26
  uid = str(uuid.uuid4())
31
27
  html = render(runtime.value, uid, envs, json.dumps(body))
32
- script = Script(id=uid, tool_path=tool_path, rendered_html=html, runtime=runtime)
28
+ script = Script(
29
+ id=uid, tool_path=tool_path, rendered_html=html, runtime=runtime
30
+ )
33
31
  ScriptStore.add_script(script=script)
34
32
  future_data = FutureStore.create_future(uid=uid)
35
33
  browser = await InvokerBrowser.get_instance()
36
34
  page = await browser.new_page()
37
- url = urljoin(config.internal_base_url + '/', f'tools/wasm/scripts/{uid}/browse')
35
+ url = urljoin(
36
+ config().internal_base_url + "/", f"tools/wasm/scripts/{uid}/browse"
37
+ )
38
38
  await page.goto(url)
39
39
  stdout = await future_data.future
40
40
  await page.close()