hyperpocket 0.0.2__py3-none-any.whl → 0.1.8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. hyperpocket/auth/README.md +3 -3
  2. hyperpocket/auth/__init__.py +0 -8
  3. hyperpocket/auth/gumloop/context.py +13 -0
  4. hyperpocket/auth/gumloop/token_context.py +15 -0
  5. hyperpocket/auth/gumloop/token_handler.py +66 -0
  6. hyperpocket/auth/gumloop/token_schema.py +8 -0
  7. hyperpocket/auth/linear/token_context.py +1 -1
  8. hyperpocket/auth/notion/README.md +28 -0
  9. hyperpocket/auth/notion/context.py +15 -0
  10. hyperpocket/auth/notion/token_context.py +14 -0
  11. hyperpocket/auth/notion/token_handler.py +65 -0
  12. hyperpocket/auth/notion/token_schema.py +10 -0
  13. hyperpocket/auth/provider.py +8 -5
  14. hyperpocket/auth/reddit/context.py +15 -0
  15. hyperpocket/auth/reddit/oauth2_context.py +32 -0
  16. hyperpocket/auth/reddit/oauth2_handler.py +151 -0
  17. hyperpocket/auth/reddit/oauth2_schema.py +18 -0
  18. hyperpocket/auth/slack/token_context.py +1 -1
  19. hyperpocket/builtin.py +63 -0
  20. hyperpocket/cli/__main__.py +12 -0
  21. hyperpocket/cli/auth.py +83 -0
  22. hyperpocket/cli/codegen/auth/__init__.py +13 -0
  23. hyperpocket/cli/codegen/auth/auth_context_template.py +16 -0
  24. hyperpocket/cli/codegen/auth/auth_token_context_template.py +16 -0
  25. hyperpocket/cli/codegen/auth/auth_token_handler_template.py +69 -0
  26. hyperpocket/cli/codegen/auth/auth_token_schema_template.py +12 -0
  27. hyperpocket/cli/codegen/auth/server_auth_template.py +18 -0
  28. hyperpocket/cli/eject.py +19 -0
  29. hyperpocket/cli/sync.py +5 -5
  30. hyperpocket/config/settings.py +2 -4
  31. hyperpocket/futures/futurestore.py +0 -1
  32. hyperpocket/pocket_auth.py +25 -5
  33. hyperpocket/pocket_core.py +262 -0
  34. hyperpocket/pocket_main.py +125 -171
  35. hyperpocket/prompts.py +6 -8
  36. hyperpocket/repository/__init__.py +2 -2
  37. hyperpocket/repository/lock.py +19 -0
  38. hyperpocket/repository/lockfile.py +19 -13
  39. hyperpocket/repository/repository.py +26 -1
  40. hyperpocket/server/auth/__init__.py +0 -6
  41. hyperpocket/server/auth/gumloop.py +16 -0
  42. hyperpocket/server/auth/notion.py +19 -0
  43. hyperpocket/server/auth/reddit.py +16 -0
  44. hyperpocket/server/server.py +52 -16
  45. hyperpocket/server/tool/dto/script.py +15 -2
  46. hyperpocket/server/tool/wasm.py +20 -8
  47. hyperpocket/session/README.md +2 -2
  48. hyperpocket/session/in_memory.py +18 -5
  49. hyperpocket/session/interface.py +14 -0
  50. hyperpocket/session/redis.py +29 -5
  51. hyperpocket/tool/README.md +16 -12
  52. hyperpocket/tool/__init__.py +4 -3
  53. hyperpocket/tool/function/README.md +39 -10
  54. hyperpocket/tool/function/__init__.py +2 -0
  55. hyperpocket/tool/function/annotation.py +2 -1
  56. hyperpocket/tool/function/tool.py +98 -13
  57. hyperpocket/tool/tests/test_function_tool.py +55 -0
  58. hyperpocket/tool/tests/test_wasm_tool.py +73 -0
  59. hyperpocket/tool/tool.py +65 -2
  60. hyperpocket/tool/wasm/README.md +27 -5
  61. hyperpocket/tool/wasm/script.py +40 -1
  62. hyperpocket/tool/wasm/templates/python.py +32 -14
  63. hyperpocket/tool/wasm/tool.py +21 -18
  64. hyperpocket/tool_like.py +5 -0
  65. hyperpocket/util/__init__.py +1 -1
  66. hyperpocket/util/extract_func_param_desc_from_docstring.py +4 -4
  67. hyperpocket/util/function_to_model.py +5 -2
  68. hyperpocket/util/json_schema_to_model.py +45 -26
  69. {hyperpocket-0.0.2.dist-info → hyperpocket-0.1.8.dist-info}/METADATA +101 -72
  70. hyperpocket-0.1.8.dist-info/RECORD +139 -0
  71. {hyperpocket-0.0.2.dist-info → hyperpocket-0.1.8.dist-info}/WHEEL +1 -1
  72. hyperpocket-0.1.8.dist-info/entry_points.txt +2 -0
  73. hyperpocket/auth/README.KR.md +0 -309
  74. hyperpocket/auth/slack/tests/test_oauth2_handler.py +0 -32
  75. hyperpocket/auth/slack/tests/test_token_handler.py +0 -23
  76. hyperpocket/auth/tests/test_google_oauth2_handler.py +0 -147
  77. hyperpocket/auth/tests/test_slack_oauth2_handler.py +0 -147
  78. hyperpocket/auth/tests/test_slack_token_handler.py +0 -66
  79. hyperpocket/external/__init__.py +0 -7
  80. hyperpocket/external/github_client.py +0 -19
  81. hyperpocket/session/README.KR.md +0 -62
  82. hyperpocket/session/tests/test_in_memory.py +0 -145
  83. hyperpocket/session/tests/test_redis.py +0 -151
  84. hyperpocket/tests/test_pocket.py +0 -116
  85. hyperpocket/tests/test_pocket_auth.py +0 -982
  86. hyperpocket/tool/README.KR.md +0 -68
  87. hyperpocket/tool/builtins/__init__.py +0 -0
  88. hyperpocket/tool/builtins/example/__init__.py +0 -0
  89. hyperpocket/tool/builtins/example/add_tool.py +0 -18
  90. hyperpocket/tool/function/README.KR.md +0 -159
  91. hyperpocket/tool/wasm/README.KR.md +0 -144
  92. hyperpocket-0.0.2.dist-info/RECORD +0 -130
  93. hyperpocket-0.0.2.dist-info/entry_points.txt +0 -3
  94. /hyperpocket/auth/{slack/tests → gumloop}/__init__.py +0 -0
  95. /hyperpocket/auth/{tests → notion}/__init__.py +0 -0
  96. /hyperpocket/{session/tests → auth/reddit}/__init__.py +0 -0
  97. /hyperpocket/{tests → cli/codegen}/__init__.py +0 -0
@@ -1,66 +0,0 @@
1
- from unittest.async_case import IsolatedAsyncioTestCase
2
- from urllib.parse import urlparse, parse_qs
3
-
4
- from hyperpocket.auth import SlackTokenAuthContext
5
- from hyperpocket.auth.slack.token_handler import SlackTokenAuthHandler
6
- from hyperpocket.auth.slack.token_schema import SlackTokenRequest
7
- from hyperpocket.futures import FutureStore
8
-
9
-
10
- class TestSlackTokenAuthHandler(IsolatedAsyncioTestCase):
11
-
12
- async def asyncSetUp(self):
13
- self.handler: SlackTokenAuthHandler = SlackTokenAuthHandler()
14
- self.auth_req = SlackTokenRequest()
15
-
16
- async def test_make_auth_url(self):
17
- auth_url = self.handler._make_auth_url(
18
- req=self.auth_req,
19
- redirect_uri="http://test-redirect-uri.com",
20
- state="test-future-id"
21
- )
22
- parsed = urlparse(auth_url)
23
- query_params = parse_qs(parsed.query)
24
- base_url = f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
25
-
26
- # then
27
- self.assertEqual(base_url, self.handler._TOKEN_URL)
28
- self.assertEqual(query_params["state"][0], "test-future-id")
29
- self.assertEqual(query_params["redirect_uri"][0], "http://test-redirect-uri.com")
30
-
31
- async def test_prepare(self):
32
- # when
33
- prepare: str = self.handler.prepare(
34
- auth_req=self.auth_req,
35
- thread_id="test-prepare-thread-id",
36
- profile="test-prepare-profile",
37
- future_uid="test-prepare-future-uid",
38
- )
39
- auth_url = prepare.removeprefix("User needs to authenticate using the following URL:").strip()
40
- future_data = FutureStore.get_future( uid="test-prepare-future-uid")
41
-
42
- # then
43
- self.assertTrue(auth_url.startswith(self.handler._TOKEN_URL))
44
- self.assertIsNotNone(future_data)
45
- self.assertEqual(future_data.data["thread_id"], "test-prepare-thread-id")
46
- self.assertEqual(future_data.data["profile"], "test-prepare-profile")
47
- self.assertFalse(future_data.future.done())
48
-
49
- async def test_authenticate(self):
50
- self.handler.prepare(
51
- auth_req=self.auth_req,
52
- thread_id="test-thread-id",
53
- profile="test-profile",
54
- future_uid="test-future-uid"
55
- )
56
- future_data = FutureStore.get_future( uid="test-future-uid")
57
- future_data.future.set_result("test-token")
58
-
59
- response: SlackTokenAuthContext = await self.handler.authenticate(
60
- auth_req=self.auth_req,
61
- future_uid="test-future-uid"
62
- )
63
-
64
- self.assertIsInstance(response, SlackTokenAuthContext)
65
- self.assertEqual(response.access_token, "test-token")
66
- self.assertIsNone(response.expires_at)
@@ -1,7 +0,0 @@
1
- from hyperpocket.external.github_client import github_instance
2
-
3
- github = github_instance()
4
-
5
- __all__ = [
6
- "github",
7
- ]
@@ -1,19 +0,0 @@
1
- from github import Auth, Github, GithubIntegration
2
-
3
- from hyperpocket.config import config
4
-
5
- _github = None
6
-
7
-
8
- def github_instance() -> Github:
9
- global _github
10
- if _github is None:
11
- if config.git.github.github_token:
12
- _github = Github(auth=Auth.Token(config.git.github.github_token))
13
- elif config.git.github.app_id:
14
- auth = Auth.AppAuth(config.git.github.app_id, config.git.github.app_private_key)
15
- gi = GithubIntegration(auth=auth)
16
- _github = gi.get_github_for_installation(config.git.github.app_installation_id)
17
- else:
18
- _github = Github()
19
- return _github
@@ -1,62 +0,0 @@
1
- # Session Storage
2
-
3
- 유저의 authentication(auth) session을 저장하기 위한 storage
4
-
5
- ## Current supported session storage
6
-
7
- - [x] InMemory
8
- - [x] Redis
9
- - [ ] Postgres
10
- - [ ] Mysql
11
- - [ ] Mongodb
12
-
13
- ## SessionKey
14
-
15
- 세션 키는 유저의 인증 정보를 식별하기 위한 유니크 키이다.
16
-
17
- 일반적으로 세션 키는 다음 세 가지 요소로 식별될 수 있다.
18
-
19
- - auth provider
20
- - profile
21
- - thread_id
22
-
23
- 하나의 auth provider에서는 하나의 session만 가질 수 있다.
24
-
25
- - 예를 들어 slack token으로 이미 인증한 사용자가 oauth로 인증하려 하면 이전 세션은 사라지게 된다.
26
-
27
- - profile은 pocket에서 지원하는 개념으로 하나의 thread_id에 여러 profile이 존재할 수 있다.
28
-
29
- - profile을 이용해 한 사용자는 여러 persona를 갖고 작업을 수행하도록 할 수 있다.
30
- - e.g., A group의 슬랙 메세지를 읽어 B group으로 요약해서 전달
31
-
32
- ## BaseSessionValue
33
-
34
- ```python
35
- class BaseSessionValue(BaseModel):
36
- auth_provider_name: str
37
- auth_context: Optional[AuthContext] = None
38
- scoped: bool
39
- auth_scopes: Optional[Set[str]] = None
40
- auth_resolve_uid: Optional[str] = None
41
- ```
42
-
43
- 기본적으로 Session에는 다음 정보들을 갖고 있다.
44
-
45
- - auth_provider_name : 현재 세션을 인증한 auth provider name
46
- - auth_context : 실제 세션 내용이 들어있는 auth context
47
- - scoped : 현재 세션이 scoped session인지 여부
48
- - auth_scopes : 현재 세션의 auth scopes. scoped session의 경우에만 존재
49
- - auth_resolve_uid : 유저가 auth 인증을 완료했는지를 비동기적으로 확인하기 위한 uid
50
-
51
- ## SessionStorageInterface
52
-
53
- TBU
54
-
55
- ## How To Implement
56
-
57
- 1. `pocket/config/session.py` 내에 새로운 SessionType Enum 추가
58
- 2. `pocket/config/session.py` 내에 새로운 SessionConfig 추가
59
- 3. SessionStorageInterface 구현
60
- - session storage가 초기화될 때 위에서 정의한 SessionConfig를 입력으로 받아야 한다.
61
-
62
-
@@ -1,145 +0,0 @@
1
- import unittest
2
-
3
- from hyperpocket.auth import AuthProvider, SlackTokenAuthContext
4
- from hyperpocket.config.session import SessionConfigInMemory
5
- from hyperpocket.session.in_memory import InMemorySessionStorage, InMemorySessionValue
6
-
7
-
8
- class TestInMemorySessionStorage(unittest.TestCase):
9
- storage: InMemorySessionStorage
10
- context: SlackTokenAuthContext
11
-
12
- def setUp(self):
13
- self.storage = InMemorySessionStorage(SessionConfigInMemory())
14
- self.auth_context = SlackTokenAuthContext(
15
- access_token="test",
16
- description="test-description",
17
- expires_at=None,
18
- detail=None,
19
- )
20
-
21
- def tearDown(self):
22
- del self.storage
23
- del self.auth_context
24
-
25
- def test_make_session_key(self):
26
- key = self.storage._make_session_key(
27
- auth_provider=AuthProvider.SLACK,
28
- thread_id="default_thread_id",
29
- profile="default_profile"
30
- )
31
-
32
- self.assertEqual(key, "SLACK__default_thread_id__default_profile")
33
-
34
- def test_make_session(self):
35
- session = self.storage._make_session(
36
- auth_provider_name=AuthProvider.SLACK.name,
37
- auth_scopes=["scope1", "scope2"],
38
- auth_context=self.auth_context,
39
- auth_resolve_uid="test-resolve-uid",
40
- is_auth_scope_universal=True
41
- )
42
-
43
- # then
44
- self.assertIsInstance(session, InMemorySessionValue)
45
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
46
- self.assertEqual(session.auth_context.access_token, "test")
47
- self.assertEqual(session.auth_context.description, "test-description")
48
-
49
- def test_set(self):
50
- session = self.storage.set(
51
- auth_provider=AuthProvider.SLACK,
52
- thread_id="default_thread_id",
53
- profile="default_profile",
54
- auth_scopes=["scope1", "scope2"],
55
- auth_resolve_uid="test-resolve-uid",
56
- auth_context=self.auth_context,
57
- is_auth_scope_universal=True
58
- )
59
-
60
- self.assertIsInstance(session, InMemorySessionValue)
61
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
62
- self.assertEqual(session.auth_context.access_token, self.auth_context.access_token)
63
- self.assertEqual(session.auth_context.description, self.auth_context.description)
64
-
65
- def test_get_existing_data(self):
66
- # given
67
- self.storage.set(
68
- auth_provider=AuthProvider.SLACK,
69
- thread_id="default_thread_id",
70
- profile="default_profile",
71
- auth_scopes=["scope1", "scope2"],
72
- auth_resolve_uid="test-resolve-uid",
73
- auth_context=self.auth_context,
74
- is_auth_scope_universal=True
75
- )
76
-
77
- # when
78
- session = self.storage.get(
79
- auth_provider=AuthProvider.SLACK,
80
- thread_id="default_thread_id",
81
- profile="default_profile",
82
- )
83
-
84
- # then
85
- self.assertIsInstance(session, InMemorySessionValue)
86
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
87
- self.assertEqual(session.auth_context.access_token, "test")
88
- self.assertEqual(session.auth_context.description, "test-description")
89
-
90
- def test_get_not_existing_data(self):
91
- # when
92
- session = self.storage.get(
93
- auth_provider=AuthProvider.SLACK,
94
- thread_id="default_thread_id",
95
- profile="default_profile",
96
- )
97
-
98
- # then
99
- self.assertIsNone(session)
100
-
101
- def test_delete_existing_data(self):
102
- # given
103
- self.storage.set(
104
- auth_provider=AuthProvider.SLACK,
105
- thread_id="default_thread_id",
106
- profile="default_profile",
107
- auth_scopes=["scope1", "scope2"],
108
- auth_resolve_uid="test-resolve-uid",
109
- auth_context=self.auth_context,
110
- is_auth_scope_universal=True
111
- )
112
-
113
- # when
114
- before_session = self.storage.get(
115
- auth_provider=AuthProvider.SLACK,
116
- thread_id="default_thread_id",
117
- profile="default_profile",
118
- )
119
-
120
- deleted = self.storage.delete(
121
- auth_provider=AuthProvider.SLACK,
122
- thread_id="default_thread_id",
123
- profile="default_profile",
124
- )
125
-
126
- after_session = self.storage.get(
127
- auth_provider=AuthProvider.SLACK,
128
- thread_id="default_thread_id",
129
- profile="default_profile",
130
- )
131
-
132
- # then
133
- self.assertTrue(deleted)
134
- self.assertIsNotNone(before_session)
135
- self.assertIsNone(after_session)
136
-
137
- def test_delete_not_existing_data(self):
138
- deleted = self.storage.delete(
139
- auth_provider=AuthProvider.SLACK,
140
- thread_id="default_thread_id",
141
- profile="default_profile",
142
- )
143
-
144
- # then
145
- self.assertFalse(deleted)
@@ -1,151 +0,0 @@
1
- import unittest
2
-
3
- from hyperpocket.auth import AuthProvider, SlackTokenAuthContext
4
- from hyperpocket.config.session import SessionConfigRedis
5
- from hyperpocket.session.in_memory import InMemorySessionValue
6
- from hyperpocket.session.redis import RedisSessionStorage, RedisSessionValue
7
-
8
-
9
- class TestRedisSessionStorage(unittest.TestCase):
10
- storage: RedisSessionStorage
11
- context: SlackTokenAuthContext
12
-
13
- def setUp(self):
14
- self.storage = RedisSessionStorage(SessionConfigRedis(
15
- host="localhost",
16
- port=6379,
17
- db="9"
18
- ))
19
- self.storage.client.flushdb()
20
-
21
- self.auth_context = SlackTokenAuthContext(
22
- access_token="test",
23
- description="test-description",
24
- expires_at=None,
25
- detail=None,
26
- )
27
-
28
- def tearDown(self):
29
- self.storage.client.flushdb()
30
-
31
- def test_make_session_key(self):
32
- key = self.storage._make_session_key(
33
- auth_provider=AuthProvider.SLACK,
34
- thread_id="default_thread_id",
35
- profile="default_profile"
36
- )
37
-
38
- self.assertEqual(key, "SLACK__default_thread_id__default_profile")
39
-
40
- def test_make_session(self):
41
- session = self.storage._make_session(
42
- auth_provider_name=AuthProvider.SLACK.name,
43
- auth_scopes=["scope1", "scope2"],
44
- auth_context=self.auth_context,
45
- auth_resolve_uid="test-resolve-uid",
46
- is_auth_scope_universal=True
47
- )
48
-
49
- # then
50
- self.assertIsInstance(session, RedisSessionValue)
51
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
52
- self.assertEqual(session.auth_context.access_token, "test")
53
- self.assertEqual(session.auth_context.description, "test-description")
54
-
55
- def test_set(self):
56
- session = self.storage.set(
57
- auth_provider=AuthProvider.SLACK,
58
- thread_id="default_thread_id",
59
- profile="default_profile",
60
- auth_scopes=["scope1", "scope2"],
61
- auth_resolve_uid="test-resolve-uid",
62
- auth_context=self.auth_context,
63
- is_auth_scope_universal=True
64
- )
65
-
66
- self.assertIsInstance(session, InMemorySessionValue)
67
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
68
- self.assertEqual(session.auth_context.access_token, self.auth_context.access_token)
69
- self.assertEqual(session.auth_context.description, self.auth_context.description)
70
-
71
- def test_get_existing_data(self):
72
- # given
73
- self.storage.set(
74
- auth_provider=AuthProvider.SLACK,
75
- thread_id="default_thread_id",
76
- profile="default_profile",
77
- auth_scopes=["scope1", "scope2"],
78
- auth_resolve_uid="test-resolve-uid",
79
- auth_context=self.auth_context,
80
- is_auth_scope_universal=True
81
- )
82
-
83
- # when
84
- session = self.storage.get(
85
- auth_provider=AuthProvider.SLACK,
86
- thread_id="default_thread_id",
87
- profile="default_profile",
88
- )
89
-
90
- # then
91
- self.assertIsInstance(session, InMemorySessionValue)
92
- self.assertEqual(session.auth_provider_name, AuthProvider.SLACK.name)
93
- self.assertEqual(session.auth_context.access_token, "test")
94
- self.assertEqual(session.auth_context.description, "test-description")
95
-
96
- def test_get_not_existing_data(self):
97
- # when
98
- session = self.storage.get(
99
- auth_provider=AuthProvider.SLACK,
100
- thread_id="default_thread_id",
101
- profile="default_profile",
102
- )
103
-
104
- # then
105
- self.assertIsNone(session)
106
-
107
- def test_delete_existing_data(self):
108
- # given
109
- self.storage.set(
110
- auth_provider=AuthProvider.SLACK,
111
- thread_id="default_thread_id",
112
- profile="default_profile",
113
- auth_scopes=["scope1", "scope2"],
114
- auth_resolve_uid="test-resolve-uid",
115
- auth_context=self.auth_context,
116
- is_auth_scope_universal=True
117
- )
118
-
119
- # when
120
- before_session = self.storage.get(
121
- auth_provider=AuthProvider.SLACK,
122
- thread_id="default_thread_id",
123
- profile="default_profile",
124
- )
125
-
126
- deleted = self.storage.delete(
127
- auth_provider=AuthProvider.SLACK,
128
- thread_id="default_thread_id",
129
- profile="default_profile",
130
- )
131
-
132
- after_session = self.storage.get(
133
- auth_provider=AuthProvider.SLACK,
134
- thread_id="default_thread_id",
135
- profile="default_profile",
136
- )
137
-
138
- # then
139
- self.assertTrue(deleted)
140
- self.assertIsNotNone(before_session)
141
- self.assertIsNone(after_session)
142
-
143
- def test_delete_not_existing_data(self):
144
- deleted = self.storage.delete(
145
- auth_provider=AuthProvider.SLACK,
146
- thread_id="default_thread_id",
147
- profile="default_profile",
148
- )
149
-
150
- # then
151
- self.assertFalse(deleted)
@@ -1,116 +0,0 @@
1
- from pathlib import Path
2
- from unittest.async_case import IsolatedAsyncioTestCase
3
-
4
- from pydantic import BaseModel
5
-
6
- from hyperpocket import Pocket
7
- from hyperpocket.config import config
8
- from hyperpocket.tool import from_local, from_git
9
-
10
-
11
- class TestPocket(IsolatedAsyncioTestCase):
12
-
13
- async def asyncSetUp(self):
14
- self.profile = "test-profile"
15
- self.thread_id = "test_thread_id"
16
-
17
- config.public_server_port = "https"
18
- config.public_hostname = "localhost"
19
- config.public_server_port = 8001
20
- config.internal_server_port = 8000
21
- config.enable_local_callback_proxy = True
22
-
23
- self.pocket = Pocket(
24
- tools=[
25
- from_git("https://github.com/vessl-ai/hyperawesometools", "main", "managed-tools/simple-echo-tool"),
26
- self.add,
27
- self.add_pydantic_args
28
- ],
29
- )
30
-
31
- async def test_function_tool(self):
32
- # given
33
- tool_name = "add"
34
-
35
- # when
36
- result = await self.pocket.ainvoke(
37
- tool_name=tool_name,
38
- body={
39
- "a": 1,
40
- "b": 3
41
- },
42
- thread_id=self.thread_id,
43
- profile=self.profile,
44
- )
45
-
46
- # then
47
- self.assertEqual(result, "4")
48
-
49
- async def test_pydantic_arg_function_tool(self):
50
- # given
51
- tool_name = "add_pydantic_args"
52
-
53
- # when
54
- result = await self.pocket.ainvoke(
55
- tool_name=tool_name,
56
- body={
57
- "a": {
58
- "first": 1
59
- },
60
- "b": {
61
- "second": 3
62
- }
63
- },
64
- thread_id=self.thread_id,
65
- profile=self.profile,
66
- )
67
-
68
- # then
69
- self.assertEqual(result, "4")
70
-
71
- async def test_wasm_tool(self):
72
- # given
73
- tool_name = "simple_echo_text"
74
-
75
- # when
76
- result = await self.pocket.ainvoke(
77
- tool_name=tool_name,
78
- body={
79
- "text": "test"
80
- },
81
- thread_id=self.thread_id,
82
- profile=self.profile,
83
- )
84
-
85
- # then
86
- self.assertTrue(result.startswith("echo message : test"))
87
-
88
- @staticmethod
89
- def add(a: int, b: int) -> int:
90
- """
91
- Add two numbers
92
-
93
- Args:
94
- a(int): first number
95
- b(int): second number
96
-
97
- """
98
-
99
- return a + b
100
-
101
- class FirstNumber(BaseModel):
102
- first: int
103
-
104
- class SecondNumber(BaseModel):
105
- second: int
106
-
107
- @staticmethod
108
- def add_pydantic_args(a: FirstNumber, b: SecondNumber):
109
- """
110
- Add two numbers
111
-
112
- Args:
113
- a(FirstNumber): first number
114
- b(SecondNumber): second number
115
- """
116
- return a.first + b.second