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,134 +0,0 @@
1
- import base64
2
- import enum
3
- import pathlib
4
- from typing import Optional
5
-
6
- import toml
7
- from pydantic import BaseModel
8
-
9
- from hyperpocket.config import pocket_logger
10
-
11
-
12
- class ScriptRuntime(enum.Enum):
13
- Node = "node"
14
- Python = "python"
15
- Wasm = "wasm"
16
-
17
-
18
- _RuntimePackageFiles = {
19
- ScriptRuntime.Node: ["dist/index.js"],
20
- ScriptRuntime.Python: ["main.py", "requirements.txt"],
21
- ScriptRuntime.Wasm: ["dist/index.wasm"],
22
- }
23
-
24
-
25
- class ScriptFileNodeContent(BaseModel):
26
- contents: str
27
-
28
-
29
- class ScriptFileNode(BaseModel):
30
- directory: Optional[dict[str, "ScriptFileNode"]] = None
31
- file: Optional[ScriptFileNodeContent] = None
32
-
33
- @classmethod
34
- def create_file_tree(cls, path: str, contents: str) -> dict[str, "ScriptFileNode"]:
35
- path_split = path.split("/")
36
- if len(path_split) == 1:
37
- return {
38
- path_split[0]: ScriptFileNode(
39
- file=ScriptFileNodeContent(contents=contents)
40
- )
41
- }
42
- node = cls.create_file_tree("/".join(path_split[1:]), contents)
43
- return {path_split[0]: ScriptFileNode(directory=node)}
44
-
45
- @staticmethod
46
- def merge(
47
- a: dict[str, "ScriptFileNode"], b: [str, "ScriptFileNode"]
48
- ) -> dict[str, "ScriptFileNode"]:
49
- for k, v in b.items():
50
- if k in a:
51
- if a[k].directory and v.directory:
52
- a[k].directory = ScriptFileNode.merge(a[k].directory, v.directory)
53
- elif a[k].file and v.file:
54
- a[k].file = v.file
55
- else:
56
- a[k] = v
57
- return a
58
-
59
-
60
- class Script(BaseModel):
61
- id: str
62
- tool_path: str
63
- rendered_html: str
64
- runtime: ScriptRuntime
65
-
66
- def load_file_tree(self) -> dict[str, ScriptFileNode]:
67
- relpaths = _RuntimePackageFiles[self.runtime]
68
- file_tree = dict()
69
- for p in relpaths:
70
- filepath = pathlib.Path(self.tool_path) / p
71
- with filepath.open("r") as f:
72
- contents = f.read().encode("utf-8")
73
- encoded_bytes = base64.b64encode(contents)
74
- encoded_str = encoded_bytes.decode()
75
- file_tree = ScriptFileNode.merge(
76
- file_tree, ScriptFileNode.create_file_tree(p, encoded_str)
77
- )
78
- return file_tree
79
-
80
- @property
81
- def package_name(self) -> Optional[str]:
82
- if self.runtime != ScriptRuntime.Python:
83
- return
84
- pyproject = toml.load(pathlib.Path(self.tool_path) / "pyproject.toml")
85
- if "project" in pyproject:
86
- name = pyproject["project"]["name"]
87
- if "tool" in pyproject and "poetry" in pyproject["tool"]:
88
- name = pyproject["tool"]["poetry"]["name"]
89
- if not name:
90
- raise ValueError("Could not find package name")
91
- return name.replace("-", "_")
92
-
93
- @property
94
- def entrypoint(self) -> str:
95
- pocket_logger.info(self.tool_path)
96
- if self.runtime == ScriptRuntime.Node:
97
- return "dist/index.js"
98
- elif self.runtime == ScriptRuntime.Wasm:
99
- return "dist/main.wasm"
100
- pyproject = toml.load(pathlib.Path(self.tool_path) / "pyproject.toml")
101
- version = None
102
- if "project" in pyproject:
103
- version = pyproject["project"]["version"]
104
- elif "tool" in pyproject and "poetry" in pyproject["tool"]:
105
- version = pyproject["tool"]["poetry"]["version"]
106
- else:
107
- raise ValueError("Could not find package version")
108
- wheel_name = f"{self.package_name}-{version}-py3-none-any.whl"
109
- wheel_path = pathlib.Path(self.tool_path) / "dist" / wheel_name
110
- if not wheel_path.exists():
111
- raise ValueError(f"Wheel file {wheel_path} does not exist")
112
- return wheel_name
113
-
114
- def dist_file_path(self, file_name: str) -> str:
115
- return str(pathlib.Path(self.tool_path) / "dist" / file_name)
116
-
117
-
118
- class _ScriptStore(object):
119
- scripts: dict[str, Script] = {}
120
-
121
- def __init__(self):
122
- self.rendered_html = {}
123
-
124
- def add_script(self, script: Script):
125
- if script.id in self.scripts:
126
- raise ValueError("Script id already exists")
127
- self.scripts[script.id] = script
128
-
129
- def get_script(self, script_id: str) -> Script:
130
- # ValueError exception is intentional
131
- return self.scripts[script_id]
132
-
133
-
134
- ScriptStore = _ScriptStore()
@@ -1,35 +0,0 @@
1
- import base64
2
- import json
3
-
4
- from jinja2 import DictLoader, Environment
5
-
6
- from hyperpocket.tool.wasm.templates.node import node_template
7
- from hyperpocket.tool.wasm.templates.python import python_template
8
-
9
- TemplateEnvironments = Environment(
10
- loader=DictLoader(
11
- {
12
- "python.html": python_template,
13
- "node.html": node_template,
14
- }
15
- ),
16
- autoescape=False,
17
- )
18
-
19
-
20
- def render(
21
- language: str, script_id: str, env: dict[str, str], body: str, **kwargs
22
- ) -> str:
23
- env_json = json.dumps(env)
24
- template = TemplateEnvironments.get_template(f"{language.lower()}.html")
25
- body_bytes = body.encode("utf-8")
26
- body_b64_bytes = base64.b64encode(body_bytes)
27
- body_b64 = body_b64_bytes.decode("ascii")
28
- return template.render(
29
- **{
30
- "SCRIPT_ID": script_id,
31
- "ENV_JSON": env_json,
32
- "BODY_JSON_B64": body_b64,
33
- }
34
- | kwargs
35
- )
@@ -1,87 +0,0 @@
1
- node_template = """
2
- <!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>PyScript Offline</title>
8
- </head>
9
- <body>
10
- <script type="module">
11
- function loadConfig() {
12
- globalThis.toolConfigs = {
13
- envs: `{{ ENV_JSON }}`,
14
- body: `{{ BODY_JSON_B64 }}`,
15
- scriptID: `{{ SCRIPT_ID }}`
16
- }
17
- }
18
- import { WebContainer } from 'https://esm.run/@webcontainer/api@1.5.1';
19
- function decodeContent(content) {
20
- return Uint8Array.from(atob(content), c => c.charCodeAt(0));
21
- }
22
- function decodeFileTree(filetree) {
23
- const decoded = {};
24
- for (const [key, value] of Object.entries(filetree)) {
25
- if (value.file) {
26
- decoded[key] = {
27
- file: {
28
- contents: decodeContent(value.file.contents)
29
- }
30
- }
31
- } else if (value.directory) {
32
- decoded[key] = {
33
- directory: decodeFileTree(value.directory)
34
- }
35
- } else if (value.symlink) {
36
- decoded[key] = {
37
- symlink: value.symlink
38
- }
39
- }
40
- }
41
- return decoded;
42
- }
43
- async function main() {
44
- loadConfig();
45
- const b64FilesResp = await fetch(`/tools/wasm/scripts/${globalThis.toolConfigs.scriptID}/file_tree`);
46
- const b64Files = await b64FilesResp.json();
47
- const files = decodeFileTree(b64Files.tree);
48
- const webcontainer = await WebContainer.boot();
49
-
50
- await webcontainer.mount(files)
51
- const envs = JSON.parse(globalThis.toolConfigs.envs)
52
- envs['DEPLOYED'] = 'true'
53
- const runProcess = await webcontainer.spawn('node', ['dist/index.js'], {
54
- output: true,
55
- env: envs,
56
- });
57
- const stdin = runProcess.input.getWriter();
58
- const decodedBytes = atob(globalThis.toolConfigs.body);
59
- await (async () => {
60
- await stdin.ready
61
- await stdin.write(decodedBytes);
62
- })()
63
- let stdout = '';
64
- runProcess.output.pipeTo(
65
- new WritableStream({
66
- write(chunk) {
67
- stdout += chunk;
68
- }
69
- })
70
- )
71
- await runProcess.exit;
72
- if (stdout.startsWith(decodedBytes)) {
73
- stdout = stdout.slice(decodedBytes);
74
- }
75
- await fetch(`/tools/wasm/scripts/${globalThis.toolConfigs.scriptID}/done`, {
76
- method: 'POST',
77
- headers: {
78
- 'Content-Type': 'application/json'
79
- },
80
- body: JSON.stringify({ stdout })
81
- });
82
- }
83
- main();
84
- </script>
85
- </body>
86
- </html>
87
- """
@@ -1,93 +0,0 @@
1
- python_template = """
2
- <!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>PyScript Offline</title>
8
- <script src="https://cdn.jsdelivr.net/pyodide/v0.26.4/full/pyodide.js"></script>
9
- </head>
10
- <body>
11
- <script type="module">
12
- function loadConfig() {
13
- globalThis.toolConfigs = {
14
- envs: `{{ ENV_JSON }}`,
15
- body: `{{ BODY_JSON_B64 }}`,
16
- scriptID: `{{ SCRIPT_ID }}`
17
- }
18
- }
19
- async function _main() {
20
- // load the script configs
21
- loadConfig();
22
-
23
- // get entrypoint wheel
24
- const entrypointResp = await fetch(`/tools/wasm/scripts/${globalThis.toolConfigs.scriptID}/entrypoint`);
25
- const { package_name: packageName, entrypoint } = await entrypointResp.json();
26
-
27
- // initialize pyodide
28
- const pyodide = await loadPyodide({
29
- env: JSON.parse(globalThis.toolConfigs.envs),
30
- });
31
- await pyodide.loadPackage("micropip");
32
- await pyodide.loadPackage("ssl");
33
- const micropip = pyodide.pyimport("micropip");
34
- await micropip.install(entrypoint);
35
- await micropip.install("pyodide-http")
36
-
37
- let emitted = false;
38
- const decodedBytes = atob(globalThis.toolConfigs.body);
39
- pyodide.setStdin({
40
- stdin: () => {
41
- if (emitted) {
42
- return null;
43
- }
44
- emitted = true;
45
- return decodedBytes;
46
- },
47
- autoEOF: true,
48
- })
49
- let stdout = "";
50
- let stderr = "";
51
- pyodide.setStdout({
52
- batched: (x) => { stdout += x; },
53
- })
54
- pyodide.setStderr({
55
- batched: (x) => { stderr += x; },
56
- })
57
- await pyodide.runPythonAsync(`
58
- import pyodide_http
59
- pyodide_http.patch_all()
60
-
61
- import ${packageName}
62
- ${packageName}.main()
63
- `);
64
- console.log(stdout)
65
- await fetch(`/tools/wasm/scripts/${globalThis.toolConfigs.scriptID}/done`, {
66
- method: 'POST',
67
- headers: {
68
- 'Content-Type': 'application/json'
69
- },
70
- body: JSON.stringify({ stdout, stderr })
71
- });
72
- }
73
-
74
- async function main() {
75
- try {
76
- await _main();
77
- } catch (e) {
78
- console.error(e);
79
- await fetch(`/tools/wasm/scripts/${globalThis.toolConfigs.scriptID}/done`, {
80
- method: 'POST',
81
- headers: {
82
- 'Content-Type': 'application/json'
83
- },
84
- body: JSON.stringify({ error: e.message })
85
- });
86
- }
87
- }
88
-
89
- main();
90
- </script>
91
- </body>
92
- </html>
93
- """
@@ -1,163 +0,0 @@
1
- import json
2
- import pathlib
3
- from typing import Any, Optional
4
-
5
- import toml
6
-
7
- from hyperpocket.auth import AuthProvider
8
- from hyperpocket.config import pocket_logger
9
- from hyperpocket.repository import Lock, Lockfile
10
- from hyperpocket.repository.lock import GitLock, LocalLock
11
- from hyperpocket.tool import Tool, ToolRequest
12
- from hyperpocket.tool.tool import ToolAuth
13
- from hyperpocket.tool.wasm.invoker import WasmInvoker
14
- from hyperpocket.tool.wasm.script import ScriptRuntime
15
-
16
-
17
- class WasmToolRequest(ToolRequest):
18
- lock: Lock
19
- rel_path: str
20
-
21
- def __init__(self, lock: Lock, rel_path: str, tool_vars: dict):
22
- self.lock = lock
23
- self.rel_path = rel_path
24
- self.overridden_tool_vars = tool_vars
25
-
26
- def __str__(self):
27
- return f"ToolRequest(lock={self.lock}, rel_path={self.rel_path})"
28
-
29
-
30
- def from_local(
31
- path: str, tool_vars: Optional[dict[str, str]] = None
32
- ) -> WasmToolRequest:
33
- if tool_vars is None:
34
- tool_vars = dict()
35
- return WasmToolRequest(LocalLock(path), "", tool_vars)
36
-
37
-
38
- def from_git(
39
- repository: str, ref: str, rel_path: str, tool_vars: Optional[dict[str, str]] = None
40
- ) -> WasmToolRequest:
41
- if not tool_vars:
42
- tool_vars = dict()
43
- return WasmToolRequest(
44
- GitLock(repository_url=repository, git_ref=ref), rel_path, tool_vars
45
- )
46
-
47
-
48
- class WasmTool(Tool):
49
- """
50
- WasmTool is Tool executing local python method.
51
- """
52
-
53
- _invoker: WasmInvoker = None
54
- pkg_lock: Lock = None
55
- rel_path: str
56
- runtime: ScriptRuntime = None
57
- json_schema: Optional[dict] = None
58
- readme: Optional[str] = None
59
-
60
- @property
61
- def invoker(self) -> WasmInvoker:
62
- if not self._invoker:
63
- self._invoker = WasmInvoker()
64
- return self._invoker
65
-
66
- @classmethod
67
- def from_tool_request(
68
- cls, tool_req: WasmToolRequest, lockfile: Lockfile = None, **kwargs
69
- ) -> "WasmTool":
70
- if not lockfile:
71
- raise ValueError("lockfile is required")
72
- tool_req.lock = lockfile.get_lock(tool_req.lock.key())
73
- toolpkg_path = tool_req.lock.toolpkg_path()
74
- rel_path = tool_req.rel_path
75
- rootpath = pathlib.Path(toolpkg_path) / rel_path
76
- schema_path = rootpath / "schema.json"
77
- config_path = rootpath / "config.toml"
78
- readme_path = rootpath / "README.md"
79
-
80
- try:
81
- with schema_path.open("r") as f:
82
- json_schema = json.load(f)
83
- except Exception as e:
84
- pocket_logger.warning(
85
- f"{toolpkg_path} failed to load json schema. error : {e}"
86
- )
87
- json_schema = None
88
-
89
- default_tool_vars = dict()
90
- try:
91
- with config_path.open("r") as f:
92
- config = toml.load(f)
93
- name = config.get("name")
94
- description = config.get("description")
95
- if language := config.get("language"):
96
- lang = language.lower()
97
- if lang == "python":
98
- runtime = ScriptRuntime.Python
99
- elif lang == "node":
100
- runtime = ScriptRuntime.Node
101
- else:
102
- raise ValueError(f"The language `{lang}` is not supported.")
103
- else:
104
- raise ValueError("`language` field is required in config.toml")
105
- auth = cls._get_auth(config)
106
- default_tool_vars = config.get("tool_vars", {})
107
- except Exception as e:
108
- raise ValueError(f"Failed to load config.toml: {e}")
109
-
110
- if readme_path.exists():
111
- with readme_path.open("r") as f:
112
- readme = f.read()
113
- else:
114
- readme = None
115
-
116
- return cls(
117
- name=name,
118
- description=description,
119
- argument_json_schema=json_schema,
120
- auth=auth,
121
- runtime=runtime,
122
- readme=readme,
123
- pkg_lock=tool_req.lock,
124
- rel_path=tool_req.rel_path,
125
- postprocessings=tool_req.postprocessings,
126
- default_tool_vars=default_tool_vars,
127
- overridden_tool_vars=tool_req.overridden_tool_vars,
128
- )
129
-
130
- @classmethod
131
- def _get_auth(cls, config: dict) -> Optional[ToolAuth]:
132
- auth = config.get("auth")
133
- if not auth:
134
- return
135
- auth_provider = auth.get("auth_provider")
136
- auth_handler = auth.get("auth_handler")
137
- scopes = auth.get("scopes", [])
138
- return ToolAuth(
139
- auth_provider=AuthProvider.get_auth_provider(auth_provider),
140
- auth_handler=auth_handler,
141
- scopes=scopes,
142
- )
143
-
144
- def template_arguments(self) -> dict[str, str]:
145
- return {}
146
-
147
- def invoke(self, body: Any, envs: dict, **kwargs) -> str:
148
- return self.invoker.invoke(
149
- str(self.pkg_lock.toolpkg_path() / self.rel_path),
150
- self.runtime,
151
- body,
152
- envs | self.tool_vars,
153
- **kwargs,
154
- )
155
-
156
- async def ainvoke(self, body: Any, envs: dict, **kwargs) -> str:
157
- return await self.invoker.ainvoke(
158
- str(self.pkg_lock.toolpkg_path() / self.rel_path),
159
- self.runtime,
160
- body,
161
- envs | self.tool_vars,
162
- **kwargs,
163
- )