hyperpocket 0.3.7__py3-none-any.whl → 0.4.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. hyperpocket/auth/activeloop/token_handler.py +4 -0
  2. hyperpocket/auth/adobe/token_handler.py +4 -0
  3. hyperpocket/auth/affinity/token_handler.py +4 -0
  4. hyperpocket/auth/agentql/token_handler.py +4 -0
  5. hyperpocket/auth/ahrefs/token_handler.py +4 -0
  6. hyperpocket/auth/airtable/token_handler.py +4 -0
  7. hyperpocket/auth/alchemy/token_handler.py +4 -0
  8. hyperpocket/auth/altoviz/token_handler.py +4 -0
  9. hyperpocket/auth/bamboohr/token_handler.py +4 -0
  10. hyperpocket/auth/bitwarden/token_handler.py +4 -0
  11. hyperpocket/auth/brevo/README.md +1 -1
  12. hyperpocket/auth/brevo/token_handler.py +4 -0
  13. hyperpocket/auth/brex/token_handler.py +4 -0
  14. hyperpocket/auth/cal/token_handler.py +4 -0
  15. hyperpocket/auth/canvas/token_handler.py +4 -0
  16. hyperpocket/auth/clickup/token_handler.py +4 -0
  17. hyperpocket/auth/cloudflare/token_handler.py +4 -0
  18. hyperpocket/auth/dailybot/token_handler.py +4 -0
  19. hyperpocket/auth/datadog/token_handler.py +4 -0
  20. hyperpocket/auth/discordbot/README.md +0 -1
  21. hyperpocket/auth/discordbot/token_handler.py +4 -0
  22. hyperpocket/auth/elevenlabs/token_handler.py +4 -0
  23. hyperpocket/auth/exa/token_handler.py +4 -0
  24. hyperpocket/auth/facebook/oauth2_handler.py +4 -0
  25. hyperpocket/auth/finage/token_handler.py +4 -0
  26. hyperpocket/auth/happyrobot/token_handler.py +4 -0
  27. hyperpocket/auth/heygen/token_handler.py +4 -0
  28. hyperpocket/auth/klaviyo/token_handler.py +4 -0
  29. hyperpocket/auth/lever/token_handler.py +4 -0
  30. hyperpocket/auth/lever_sandbox/token_handler.py +4 -0
  31. hyperpocket/auth/listennotes/token_handler.py +4 -0
  32. hyperpocket/auth/mem0/token_handler.py +4 -0
  33. hyperpocket/auth/microsoft_clarity/token_handler.py +4 -0
  34. hyperpocket/auth/neon/token_handler.py +4 -0
  35. hyperpocket/auth/ngrok/token_handler.py +4 -0
  36. hyperpocket/auth/oncehub/token_handler.py +4 -0
  37. hyperpocket/auth/pagerduty/token_handler.py +4 -0
  38. hyperpocket/auth/pandadoc/token_handler.py +4 -0
  39. hyperpocket/auth/pipedrive/token_handler.py +4 -0
  40. hyperpocket/auth/posthog/token_handler.py +4 -0
  41. hyperpocket/auth/provider.py +1 -0
  42. hyperpocket/auth/ravenseotools/token_handler.py +4 -0
  43. hyperpocket/auth/semantic_scholar/token_handler.py +4 -0
  44. hyperpocket/auth/sendgrid/token_handler.py +4 -0
  45. hyperpocket/auth/stripe/token_handler.py +4 -0
  46. hyperpocket/auth/supabase/token_handler.py +4 -0
  47. hyperpocket/auth/tavily/token_handler.py +4 -0
  48. hyperpocket/auth/timekit/token_handler.py +4 -0
  49. hyperpocket/auth/trello/token_handler.py +4 -0
  50. hyperpocket/auth/wandb/token_handler.py +4 -0
  51. hyperpocket/auth/weaviate/context.py +12 -0
  52. hyperpocket/auth/weaviate/token_context.py +11 -0
  53. hyperpocket/auth/weaviate/token_handler.py +68 -0
  54. hyperpocket/auth/weaviate/token_schema.py +7 -0
  55. hyperpocket/auth/workiom/token_handler.py +4 -0
  56. hyperpocket/auth/zinc/token_handler.py +4 -0
  57. hyperpocket/cli/eject.py +2 -7
  58. hyperpocket/cli/pull.py +2 -7
  59. hyperpocket/config/settings.py +2 -1
  60. hyperpocket/pocket_core.py +41 -68
  61. hyperpocket/pocket_main.py +37 -16
  62. hyperpocket/repository/__init__.py +3 -4
  63. hyperpocket/repository/repository.py +6 -41
  64. hyperpocket/repository/tool_reference.py +28 -0
  65. hyperpocket/server/auth/weaviate.py +27 -0
  66. hyperpocket/server/server.py +127 -61
  67. hyperpocket/session/in_memory.py +13 -3
  68. hyperpocket/tool/__init__.py +0 -3
  69. hyperpocket/tool/dock/__init__.py +3 -0
  70. hyperpocket/tool/dock/dock.py +34 -0
  71. hyperpocket/tool/function/__init__.py +1 -1
  72. hyperpocket/tool/function/tool.py +62 -32
  73. hyperpocket/tool/tool.py +1 -9
  74. hyperpocket/tool_like.py +2 -1
  75. hyperpocket/util/generate_slug.py +4 -0
  76. hyperpocket/util/json_schema_to_model.py +5 -1
  77. {hyperpocket-0.3.7.dist-info → hyperpocket-0.4.1.dist-info}/METADATA +4 -1
  78. {hyperpocket-0.3.7.dist-info → hyperpocket-0.4.1.dist-info}/RECORD +81 -87
  79. hyperpocket/cli/sync.py +0 -17
  80. hyperpocket/repository/lock.py +0 -240
  81. hyperpocket/repository/lockfile.py +0 -62
  82. hyperpocket/server/tool/__init__.py +0 -10
  83. hyperpocket/server/tool/dto/script.py +0 -33
  84. hyperpocket/server/tool/wasm.py +0 -46
  85. hyperpocket/tool/wasm/README.md +0 -166
  86. hyperpocket/tool/wasm/__init__.py +0 -3
  87. hyperpocket/tool/wasm/browser.py +0 -63
  88. hyperpocket/tool/wasm/invoker.py +0 -41
  89. hyperpocket/tool/wasm/script.py +0 -134
  90. hyperpocket/tool/wasm/templates/__init__.py +0 -35
  91. hyperpocket/tool/wasm/templates/node.py +0 -87
  92. hyperpocket/tool/wasm/templates/python.py +0 -93
  93. hyperpocket/tool/wasm/tool.py +0 -163
  94. /hyperpocket/{server/tool/dto → auth/weaviate}/__init__.py +0 -0
  95. {hyperpocket-0.3.7.dist-info → hyperpocket-0.4.1.dist-info}/WHEEL +0 -0
  96. {hyperpocket-0.3.7.dist-info → hyperpocket-0.4.1.dist-info}/entry_points.txt +0 -0
@@ -1,240 +0,0 @@
1
- import abc
2
- import pathlib
3
- import shutil
4
- from typing import Optional, Tuple, ClassVar
5
-
6
- import git
7
- from pydantic import BaseModel, Field
8
- from pydantic.fields import ModelPrivateAttr
9
-
10
- from hyperpocket.config import pocket_logger, settings
11
-
12
-
13
- class Lock(BaseModel, abc.ABC):
14
- tool_source: str = None
15
-
16
- @abc.abstractmethod
17
- def __str__(self):
18
- raise NotImplementedError
19
-
20
- @abc.abstractmethod
21
- def key(self) -> tuple[str, ...]:
22
- raise NotImplementedError
23
-
24
- @abc.abstractmethod
25
- def sync(self, **kwargs):
26
- raise NotImplementedError
27
-
28
- @abc.abstractmethod
29
- def toolpkg_path(self) -> pathlib.Path:
30
- raise NotImplementedError
31
-
32
- def eject_to_path(self, dest_path: pathlib.Path, src_sub_path: str = None):
33
- ## local locks are already tracked by git
34
- raise NotImplementedError
35
-
36
-
37
- class LocalLock(Lock):
38
- tool_source: str = Field(default="local")
39
- tool_path: str
40
-
41
- def __init__(self, tool_path: str):
42
- super().__init__(
43
- tool_source="local", tool_path=str(pathlib.Path(tool_path).resolve())
44
- )
45
-
46
- def __str__(self):
47
- return f"local\t{self.tool_path}"
48
-
49
- def key(self):
50
- return self.tool_source, self.tool_path.rstrip("/")
51
-
52
- def sync(self, **kwargs):
53
- pocket_logger.info(f"Syncing path: {self.tool_path} ...")
54
- pkg_path = self.toolpkg_path()
55
- if pkg_path.exists():
56
- shutil.rmtree(pkg_path)
57
- shutil.copytree(self.tool_path, pkg_path)
58
-
59
- def toolpkg_path(self) -> pathlib.Path:
60
- pocket_pkgs = settings.toolpkg_path
61
- return pocket_pkgs / "local" / self.tool_path[1:]
62
-
63
-
64
- class GitLock(Lock):
65
- _remote_cache: ClassVar[dict[str, dict[str, str]]]
66
- tool_source: str = "git"
67
- repository_url: str
68
- git_ref: str
69
- ref_sha: Optional[str] = None
70
-
71
- def __str__(self):
72
- return f"git\t{self.repository_url}\t{self.git_ref}\t{self.ref_sha}"
73
-
74
- def key(self):
75
- return self.tool_source, self.repository_url.rstrip("/"), self.git_ref
76
-
77
- def toolpkg_path(self) -> pathlib.Path:
78
- if not self.ref_sha:
79
- raise ValueError("ref_sha is not set")
80
- cleansed_url = self.repository_url
81
- if self.repository_url.startswith("http://"):
82
- cleansed_url = self.repository_url[7:]
83
- elif self.repository_url.startswith("https://"):
84
- cleansed_url = self.repository_url[8:]
85
- elif self.repository_url.startswith("git@"):
86
- cleansed_url = self.repository_url[4:]
87
- return settings.toolpkg_path / cleansed_url / self.ref_sha
88
-
89
- def sync(self, force_update: bool = False, **kwargs):
90
- """
91
- Synchronize the local git repository with the target remote branch.
92
-
93
- 1. Check if the SHA of the target ref in the remote repository matches the current local SHA.
94
- 2. If they do not match, fetch the target ref from the remote repository and do a hard reset
95
- to align the local repository with the remote version.
96
- """
97
- try:
98
- pocket_logger.info(
99
- f"Syncing git: {self.repository_url} @ ref: {self.git_ref} ..."
100
- )
101
-
102
- # get new sha from refs
103
- new_sha = self._get_new_sha_if_exists_in_remote()
104
- if new_sha is None:
105
- raise ValueError(
106
- f"Could not find ref {self.git_ref} in {self.repository_url}"
107
- )
108
-
109
- # check self.ref_sha should be updated
110
- if self.ref_sha != new_sha:
111
- if force_update or self.ref_sha is None:
112
- self.ref_sha = new_sha
113
-
114
- # make pkg_version_path dir if not exists
115
- pkg_version_path = self.toolpkg_path()
116
- if not pkg_version_path.exists():
117
- pkg_version_path.mkdir(parents=True)
118
-
119
- # init git repo in local and set origin url
120
- repo = git.Repo.init(pkg_version_path)
121
- try:
122
- remote = repo.remote("origin")
123
- remote.set_url(self.repository_url)
124
- except ValueError:
125
- remote = repo.create_remote("origin", self.repository_url)
126
-
127
- # check current local commit include new_sha
128
- # if not included, fetch and do hard reset
129
- exist_sha = None
130
- try:
131
- exist_sha = repo.head.commit.hexsha
132
- except ValueError:
133
- pass
134
- if exist_sha is None or exist_sha != self.ref_sha:
135
- remote.fetch(depth=1, refspec=self.ref_sha)
136
- repo.git.checkout(new_sha)
137
- repo.git.reset("--hard", new_sha)
138
- repo.git.clean("-fd")
139
- except Exception as e:
140
- pocket_logger.error(
141
- f"failed to sync git: {self.repository_url} @ ref: {self.git_ref}. reason : {e}"
142
- )
143
- raise e
144
-
145
- def _get_new_sha_if_exists_in_remote(self):
146
- """
147
- get new sha in refs
148
- First, check remote sha is matched to saved ref_sha
149
- Second, check remote ref name is matched to saved ref name
150
- Third, check local ref name is matched to saved ref name
151
- And last, check tag ref name is matched to saved ref name
152
- """
153
- refs = git.cmd.Git().ls_remote(self.repository_url)
154
-
155
- new_sha = None
156
- for r in refs.split("\n"):
157
- sha, ref = r.split("\t")
158
- if sha == self.ref_sha:
159
- new_sha = sha
160
- break
161
- elif ref == self.git_ref:
162
- new_sha = sha
163
- break
164
- elif ref == f"refs/heads/{self.git_ref}":
165
- new_sha = sha
166
- break
167
- elif ref == f"refs/tags/{self.git_ref}":
168
- new_sha = sha
169
- break
170
- return new_sha
171
-
172
- @classmethod
173
- def get_git_branches(cls, repo_url):
174
- if not hasattr(cls, "_remote_cache"):
175
- cls._remote_cache = {}
176
- if cls._remote_cache.get(repo_url) is None:
177
- ls_lists = git.cmd.Git().ls_remote(repo_url)
178
-
179
- branches = {}
180
- for line in ls_lists.split("\n"):
181
- sha, ref = line.split("\t")
182
- if ref.startswith("refs/heads/"):
183
- branch_name = ref.replace("refs/heads/", "")
184
- branches[branch_name] = sha
185
- cls._remote_cache[repo_url] = branches
186
- return cls._remote_cache[repo_url]
187
-
188
- @classmethod
189
- def parse_repo_url(cls, repo_url: str) -> Tuple[str, str, str]:
190
- """
191
- Parses a GitHub repository URL with optional branch and path information.
192
-
193
- Returns:
194
- Tuple[str, str, str]: base_repo, branch_name, directory_path
195
- """
196
- if not repo_url.startswith("https://github.com/"):
197
- raise AttributeError("Only GitHub URLs are supported")
198
-
199
- # Remove the base URL and split the path
200
- repo_path = repo_url.removeprefix("https://github.com/")
201
- repo_path_list = repo_path.split("/")
202
-
203
- # Check if the URL contains 'tree' (indicating branch and sub-path information)
204
- if "tree" not in repo_path_list:
205
- # If no 'tree', return the full repository URL
206
- return repo_url, "HEAD", ""
207
-
208
- # Parse base repo URL and remaining path
209
- tree_index = repo_path_list.index("tree")
210
- base_repo = f"https://github.com/{'/'.join(repo_path_list[:tree_index])}"
211
- sub_path = repo_path_list[tree_index + 1 :]
212
-
213
- # Fetch branch information
214
- branches = cls.get_git_branches(base_repo)
215
-
216
- # Find branch and sub-directory path
217
- for idx in range(1, len(sub_path) + 1):
218
- branch_name = "/".join(sub_path[:idx])
219
- if branch_name in branches:
220
- directory_path = (
221
- "/".join(sub_path[idx:]) if idx < len(sub_path) else None
222
- )
223
- return base_repo, branch_name, directory_path
224
-
225
- # If no valid branch is found, raise an error
226
- raise ValueError("Branch not found in repository")
227
-
228
- def eject_to_path(self, dest_path: pathlib.Path, src_sub_path: str = None):
229
- # clone the git repository to the target path
230
- pocket_logger.info(
231
- f"Ejecting git: {self.repository_url} @ ref: {self.git_ref} source in path: {src_sub_path} to {dest_path} ..."
232
- )
233
- if dest_path.exists():
234
- shutil.rmtree(dest_path)
235
-
236
- if src_sub_path:
237
- src_path = self.toolpkg_path() / src_sub_path
238
- else:
239
- src_path = self.toolpkg_path()
240
- shutil.copytree(src_path, dest_path)
@@ -1,62 +0,0 @@
1
- import pathlib
2
- from concurrent.futures.thread import ThreadPoolExecutor
3
-
4
- from hyperpocket.repository.lock import GitLock, LocalLock, Lock
5
-
6
-
7
- class Lockfile:
8
- path: pathlib.Path = None
9
- locks: dict[tuple, Lock] = None
10
- referenced_locks: set[tuple] = None
11
-
12
- def __init__(self, path: pathlib.Path):
13
- self.path = path
14
- self.locks = {}
15
- self.referenced_locks = set()
16
- if self.path.exists():
17
- with open(self.path, "r") as f:
18
- for line in f:
19
- split = line.strip().split("\t")
20
- source = split[0]
21
- if source == "local":
22
- lock = LocalLock(tool_path=split[1])
23
- elif source == "git":
24
- lock = GitLock(
25
- repository_url=split[1],
26
- git_ref=split[2],
27
- ref_sha=split[3],
28
- )
29
- else:
30
- raise ValueError(f"Unknown tool source: {source}")
31
- self.locks[lock.key()] = lock
32
- else:
33
- self.path.touch()
34
-
35
- def add_lock(self, lock: Lock):
36
- if lock.key() not in self.locks:
37
- self.locks[lock.key()] = lock
38
- self.referenced_locks.add(lock.key())
39
-
40
- def remove_lock(self, key: tuple[str, ...]):
41
- self.locks.pop(key)
42
- if key in self.referenced_locks:
43
- self.referenced_locks.remove(key)
44
-
45
- def get_lock(self, key: tuple[str, ...]):
46
- return self.locks[key]
47
-
48
- def sync(self, force_update: bool, referenced_only: bool = False):
49
- if referenced_only:
50
- locks = [self.get_lock(key) for key in self.referenced_locks]
51
- else:
52
- locks = list(self.locks.values())
53
- with ThreadPoolExecutor(
54
- max_workers=min(len(locks) + 1, 100), thread_name_prefix="repository_loader"
55
- ) as executor:
56
- executor.map(lambda lock: lock.sync(force_update=force_update), locks)
57
- self.write()
58
-
59
- def write(self):
60
- with open(self.path, "w") as f:
61
- for lock in self.locks.values():
62
- f.write(str(lock) + "\n")
@@ -1,10 +0,0 @@
1
- from fastapi import APIRouter
2
-
3
- from hyperpocket.server.tool.wasm import wasm_tool_router
4
-
5
- tool_router = APIRouter(
6
- prefix="/tools",
7
- )
8
- tool_router.include_router(wasm_tool_router)
9
-
10
- __all__ = ["tool_router"]
@@ -1,33 +0,0 @@
1
- from typing import Optional
2
-
3
- from pydantic import BaseModel, Field
4
-
5
- from hyperpocket.tool.wasm.script import ScriptFileNode
6
-
7
-
8
- class Script(BaseModel):
9
- id: str = Field(alias="id")
10
- tool_id: str = Field(alias="tool_id")
11
-
12
-
13
- class ScriptResult(BaseModel):
14
- stdout: Optional[str] = Field(alias="stdout", default=None)
15
- stderr: Optional[str] = Field(alias="stderr", default=None)
16
- error: Optional[str] = Field(alias="error", default=None)
17
-
18
-
19
- class ScriptFileTree(BaseModel):
20
- tree: dict[str, ScriptFileNode] = Field(alias="tree")
21
-
22
-
23
- class ScriptEntrypoint(BaseModel):
24
- package_name: Optional[str] = Field(alias="package_name")
25
- entrypoint: str = Field(alias="entrypoint")
26
-
27
-
28
- class ScriptEncodedFile(BaseModel):
29
- encoded_file: str = Field(alias="encoded_file")
30
-
31
-
32
- class ScriptFileRequest(BaseModel):
33
- path: str = Field(alias="path")
@@ -1,46 +0,0 @@
1
- from fastapi import APIRouter
2
- from fastapi.responses import FileResponse, HTMLResponse
3
-
4
- from hyperpocket.futures import FutureStore
5
- from hyperpocket.server.tool.dto import script as scriptdto
6
- from hyperpocket.tool.wasm.script import ScriptStore
7
-
8
- wasm_tool_router = APIRouter(prefix="/wasm")
9
-
10
-
11
- @wasm_tool_router.get("/scripts/{script_id}/browse", response_class=HTMLResponse)
12
- async def browse_script_page(script_id: str):
13
- html = ScriptStore.get_script(script_id).rendered_html
14
- return HTMLResponse(content=html)
15
-
16
-
17
- @wasm_tool_router.post("/scripts/{script_id}/done")
18
- async def done_script_page(
19
- script_id: str, req: scriptdto.ScriptResult
20
- ) -> scriptdto.ScriptResult:
21
- FutureStore.resolve_future(
22
- script_id, {"stdout": req.stdout, "stderr": req.stderr, "error": req.error}
23
- )
24
- return req
25
-
26
-
27
- @wasm_tool_router.get("/scripts/{script_id}/file_tree")
28
- async def get_file_tree(script_id: str) -> scriptdto.ScriptFileTree:
29
- script = ScriptStore.get_script(script_id)
30
- return scriptdto.ScriptFileTree(tree=script.load_file_tree())
31
-
32
-
33
- @wasm_tool_router.get("/scripts/{script_id}/entrypoint")
34
- async def get_entrypoint(script_id: str) -> scriptdto.ScriptEntrypoint:
35
- script = ScriptStore.get_script(script_id)
36
- package_name = script.package_name
37
- entrypoint = f"/tools/wasm/scripts/{script_id}/file/{script.entrypoint}"
38
- return scriptdto.ScriptEntrypoint(package_name=package_name, entrypoint=entrypoint)
39
-
40
-
41
- @wasm_tool_router.get(
42
- "/scripts/{script_id}/file/{file_name}", response_class=FileResponse
43
- )
44
- async def get_dist_file(script_id: str, file_name: str):
45
- script = ScriptStore.get_script(script_id)
46
- return FileResponse(script.dist_file_path(file_name))
@@ -1,166 +0,0 @@
1
- # Wasm(WebAssembly)
2
-
3
- ---
4
-
5
- ## How To Use
6
-
7
- ### plain url
8
-
9
- load the tool by providing a GitHub URL
10
-
11
- ```python
12
- from hyperpocket import Pocket
13
-
14
- pocket = Pocket(tools=[
15
- 'https://github.com/your-organization/your-repository/tree/main',
16
- ])
17
- ```
18
-
19
- - in this case, read tool code from `main` branch by default
20
-
21
- ### from_git
22
-
23
- - using `from_git`, you can specify branch and tool code path
24
-
25
- ```python
26
- from hyperpocket import Pocket
27
- from hyperpocket.tool import from_git
28
-
29
- pocket = Pocket(tools=[
30
- from_git("https://github.com/your-organization/your-repository", "branch-name", "your/tool/code/path"),
31
- ])
32
- ```
33
-
34
- ### from_local
35
-
36
- - using `from_local`, you can load a tool by specifying a local path
37
-
38
- ```python
39
- from hyperpocket import Pocket
40
- from hyperpocket.tool import from_local
41
-
42
- pocket = Pocket(tools=[
43
- from_local("your/local/tool/code/path")
44
- ])
45
- ```
46
-
47
- ## WasmToolRequest
48
-
49
- The class to initiate WasmTool
50
-
51
- WasmToolRequest offer those build method:
52
-
53
- - `from_local`
54
- - `from_git`
55
-
56
- Each `WasmToolRequest` has it's own `Lock` object
57
-
58
- Those `Lock` object is managed by `Lockfile` in the `Pocket` class
59
-
60
- ```mermaid
61
- classDiagram
62
- class WasmToolRequest {
63
- +Lock lock
64
- + from_git()
65
- + from_local()
66
- }
67
-
68
- class Lock{
69
- +key()
70
- +sync()
71
- }
72
-
73
- class GitLock{
74
- +key()
75
- +sync()
76
- }
77
-
78
- class LocalLock{
79
- +key()
80
- +sync()
81
- }
82
-
83
- class Lockfile {
84
- +dict[tuple,Lock] locks
85
-
86
- + add_lock()
87
- + get_lock()
88
- + sync()
89
- + write()
90
- }
91
-
92
- ToolRequest <|.. WasmToolRequest : Implementation
93
- Lock o-- WasmToolRequest : 1..1
94
- Lock <|.. GitLock : Implementation
95
- Lock <|.. LocalLock : Implementation
96
- Lock o-- Lockfile : n..1
97
- Lockfile o-- Pocket : 1..1
98
- ```
99
-
100
- ### Inject tool variables
101
-
102
- If the user specifies [tool_vars] in the `config.toml` of the tool's repository, which is allowed to be injected dynamically when the user develops an agent, it can be injected through the following steps.
103
-
104
- ```toml
105
- # config.toml of a tool
106
-
107
- [tool_vars]
108
- config1 = "config1"
109
- config2 = "config2"
110
- ```
111
-
112
- 1. Injecting tool_vars when importing tool in code.
113
-
114
- ```python
115
- from_git('https://github.com/your-organization/your-repository/tree/main',tool_vars = {
116
- "config1": "modified_config1"
117
- })
118
- ```
119
-
120
- 2. Injecting tool_vars by settings.toml
121
- Hyperpocket checks the `settings.toml` from the agent code directory.
122
-
123
- ## WasmTool
124
-
125
- ```python
126
- class WasmTool(Tool):
127
- _invoker: WasmInvoker = None
128
- pkg_lock: Lock = None
129
- rel_path: str
130
- runtime: ScriptRuntime = None
131
- json_schema: Optional[dict] = None
132
- readme: Optional[str] = None
133
- ```
134
-
135
- - `_invoker`: A class for executing WASM.
136
- - `pkg_lock`: The lock class for the tool.
137
- - Used for determining the package path where the current WASM code is stored.
138
- - `rel_path`: The relative path to the location of the WASM code within the package.
139
- - `runtime`: The runtime language of the WASM code.
140
- - `json_schema`: The JSON schema for the WASM tool.
141
- - Information read from schema.json.
142
- - `readme`: The README information.
143
-
144
- ## WasmInvoker
145
-
146
- A class for running actual WASM
147
-
148
- 1. Combines runtime information, authentication details, and body content to render HTML.
149
- 2. Stores the rendered HTML in memory.
150
- 3. Launches a browser to execute the WASM.
151
- 4. The browser sends a request to the server to retrieve the rendered HTML.
152
- 5. Executes code specific to each runtime within the HTML and returns the result.
153
-
154
- ```mermaid
155
- sequenceDiagram
156
- participant WasmTool as WasmTool (Includes Server)
157
- participant Browser as Browser (Executes WASM Runtime)
158
-
159
-
160
- WasmTool->>WasmTool: Render HTML and Store in Memory
161
- WasmTool->>Browser: Launch Browser
162
- Browser->>WasmTool: Request Rendered HTML
163
- WasmTool->>Browser: Provide Rendered HTML
164
- Browser->>Browser: Execute Injected WASM Runtime Script
165
- Browser->>WasmTool: Return Execution Result
166
- ```
@@ -1,3 +0,0 @@
1
- from hyperpocket.tool.wasm.tool import WasmTool
2
-
3
- __all__ = ["WasmTool"]
@@ -1,63 +0,0 @@
1
- import asyncio
2
-
3
- from playwright.async_api import (
4
- BrowserContext,
5
- Page,
6
- Playwright,
7
- Route,
8
- async_playwright,
9
- )
10
-
11
-
12
- class InvokerBrowser(object):
13
- _instance: "InvokerBrowser" = None
14
- _lock = asyncio.Lock()
15
- playwright: Playwright
16
- browser_context: BrowserContext
17
-
18
- def __init__(self):
19
- raise RuntimeError("Use InvokerBrowser.get_instance() instead")
20
-
21
- async def _async_init(self):
22
- self.playwright = await async_playwright().start()
23
- self.browser_context = await self.playwright.chromium.launch_persistent_context(
24
- headless=True,
25
- args=[
26
- "--disable-web-security=True",
27
- ],
28
- user_data_dir="/tmp/chrome_dev_user",
29
- )
30
-
31
- @classmethod
32
- async def get_instance(cls):
33
- if not cls._instance:
34
- async with cls._lock:
35
- if cls._instance is None:
36
- instance = cls.__new__(cls)
37
- await instance._async_init()
38
- cls._instance = instance
39
- return cls._instance
40
-
41
- async def new_page(self) -> Page:
42
- page = await self.browser_context.new_page()
43
-
44
- async def _hijack_route(route: Route):
45
- response = await route.fetch()
46
- body = await response.body()
47
- await route.fulfill(
48
- response=response,
49
- body=body,
50
- headers={
51
- **response.headers,
52
- "Cross-Origin-Opener-Policy": "same-origin",
53
- "Cross-Origin-Embedder-Policy": "require-corp",
54
- "Cross-Origin-Resource-Policy": "cross-origin",
55
- },
56
- )
57
-
58
- await page.route("**/*", _hijack_route)
59
- return page
60
-
61
- async def teardown(self):
62
- await self.browser_context.close()
63
- await self.playwright.stop()
@@ -1,41 +0,0 @@
1
- import asyncio
2
- import json
3
- import uuid
4
- from typing import Any
5
- from urllib.parse import urljoin
6
-
7
- from hyperpocket.config import config
8
- from hyperpocket.futures import FutureStore
9
- from hyperpocket.tool.wasm.browser import InvokerBrowser
10
- from hyperpocket.tool.wasm.script import Script, ScriptRuntime, ScriptStore
11
- from hyperpocket.tool.wasm.templates import render
12
-
13
-
14
- class WasmInvoker(object):
15
- def invoke(
16
- self, tool_path: str, runtime: ScriptRuntime, body: Any, envs: dict, **kwargs
17
- ) -> str:
18
- loop = asyncio.get_running_loop()
19
- return loop.run_until_complete(
20
- self.ainvoke(tool_path, runtime, body, envs, **kwargs)
21
- )
22
-
23
- async def ainvoke(
24
- self, tool_path: str, runtime: ScriptRuntime, body: Any, envs: dict, **kwargs
25
- ) -> str:
26
- uid = str(uuid.uuid4())
27
- html = render(runtime.value, uid, envs, json.dumps(body))
28
- script = Script(
29
- id=uid, tool_path=tool_path, rendered_html=html, runtime=runtime
30
- )
31
- ScriptStore.add_script(script=script)
32
- future_data = FutureStore.create_future(uid=uid)
33
- browser = await InvokerBrowser.get_instance()
34
- page = await browser.new_page()
35
- url = urljoin(
36
- config().internal_base_url + "/", f"tools/wasm/scripts/{uid}/browse"
37
- )
38
- await page.goto(url)
39
- stdout = await future_data.future
40
- await page.close()
41
- return stdout