hyperpocket 0.0.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. hyperpocket/__init__.py +7 -0
  2. hyperpocket/auth/README.KR.md +309 -0
  3. hyperpocket/auth/README.md +323 -0
  4. hyperpocket/auth/__init__.py +24 -0
  5. hyperpocket/auth/calendly/__init__.py +0 -0
  6. hyperpocket/auth/calendly/context.py +13 -0
  7. hyperpocket/auth/calendly/oauth2_context.py +25 -0
  8. hyperpocket/auth/calendly/oauth2_handler.py +146 -0
  9. hyperpocket/auth/calendly/oauth2_schema.py +16 -0
  10. hyperpocket/auth/context.py +38 -0
  11. hyperpocket/auth/github/__init__.py +0 -0
  12. hyperpocket/auth/github/context.py +13 -0
  13. hyperpocket/auth/github/oauth2_context.py +25 -0
  14. hyperpocket/auth/github/oauth2_handler.py +143 -0
  15. hyperpocket/auth/github/oauth2_schema.py +16 -0
  16. hyperpocket/auth/github/token_context.py +12 -0
  17. hyperpocket/auth/github/token_handler.py +79 -0
  18. hyperpocket/auth/github/token_schema.py +9 -0
  19. hyperpocket/auth/google/__init__.py +0 -0
  20. hyperpocket/auth/google/context.py +15 -0
  21. hyperpocket/auth/google/oauth2_context.py +31 -0
  22. hyperpocket/auth/google/oauth2_handler.py +137 -0
  23. hyperpocket/auth/google/oauth2_schema.py +18 -0
  24. hyperpocket/auth/handler.py +171 -0
  25. hyperpocket/auth/linear/__init__.py +0 -0
  26. hyperpocket/auth/linear/context.py +15 -0
  27. hyperpocket/auth/linear/token_context.py +15 -0
  28. hyperpocket/auth/linear/token_handler.py +68 -0
  29. hyperpocket/auth/linear/token_schema.py +9 -0
  30. hyperpocket/auth/provider.py +16 -0
  31. hyperpocket/auth/schema.py +19 -0
  32. hyperpocket/auth/slack/__init__.py +0 -0
  33. hyperpocket/auth/slack/context.py +15 -0
  34. hyperpocket/auth/slack/oauth2_context.py +40 -0
  35. hyperpocket/auth/slack/oauth2_handler.py +151 -0
  36. hyperpocket/auth/slack/oauth2_schema.py +40 -0
  37. hyperpocket/auth/slack/tests/__init__.py +0 -0
  38. hyperpocket/auth/slack/tests/test_oauth2_handler.py +32 -0
  39. hyperpocket/auth/slack/tests/test_token_handler.py +23 -0
  40. hyperpocket/auth/slack/token_context.py +14 -0
  41. hyperpocket/auth/slack/token_handler.py +64 -0
  42. hyperpocket/auth/slack/token_schema.py +9 -0
  43. hyperpocket/auth/tests/__init__.py +0 -0
  44. hyperpocket/auth/tests/test_google_oauth2_handler.py +147 -0
  45. hyperpocket/auth/tests/test_slack_oauth2_handler.py +147 -0
  46. hyperpocket/auth/tests/test_slack_token_handler.py +66 -0
  47. hyperpocket/cli/__init__.py +0 -0
  48. hyperpocket/cli/__main__.py +12 -0
  49. hyperpocket/cli/pull.py +18 -0
  50. hyperpocket/cli/sync.py +17 -0
  51. hyperpocket/config/__init__.py +9 -0
  52. hyperpocket/config/auth.py +36 -0
  53. hyperpocket/config/git.py +17 -0
  54. hyperpocket/config/logger.py +81 -0
  55. hyperpocket/config/session.py +35 -0
  56. hyperpocket/config/settings.py +62 -0
  57. hyperpocket/constants.py +0 -0
  58. hyperpocket/curated_tools.py +10 -0
  59. hyperpocket/external/__init__.py +7 -0
  60. hyperpocket/external/github_client.py +19 -0
  61. hyperpocket/futures/__init__.py +7 -0
  62. hyperpocket/futures/futurestore.py +48 -0
  63. hyperpocket/pocket_auth.py +344 -0
  64. hyperpocket/pocket_main.py +351 -0
  65. hyperpocket/prompts.py +15 -0
  66. hyperpocket/repository/__init__.py +5 -0
  67. hyperpocket/repository/lock.py +156 -0
  68. hyperpocket/repository/lockfile.py +56 -0
  69. hyperpocket/repository/repository.py +18 -0
  70. hyperpocket/server/__init__.py +3 -0
  71. hyperpocket/server/auth/__init__.py +15 -0
  72. hyperpocket/server/auth/calendly.py +16 -0
  73. hyperpocket/server/auth/github.py +25 -0
  74. hyperpocket/server/auth/google.py +16 -0
  75. hyperpocket/server/auth/linear.py +18 -0
  76. hyperpocket/server/auth/slack.py +28 -0
  77. hyperpocket/server/auth/token.py +51 -0
  78. hyperpocket/server/proxy.py +63 -0
  79. hyperpocket/server/server.py +178 -0
  80. hyperpocket/server/tool/__init__.py +10 -0
  81. hyperpocket/server/tool/dto/__init__.py +0 -0
  82. hyperpocket/server/tool/dto/script.py +15 -0
  83. hyperpocket/server/tool/wasm.py +31 -0
  84. hyperpocket/session/README.KR.md +62 -0
  85. hyperpocket/session/README.md +61 -0
  86. hyperpocket/session/__init__.py +4 -0
  87. hyperpocket/session/in_memory.py +76 -0
  88. hyperpocket/session/interface.py +118 -0
  89. hyperpocket/session/redis.py +126 -0
  90. hyperpocket/session/tests/__init__.py +0 -0
  91. hyperpocket/session/tests/test_in_memory.py +145 -0
  92. hyperpocket/session/tests/test_redis.py +151 -0
  93. hyperpocket/tests/__init__.py +0 -0
  94. hyperpocket/tests/test_pocket.py +118 -0
  95. hyperpocket/tests/test_pocket_auth.py +982 -0
  96. hyperpocket/tool/README.KR.md +68 -0
  97. hyperpocket/tool/README.md +75 -0
  98. hyperpocket/tool/__init__.py +13 -0
  99. hyperpocket/tool/builtins/__init__.py +0 -0
  100. hyperpocket/tool/builtins/example/__init__.py +0 -0
  101. hyperpocket/tool/builtins/example/add_tool.py +18 -0
  102. hyperpocket/tool/function/README.KR.md +159 -0
  103. hyperpocket/tool/function/README.md +169 -0
  104. hyperpocket/tool/function/__init__.py +9 -0
  105. hyperpocket/tool/function/annotation.py +30 -0
  106. hyperpocket/tool/function/tool.py +87 -0
  107. hyperpocket/tool/tests/__init__.py +0 -0
  108. hyperpocket/tool/tests/test_function_tool.py +266 -0
  109. hyperpocket/tool/tool.py +106 -0
  110. hyperpocket/tool/wasm/README.KR.md +144 -0
  111. hyperpocket/tool/wasm/README.md +144 -0
  112. hyperpocket/tool/wasm/__init__.py +3 -0
  113. hyperpocket/tool/wasm/browser.py +63 -0
  114. hyperpocket/tool/wasm/invoker.py +41 -0
  115. hyperpocket/tool/wasm/script.py +82 -0
  116. hyperpocket/tool/wasm/templates/__init__.py +28 -0
  117. hyperpocket/tool/wasm/templates/node.py +87 -0
  118. hyperpocket/tool/wasm/templates/python.py +75 -0
  119. hyperpocket/tool/wasm/tool.py +147 -0
  120. hyperpocket/util/__init__.py +1 -0
  121. hyperpocket/util/extract_func_param_desc_from_docstring.py +97 -0
  122. hyperpocket/util/find_all_leaf_class_in_package.py +17 -0
  123. hyperpocket/util/find_all_subclass_in_package.py +29 -0
  124. hyperpocket/util/flatten_json_schema.py +45 -0
  125. hyperpocket/util/function_to_model.py +46 -0
  126. hyperpocket/util/get_objects_from_subpackage.py +28 -0
  127. hyperpocket/util/json_schema_to_model.py +69 -0
  128. hyperpocket-0.0.1.dist-info/METADATA +304 -0
  129. hyperpocket-0.0.1.dist-info/RECORD +131 -0
  130. hyperpocket-0.0.1.dist-info/WHEEL +4 -0
  131. hyperpocket-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,68 @@
1
+ # Tool
2
+
3
+ ---
4
+
5
+ ## ToolRequest
6
+
7
+ 각 Tool을 초기화할 때 필요한 정보를 담고 있는 인터페이스
8
+
9
+ ## ToolAuth
10
+
11
+ ToolAuth는 Tool을 호출하기 위해 필요한 Authentication 정보를 나타내는 객체
12
+
13
+ 다음과 같은 필드가 존재
14
+
15
+ - auth_provider : tool 호출 시에 어떤 authentication provider의 인증 정보가 필요한지 표시
16
+ - auth_provider가 명시되지 않는 경우, authentication이 필요없는 Tool로 인식된다.
17
+ - auth_handler : tool 호출 시 어떤 authentication handler를 사용할 것인지를 표시
18
+ - auth_handler가 명시되지 않는 경우, authentication provider의 default handler가 사용된다.
19
+ - scopes : tool 호출 시에 어떤 authentication scopes가 필요한지를 표시
20
+ - authentication을 수행하지 않거나, authentication handler가 non-scoped인 경우에는 None값을 사용
21
+
22
+ ## Tool
23
+
24
+ 실제 Tool을 실행하는 인터페이스
25
+
26
+ ```python
27
+ class Tool(BaseModel, abc.ABC):
28
+ name: str = Field(description="tool name")
29
+ description: str = Field(description="tool description")
30
+ argument_json_schema: Optional[dict] = Field(default=None, description="tool argument json schema")
31
+ auth: Optional[ToolAuth] = Field(default=None, description="authentication information to invoke tool")
32
+ ```
33
+
34
+ ### schema_model
35
+
36
+ Tool.schema_model은 Tool이 호출 될 때 인자로 `profile`과 `thread_id`를 받기 위해 기존 Tool의 argument_json_schema을 wrapping한
37
+ model을 반환
38
+
39
+ 이때 기존의 argument_json_schema는 `body` 필드로 이동
40
+
41
+ ## How to implement
42
+
43
+ 1. Tool을 상속한 클래스를 생성
44
+ - `invoke` 또는 `ainvoke` 내에서 툴 호출 시 수행할 작업을 정의
45
+ - Tool을 초기화할 factory method를 정의
46
+ - 이때 위의 필수 필드에 대한 값을 주입
47
+
48
+ 2. `Pocket` 내의 `ToolLike`에 클래스를 추가(Optional)
49
+ - `WasmTool`의 경우 ToolRequest, str을 입력으로 받을 수 있음
50
+ - `FunctionTool`의 경우 Callable을 입력으로 받을 수 있음
51
+
52
+ 3. `Pocket.__init__` 또는 `Pocket._load_tool` 함수 내에서 `ToolLike`값을 기반으로 Tool 초기화 수행
53
+
54
+ ## Invoke Flow
55
+
56
+ 1. `Pocket.invoke`를 통해 최초 Tool calling이 수행된다.
57
+ 2. Tool 호출을 위해 authentication이 필요한 경우 `PocketAuth.invoke`를 통해 authentication을 수행
58
+ 3. authentication이 완료된 후 `PocketAuth`에서 얻은 authentication 정보를 tool 호출 시 같이 전달
59
+
60
+ ```mermaid
61
+ flowchart TD
62
+ Z["Agent"] -->|"Invoke tool"| A["Pocket"]
63
+ A["Pocket"] -->|Requires Authentication?| B{"Yes"}
64
+ B --> D["PocketAuth: Provide Authentication Info"]
65
+ D --> E["Pocket: Invoke Tool with Auth Info"]
66
+ B -->|No| F
67
+ E --> F["Tool: Perform Operations"]
68
+ ```
@@ -0,0 +1,75 @@
1
+ # Tool
2
+
3
+ ---
4
+
5
+ ## ToolRequest
6
+
7
+ The interface that contains information to initiate each tool
8
+
9
+ ## ToolAuth
10
+
11
+ The class that contains authentication information to invoke tool
12
+
13
+ authentication information fields are:
14
+
15
+ - `auth_provider`: Indicates which authentication provider’s credentials are required to invoke the tool.
16
+ - If auth_provider is not specified, the tool is considered to require no authentication.
17
+
18
+ - `auth_handler`: Specifies which authentication handler should be used when invoking the tool.
19
+ - If auth_handler is not specified, the default handler of the authentication provider will be used.
20
+
21
+ - `scopes`: Indicates the authentication scopes required to invoke the tool.
22
+ - If authentication is not performed or the authentication handler is non-scoped, the value should be None.
23
+
24
+ ## Tool
25
+
26
+ The interface to execute tool actually
27
+
28
+ ```python
29
+ class Tool(BaseModel, abc.ABC):
30
+ name: str = Field(description="tool name")
31
+ description: str = Field(description="tool description")
32
+ argument_json_schema: Optional[dict] = Field(default=None, description="tool argument json schema")
33
+ auth: Optional[ToolAuth] = Field(default=None, description="authentication information to invoke tool")
34
+ ```
35
+
36
+ ### schema_model
37
+
38
+ `Tool.schema_model` returns a model that wraps the existing `argument_json_schema` to include `profile` and `thread_id` as
39
+ arguments when the tool is invoked.
40
+
41
+ In this process, the original `argument_json_schema` is moved under the `body` field.
42
+
43
+ ## How to implement
44
+
45
+ 1. Create a class that inherits from Tool
46
+ - Define the tasks to be performed when invoking the tool in invoke or ainvoke.
47
+ - Define a factory method to initialize the tool.(Optional)
48
+ - Inject values for the required fields during initialization.
49
+
50
+ 2. Add the class to `ToolLike` in Pocket (Optional)
51
+ - For `WasmTool`, the input can be a ToolRequest or a str.
52
+ - For `FunctionTool`, the input can be a Callable.
53
+
54
+ 3. Perform tool initialization in `Pocket.__init__` or `Pocket._load_tool`
55
+ - The initialization is based on the provided ToolLike value.
56
+
57
+ ## Invoke Flow
58
+
59
+ 1. The initial tool invocation occurs via `Pocket.invoke`.
60
+ 2. If authentication is required for tool invocation, authentication is performed using `PocketAuth.invoke`.
61
+ 3. After successful authentication, the authentication information obtained from PocketAuth is included when invoking
62
+ the tool.
63
+
64
+ ```mermaid
65
+ flowchart TD
66
+ Z["Agent"] -->|"Invoke tool"| A["Pocket"]
67
+ A["Pocket"] -->|Requires Authentication?| B{"Yes"}
68
+ B --> D["PocketAuth: Provide Authentication Info"]
69
+ D --> E["Pocket: Invoke Tool with Auth Info"]
70
+ B -->|No| F
71
+ E --> F["Tool: Perform Operations"]
72
+ ```
73
+
74
+
75
+
@@ -0,0 +1,13 @@
1
+ from hyperpocket.tool.function import from_func, function_tool
2
+ from hyperpocket.tool.tool import Tool, ToolRequest, ToolAuth
3
+ from hyperpocket.tool.wasm.tool import from_local, from_git
4
+
5
+ __all__ = [
6
+ 'Tool',
7
+ 'ToolAuth',
8
+ 'ToolRequest',
9
+ 'from_local',
10
+ 'from_git',
11
+ "from_func",
12
+ "function_tool"
13
+ ]
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ # from pydantic import BaseModel, Field
2
+ #
3
+ # from pocket.tool.builtin import BuiltinTool
4
+ # from pocket.tool.tool import TAny, TModelGeneric
5
+ #
6
+ #
7
+ # class Schema(BaseModel):
8
+ # a: int = Field(description="first number to add")
9
+ # b: int = Field(description="second number to add")
10
+ #
11
+ #
12
+ # class AddTool(BuiltinTool):
13
+ # name: str = "add_two_number_tool"
14
+ # description: str = "add two numbers"
15
+ # argument_schema: TModelGeneric = Schema
16
+ #
17
+ # def invoke(self, a: int, b: int) -> TAny:
18
+ # return a + b
@@ -0,0 +1,159 @@
1
+ # Function
2
+
3
+ python 함수를 tool로 등록해 사용
4
+
5
+ ---
6
+
7
+ ## How To Use
8
+
9
+ ### No Auth
10
+
11
+ python method를 pocket tool에 그대로 입력
12
+
13
+ ```python
14
+ from hyperpocket import Pocket
15
+
16
+ pocket = Pocket(tools=[
17
+ my_function]
18
+ )
19
+ ```
20
+
21
+ ### Auth
22
+
23
+ python method에 `@function_tool`를 사용해 필요한 authentication provider를 명시
24
+
25
+ ```python
26
+ from hyperpocket import Pocket
27
+ from hyperpocket.auth import AuthProvider
28
+ from hyperpocket.tool import function_tool
29
+
30
+
31
+ @function_tool(
32
+ auth_provider=AuthProvider.SLACK,
33
+ scopes=["channels:history", "im:history", "mpim:history", "groups:history", "reactions:read", "mpim:read",
34
+ "im:read"]
35
+ )
36
+ def my_function():
37
+ pass
38
+
39
+
40
+ pocket = Pocket(
41
+ tools=[
42
+ my_function
43
+ ]
44
+ )
45
+ ```
46
+
47
+ `from_function`을 통해 pocket을 초기화할 때에만 일시적으로 `FunctionTool`로 변환해 넣어줄 수 있다.
48
+
49
+ ```python
50
+ from hyperpocket import Pocket
51
+ from hyperpocket.auth import AuthProvider
52
+ from hyperpocket.tool import from_func
53
+ from hyperpocket.tool.tool import ToolAuth
54
+
55
+ Pocket(tools=[
56
+ from_func(
57
+ func=my_function,
58
+ auth=ToolAuth(
59
+ auth_provider=AuthProvider.SLACK,
60
+ scopes=["channels:history", "im:history", "mpim:history", "groups:history", "reactions:read", "mpim:read",
61
+ "im:read"]
62
+ )
63
+ )
64
+ ])
65
+ ```
66
+
67
+ authentication access token은 python 함수의 variable keyword로 매핑되어 전달된다.
68
+
69
+ ```python
70
+ from hyperpocket.tool import function_tool
71
+ from hyperpocket.auth import AuthProvider
72
+
73
+
74
+ @function_tool(
75
+ auth_provider=AuthProvider.SLACK
76
+ )
77
+ def my_function(**kwargs):
78
+ token = kwargs["SLACK_BOT_TOKEN"]
79
+
80
+ # ...
81
+ ```
82
+
83
+ - 각 provider 별 mapping key값은 각 provider의 `_ACCESS_TOKEN_KEY` 필드를 확인
84
+
85
+ ## Docstring parsing
86
+
87
+ docstring을 parsing해 argument 의미 파악
88
+
89
+ 다음 docstring style을 지원
90
+
91
+ - google style
92
+ - sphinx
93
+ - javadoc
94
+ - plain
95
+
96
+ ### Google Style
97
+
98
+ ```python
99
+ def my_function(a: int, b: int):
100
+ """
101
+ My Function
102
+
103
+ Args:
104
+ a(int): first argument
105
+ b(int): second argument
106
+ """
107
+ pass
108
+ ```
109
+
110
+ ### Sphinx Style
111
+
112
+ ```python
113
+ def my_function(a: int, b: int):
114
+ """
115
+ My Function
116
+
117
+ :param a: first argument
118
+ :param b: second argument
119
+ """
120
+ pass
121
+ ```
122
+
123
+ ## Javadoc Style
124
+
125
+ ```python
126
+ def my_function(a: int, b: int):
127
+ """
128
+ My Function
129
+
130
+ @param a: first argument
131
+ @param b: second argument
132
+ """
133
+ pass
134
+ ```
135
+
136
+ ## Other Style
137
+
138
+ ```python
139
+ def my_function(a: int, b: int):
140
+ """
141
+ My Function
142
+
143
+ @arg a: first argument
144
+ @arg b: second argument
145
+
146
+ or
147
+
148
+ :arg a: first argument
149
+ :arg b: second argument
150
+ """
151
+ pass
152
+ ```
153
+
154
+ 하나의 docstring에서 여러 style이 혼용되는 경우는 고려하지 않음
155
+
156
+ ## Limits
157
+
158
+ - input type은 python builtin type과 pydantic만 지원
159
+
@@ -0,0 +1,169 @@
1
+ # Function
2
+
3
+ Register and use Python functions as tools.
4
+
5
+ ---
6
+
7
+ ## How To Use
8
+
9
+ ### No Authentication Required
10
+
11
+ Directly pass Python methods into the pocket tool.
12
+
13
+ ```python
14
+ from hyperpocket import Pocket
15
+
16
+ pocket = Pocket(tools=[
17
+ my_function
18
+ ])
19
+ ```
20
+
21
+ ### With Authentication
22
+
23
+ Use the `@function_tool` decorator to specify the required authentication provider for a Python method.
24
+
25
+ ```python
26
+ from hyperpocket import Pocket
27
+ from hyperpocket.auth import AuthProvider
28
+ from hyperpocket.tool import function_tool
29
+
30
+
31
+ @function_tool(
32
+ auth_provider=AuthProvider.SLACK,
33
+ scopes=["channels:history", "im:history", "mpim:history", "groups:history", "reactions:read", "mpim:read",
34
+ "im:read"]
35
+ )
36
+ def my_function():
37
+ pass
38
+
39
+
40
+ pocket = Pocket(
41
+ tools=[
42
+ my_function
43
+ ]
44
+ )
45
+ ```
46
+
47
+ You can temporarily convert a function into a FunctionTool when initializing a Pocket instance using `from_func`.
48
+
49
+ ```python
50
+ from hyperpocket import Pocket
51
+ from hyperpocket.auth import AuthProvider
52
+ from hyperpocket.tool import from_func
53
+ from hyperpocket.tool.tool import ToolAuth
54
+
55
+ Pocket(tools=[
56
+ from_func(
57
+ func=my_function,
58
+ auth=ToolAuth(
59
+ auth_provider=AuthProvider.SLACK,
60
+ scopes=["channels:history", "im:history", "mpim:history", "groups:history", "reactions:read", "mpim:read",
61
+ "im:read"]
62
+ )
63
+ )
64
+ ])
65
+ ```
66
+
67
+ Authentication access tokens are passed to the Python function as __variable keyword__ arguments.
68
+
69
+ ```python
70
+ from hyperpocket.tool import function_tool
71
+ from hyperpocket.auth import AuthProvider
72
+
73
+
74
+ @function_tool(
75
+ auth_provider=AuthProvider.SLACK
76
+ )
77
+ def my_function(**kwargs):
78
+ token = kwargs["SLACK_BOT_TOKEN"]
79
+
80
+ # ...
81
+ ```
82
+
83
+ - Check the `_ACCESS_TOKEN_KEY` field of each provider for the mapping key of their access tokens.
84
+
85
+ ## Docstring Parsing
86
+
87
+ Parse docstrings to understand the meanings of arguments.
88
+
89
+ The following docstring styles are supported:
90
+
91
+ - Google Style
92
+ - Sphinx
93
+ - Javadoc
94
+ - Plain
95
+
96
+ ### Google Style
97
+
98
+ ```python
99
+ def my_function(a: int, b: int):
100
+ """
101
+ My Function
102
+
103
+ Args:
104
+ a (int): First argument
105
+ b (int): Second argument
106
+ """
107
+ pass
108
+ ```
109
+
110
+ ### Sphinx Style
111
+
112
+ ```python
113
+ def my_function(a: int, b: int):
114
+ """
115
+ My Function
116
+
117
+ :param a: First argument
118
+ :param b: Second argument
119
+ """
120
+ pass
121
+ ```
122
+
123
+ ### Javadoc Style
124
+
125
+ ```python
126
+ def my_function(a: int, b: int):
127
+ """
128
+ My Function
129
+
130
+ @param a: First argument
131
+ @param b: Second argument
132
+ """
133
+ pass
134
+ ```
135
+
136
+ ### Other Style
137
+
138
+ ```python
139
+ def my_function(a: int, b: int):
140
+ """
141
+ My Function
142
+
143
+ @arg a: First argument
144
+ @arg b: Second argument
145
+
146
+ or
147
+
148
+ :arg a: First argument
149
+ :arg b: Second argument
150
+ """
151
+ pass
152
+ ```
153
+
154
+ ### Plain
155
+
156
+ ```python
157
+ def my_function(a: int, b: int):
158
+ """
159
+ My Function
160
+
161
+ a(int): First argument
162
+ b(int): Second argument
163
+ """
164
+ pass
165
+ ```
166
+
167
+ ## Limitations
168
+
169
+ Input types are limited to Python built-in types and Pydantic.
@@ -0,0 +1,9 @@
1
+ from hyperpocket.tool.function.annotation import function_tool
2
+ from hyperpocket.tool.function.tool import FunctionTool
3
+
4
+ from_func = FunctionTool.from_func
5
+
6
+ __all__ = [
7
+ "from_func",
8
+ "function_tool"
9
+ ]
@@ -0,0 +1,30 @@
1
+ from typing import List, Callable, Optional
2
+
3
+ from hyperpocket.auth import AuthProvider
4
+ from hyperpocket.tool.function.tool import FunctionTool
5
+ from hyperpocket.tool.tool import ToolAuth
6
+
7
+
8
+ def function_tool(func: Optional[Callable] = None, *, auth_provider: AuthProvider = None, scopes: List[str] = None,
9
+ auth_handler: str = None):
10
+ def decorator(inner_func: Callable):
11
+ if not callable(inner_func):
12
+ raise ValueError("FunctionTool can only be created from a callable")
13
+ auth = None
14
+ if auth_provider is not None:
15
+ auth = ToolAuth(
16
+ auth_provider=auth_provider,
17
+ scopes=scopes if scopes else [],
18
+ auth_handler=auth_handler
19
+ )
20
+
21
+ return FunctionTool.from_func(
22
+ func=inner_func,
23
+ auth=auth,
24
+ )
25
+
26
+ if func is not None:
27
+ return decorator(func)
28
+
29
+ # return FunctionTool
30
+ return decorator
@@ -0,0 +1,87 @@
1
+ import copy
2
+ import inspect
3
+ from typing import Callable, Awaitable, Optional
4
+
5
+ from pydantic import BaseModel
6
+
7
+ from hyperpocket.tool.tool import Tool, ToolAuth
8
+ from hyperpocket.util.flatten_json_schema import flatten_json_schema
9
+ from hyperpocket.util.function_to_model import function_to_model
10
+
11
+
12
+ class FunctionTool(Tool):
13
+ """
14
+ FunctionTool is Tool executing local python method.
15
+ """
16
+ func: Callable
17
+ afunc: Optional[Callable[..., Awaitable[str]]]
18
+
19
+ def invoke(self, **kwargs) -> str:
20
+ binding_args = self._get_binding_args(kwargs)
21
+ return str(self.func(**binding_args))
22
+
23
+ async def ainvoke(self, **kwargs) -> str:
24
+ binding_args = self._get_binding_args(kwargs)
25
+ if self.afunc is None:
26
+ return str(self.func(**binding_args))
27
+ return str(await self.afunc(**binding_args))
28
+
29
+ def _get_binding_args(self, kwargs):
30
+ _kwargs = copy.deepcopy(kwargs)
31
+
32
+ # make body args to model
33
+ schema_model = self.schema_model()
34
+ model = schema_model(body=_kwargs["body"])
35
+ _kwargs.pop("body")
36
+
37
+ # body model to dict
38
+ args = self.model_to_kwargs(model.body)
39
+
40
+ # binding args
41
+ binding_args = {}
42
+ sig = inspect.signature(self.func)
43
+ for param_name, param in sig.parameters.items():
44
+ if param_name not in args:
45
+ continue
46
+
47
+ if param.kind == param.VAR_KEYWORD:
48
+ # var keyword args should be passed by plain dict
49
+ binding_args |= args[param_name]
50
+ binding_args |= _kwargs.get("envs", {})
51
+
52
+ if "envs" in _kwargs:
53
+ _kwargs.pop("envs")
54
+
55
+ binding_args |= _kwargs # add other kwargs
56
+ continue
57
+
58
+ binding_args[param_name] = args[param_name]
59
+
60
+ return binding_args
61
+
62
+ @staticmethod
63
+ def model_to_kwargs(model: BaseModel) -> dict:
64
+ kwargs = {}
65
+ for field, value in model.model_fields.items():
66
+ attr_value = getattr(model, field)
67
+ kwargs[field] = attr_value
68
+ return kwargs
69
+
70
+ @classmethod
71
+ def from_func(
72
+ cls,
73
+ func: Callable,
74
+ afunc: Callable[..., Awaitable[str]] = None,
75
+ auth: Optional[ToolAuth] = None
76
+ ) -> "FunctionTool":
77
+ model = function_to_model(func)
78
+ argument_json_schema = flatten_json_schema(model.model_json_schema())
79
+
80
+ return cls(
81
+ func=func,
82
+ afunc=afunc,
83
+ name=func.__name__,
84
+ description=model.__doc__,
85
+ argument_json_schema=argument_json_schema,
86
+ auth=auth
87
+ )
File without changes