gohumanloop 0.0.2__py3-none-any.whl → 0.0.3__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.
- gohumanloop/adapters/langgraph_adapter.py +39 -41
- gohumanloop/core/interface.py +342 -21
- gohumanloop/core/manager.py +302 -39
- gohumanloop/manager/ghl_manager.py +22 -22
- gohumanloop/providers/api_provider.py +18 -18
- gohumanloop/providers/base.py +239 -9
- gohumanloop/providers/email_provider.py +15 -15
- gohumanloop/providers/terminal_provider.py +12 -13
- gohumanloop/utils/utils.py +30 -3
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/METADATA +1 -1
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/RECORD +15 -15
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/WHEEL +1 -1
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/entry_points.txt +0 -0
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/licenses/LICENSE +0 -0
- {gohumanloop-0.0.2.dist-info → gohumanloop-0.0.3.dist-info}/top_level.txt +0 -0
@@ -132,7 +132,7 @@ class EmailProvider(BaseProvider):
|
|
132
132
|
"powered_by": "Powered by GoHumanLoop"
|
133
133
|
}
|
134
134
|
|
135
|
-
async def
|
135
|
+
async def _async_send_email(
|
136
136
|
self,
|
137
137
|
to_email: str,
|
138
138
|
subject: str,
|
@@ -195,7 +195,7 @@ class EmailProvider(BaseProvider):
|
|
195
195
|
logger.exception(f"Unknown error occurred while sending email: {str(e)}")
|
196
196
|
raise
|
197
197
|
|
198
|
-
async def
|
198
|
+
async def _async_check_emails(self, conversation_id: str, request_id: str, recipient_email: str, subject: str):
|
199
199
|
"""Check email replies
|
200
200
|
|
201
201
|
Args:
|
@@ -603,7 +603,7 @@ class EmailProvider(BaseProvider):
|
|
603
603
|
|
604
604
|
return text_body, "\n".join(html_body)
|
605
605
|
|
606
|
-
async def
|
606
|
+
async def async_request_humanloop(
|
607
607
|
self,
|
608
608
|
task_id: str,
|
609
609
|
conversation_id: str,
|
@@ -678,7 +678,7 @@ class EmailProvider(BaseProvider):
|
|
678
678
|
|
679
679
|
|
680
680
|
# 发送邮件
|
681
|
-
success = await self.
|
681
|
+
success = await self._async_send_email(
|
682
682
|
to_email=recipient_email,
|
683
683
|
subject=subject,
|
684
684
|
body=body,
|
@@ -701,13 +701,13 @@ class EmailProvider(BaseProvider):
|
|
701
701
|
|
702
702
|
# 创建邮件检查任务
|
703
703
|
check_task = asyncio.create_task(
|
704
|
-
self.
|
704
|
+
self._async_check_emails(conversation_id, request_id, recipient_email, subject)
|
705
705
|
)
|
706
706
|
self._mail_check_tasks[(conversation_id, request_id)] = check_task
|
707
707
|
|
708
708
|
# 如果设置了超时,创建超时任务
|
709
709
|
if timeout:
|
710
|
-
self.
|
710
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
711
711
|
|
712
712
|
return HumanLoopResult(
|
713
713
|
conversation_id=conversation_id,
|
@@ -716,7 +716,7 @@ class EmailProvider(BaseProvider):
|
|
716
716
|
status=HumanLoopStatus.PENDING
|
717
717
|
)
|
718
718
|
|
719
|
-
async def
|
719
|
+
async def async_check_request_status(
|
720
720
|
self,
|
721
721
|
conversation_id: str,
|
722
722
|
request_id: str
|
@@ -755,7 +755,7 @@ class EmailProvider(BaseProvider):
|
|
755
755
|
|
756
756
|
return result
|
757
757
|
|
758
|
-
async def
|
758
|
+
async def async_continue_humanloop(
|
759
759
|
self,
|
760
760
|
conversation_id: str,
|
761
761
|
context: Dict[str, Any],
|
@@ -855,7 +855,7 @@ class EmailProvider(BaseProvider):
|
|
855
855
|
body, html_body = self._format_email_body(prompt, HumanLoopType.CONVERSATION, subject)
|
856
856
|
|
857
857
|
# 发送邮件
|
858
|
-
success = await self.
|
858
|
+
success = await self._async_send_email(
|
859
859
|
to_email=recipient_email,
|
860
860
|
subject=subject,
|
861
861
|
body=body,
|
@@ -879,13 +879,13 @@ class EmailProvider(BaseProvider):
|
|
879
879
|
|
880
880
|
# 创建邮件检查任务
|
881
881
|
check_task = asyncio.create_task(
|
882
|
-
self.
|
882
|
+
self._async_check_emails(conversation_id, request_id, recipient_email, subject)
|
883
883
|
)
|
884
884
|
self._mail_check_tasks[(conversation_id, request_id)] = check_task
|
885
885
|
|
886
886
|
# 如果设置了超时,创建超时任务
|
887
887
|
if timeout:
|
888
|
-
self.
|
888
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
889
889
|
|
890
890
|
return HumanLoopResult(
|
891
891
|
conversation_id=conversation_id,
|
@@ -894,7 +894,7 @@ class EmailProvider(BaseProvider):
|
|
894
894
|
status=HumanLoopStatus.PENDING
|
895
895
|
)
|
896
896
|
|
897
|
-
async def
|
897
|
+
async def async_cancel_request(
|
898
898
|
self,
|
899
899
|
conversation_id: str,
|
900
900
|
request_id: str
|
@@ -916,9 +916,9 @@ class EmailProvider(BaseProvider):
|
|
916
916
|
del self._mail_check_tasks[request_key]
|
917
917
|
|
918
918
|
# 调用父类方法取消请求
|
919
|
-
return await super().
|
919
|
+
return await super().async_cancel_request(conversation_id, request_id)
|
920
920
|
|
921
|
-
async def
|
921
|
+
async def async_cancel_conversation(
|
922
922
|
self,
|
923
923
|
conversation_id: str
|
924
924
|
) -> bool:
|
@@ -938,7 +938,7 @@ class EmailProvider(BaseProvider):
|
|
938
938
|
del self._mail_check_tasks[request_key]
|
939
939
|
|
940
940
|
# 调用父类方法取消对话
|
941
|
-
return await super().
|
941
|
+
return await super().async_cancel_conversation(conversation_id)
|
942
942
|
|
943
943
|
def _extract_user_reply_content(self, body: str) -> str:
|
944
944
|
"""Extract the actual reply content from the email, excluding quoted original email content
|
@@ -28,7 +28,7 @@ class TerminalProvider(BaseProvider):
|
|
28
28
|
terminal_info = f"- Terminal Provider: Terminal-based human-in-the-loop implementation\n"
|
29
29
|
return f"{terminal_info}{base_str}"
|
30
30
|
|
31
|
-
async def
|
31
|
+
async def async_request_humanloop(
|
32
32
|
self,
|
33
33
|
task_id: str,
|
34
34
|
conversation_id: str,
|
@@ -77,11 +77,11 @@ class TerminalProvider(BaseProvider):
|
|
77
77
|
|
78
78
|
# Create timeout task if timeout is specified
|
79
79
|
if timeout:
|
80
|
-
self.
|
80
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
81
81
|
|
82
82
|
return result
|
83
83
|
|
84
|
-
async def
|
84
|
+
async def async_check_request_status(
|
85
85
|
self,
|
86
86
|
conversation_id: str,
|
87
87
|
request_id: str
|
@@ -120,7 +120,7 @@ class TerminalProvider(BaseProvider):
|
|
120
120
|
|
121
121
|
return result
|
122
122
|
|
123
|
-
async def
|
123
|
+
async def async_continue_humanloop(
|
124
124
|
self,
|
125
125
|
conversation_id: str,
|
126
126
|
context: Dict[str, Any],
|
@@ -179,7 +179,7 @@ class TerminalProvider(BaseProvider):
|
|
179
179
|
|
180
180
|
# Create timeout task if timeout is specified
|
181
181
|
if timeout:
|
182
|
-
self.
|
182
|
+
await self._async_create_timeout_task(conversation_id, request_id, timeout)
|
183
183
|
|
184
184
|
return result
|
185
185
|
|
@@ -205,14 +205,14 @@ class TerminalProvider(BaseProvider):
|
|
205
205
|
|
206
206
|
# Handle different interaction types based on loop type
|
207
207
|
if loop_type == HumanLoopType.APPROVAL:
|
208
|
-
await self.
|
208
|
+
await self._async_handle_approval_interaction(conversation_id, request_id, request_info)
|
209
209
|
elif loop_type == HumanLoopType.INFORMATION:
|
210
|
-
await self.
|
210
|
+
await self._async_handle_information_interaction(conversation_id, request_id, request_info)
|
211
211
|
else: # HumanLoopType.CONVERSATION
|
212
|
-
await self.
|
212
|
+
await self._async_handle_conversation_interaction(conversation_id, request_id, request_info)
|
213
213
|
|
214
214
|
|
215
|
-
async def
|
215
|
+
async def _async_handle_approval_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
|
216
216
|
"""Handle approval type interaction
|
217
217
|
|
218
218
|
Args:
|
@@ -225,7 +225,6 @@ class TerminalProvider(BaseProvider):
|
|
225
225
|
# Execute blocking input() call in thread pool using run_in_executor
|
226
226
|
loop = asyncio.get_event_loop()
|
227
227
|
response = await loop.run_in_executor(None, input)
|
228
|
-
|
229
228
|
# Process response
|
230
229
|
response = response.strip().lower()
|
231
230
|
if response in ["approve", "yes", "y", "同意", "批准"]:
|
@@ -239,7 +238,7 @@ class TerminalProvider(BaseProvider):
|
|
239
238
|
else:
|
240
239
|
print("\nInvalid input, please enter 'approve' or 'reject'")
|
241
240
|
# Recursively handle approval interaction
|
242
|
-
await self.
|
241
|
+
await self._async_handle_approval_interaction(conversation_id, request_id, request_info)
|
243
242
|
return
|
244
243
|
|
245
244
|
# Update request information
|
@@ -250,7 +249,7 @@ class TerminalProvider(BaseProvider):
|
|
250
249
|
|
251
250
|
print(f"\nYour decision has been recorded: {status.value}")
|
252
251
|
|
253
|
-
async def
|
252
|
+
async def _async_handle_information_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
|
254
253
|
"""Handle information collection type interaction
|
255
254
|
|
256
255
|
Args:
|
@@ -272,7 +271,7 @@ class TerminalProvider(BaseProvider):
|
|
272
271
|
|
273
272
|
print("\nYour information has been recorded")
|
274
273
|
|
275
|
-
async def
|
274
|
+
async def _async_handle_conversation_interaction(self, conversation_id: str, request_id: str, request_info: Dict[str, Any]):
|
276
275
|
"""Handle conversation type interaction
|
277
276
|
|
278
277
|
Args:
|
gohumanloop/utils/utils.py
CHANGED
@@ -2,16 +2,43 @@ import asyncio
|
|
2
2
|
import os
|
3
3
|
from typing import Optional, Union
|
4
4
|
from pydantic import SecretStr
|
5
|
+
import warnings
|
6
|
+
|
5
7
|
def run_async_safely(coro):
|
6
|
-
"""
|
8
|
+
"""
|
9
|
+
Safely run async coroutines in synchronous environment
|
10
|
+
Will raise RuntimeError if called in async environment
|
11
|
+
"""
|
12
|
+
try:
|
13
|
+
loop = asyncio.get_running_loop()
|
14
|
+
except RuntimeError: # No running event loop
|
15
|
+
loop = None
|
16
|
+
|
17
|
+
if loop is not None:
|
18
|
+
raise RuntimeError(
|
19
|
+
"Detected running event loop! "
|
20
|
+
"You should use 'await' directly instead of run_async_safely(). "
|
21
|
+
"If you really need to call sync code from async context, "
|
22
|
+
"consider using asyncio.to_thread() or other proper methods."
|
23
|
+
)
|
24
|
+
|
25
|
+
# Handle synchronous environment
|
7
26
|
try:
|
8
27
|
loop = asyncio.get_event_loop()
|
28
|
+
print("Using existing event loop.")
|
9
29
|
except RuntimeError:
|
10
|
-
# 如果没有事件循环,创建一个新的
|
11
30
|
loop = asyncio.new_event_loop()
|
12
31
|
asyncio.set_event_loop(loop)
|
32
|
+
own_loop = True
|
33
|
+
print("Created new event loop.")
|
34
|
+
else:
|
35
|
+
own_loop = False
|
13
36
|
|
14
|
-
|
37
|
+
try:
|
38
|
+
return loop.run_until_complete(coro)
|
39
|
+
finally:
|
40
|
+
if own_loop and not loop.is_closed():
|
41
|
+
loop.close()
|
15
42
|
|
16
43
|
|
17
44
|
def get_secret_from_env(
|
@@ -1,30 +1,30 @@
|
|
1
1
|
gohumanloop/__init__.py,sha256=7_AkUtiG-_iozObldORElQS9mufxjZx_WfxuX0E5Af0,1845
|
2
2
|
gohumanloop/__main__.py,sha256=zdGKN92H9SgwZfL4xLqPkE1YaiRcHhVg_GqC-H1VurA,75
|
3
3
|
gohumanloop/adapters/__init__.py,sha256=alRiJPahmH5vIbiw7l6o3eFvEADVTkfWYIsXy5uPGSo,391
|
4
|
-
gohumanloop/adapters/langgraph_adapter.py,sha256=
|
4
|
+
gohumanloop/adapters/langgraph_adapter.py,sha256=7w3ek8Yzr1r0tfJ4A5UNb_pcFRTfNVDc5gWNVq56IH0,34099
|
5
5
|
gohumanloop/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
gohumanloop/cli/main.py,sha256=54-0nwjaAeRH2WhbyO6pN-XADPQwk4_EUUvVWDWruLc,744
|
7
7
|
gohumanloop/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
gohumanloop/core/interface.py,sha256=
|
9
|
-
gohumanloop/core/manager.py,sha256=
|
8
|
+
gohumanloop/core/interface.py,sha256=UjeEBKGS_JjwIsT5sBzyq6_IhUkDFrUvBXqpkxkFrAA,22696
|
9
|
+
gohumanloop/core/manager.py,sha256=MAgT5Sx1aLRBIb1mWxp-XJkQxEoibut8-TVtze8bWXQ,33068
|
10
10
|
gohumanloop/manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
gohumanloop/manager/ghl_manager.py,sha256=
|
11
|
+
gohumanloop/manager/ghl_manager.py,sha256=m7KVdjd5bpxPNm2Sxk4LySzx_Ll4OfpJygxrfFhToDA,22026
|
12
12
|
gohumanloop/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
gohumanloop/models/api_model.py,sha256=cNTXTlfI7yrTk_87Qf6ms0VtRXO2fYFJFLPTLy2dmQk,2853
|
14
14
|
gohumanloop/models/glh_model.py,sha256=Ht93iCdLfVYz_nW-uW4bE5s0UoyKG3VEx9q-Gg8_tiY,870
|
15
15
|
gohumanloop/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
gohumanloop/providers/api_provider.py,sha256=
|
17
|
-
gohumanloop/providers/base.py,sha256=
|
18
|
-
gohumanloop/providers/email_provider.py,sha256=
|
16
|
+
gohumanloop/providers/api_provider.py,sha256=ooZQfi4Zu27U8kyTJ9rssAVzAVoyga71xT8nUjdQJmE,24517
|
17
|
+
gohumanloop/providers/base.py,sha256=Eq2y4fqJXdDfbA4xkyHBBH7opGeOg8PAte5vAbx2lwI,24623
|
18
|
+
gohumanloop/providers/email_provider.py,sha256=G04557UxdyBnmCx4WTXiakElELRv1fHDYTYNbvzDtqw,42562
|
19
19
|
gohumanloop/providers/ghl_provider.py,sha256=YdxTpRzitFhTXTbhUcMhQlPUs3kwEBd4wyXEcGK8Svk,2524
|
20
|
-
gohumanloop/providers/terminal_provider.py,sha256=
|
20
|
+
gohumanloop/providers/terminal_provider.py,sha256=HBR6fLftaDRydueI5wxKtVOrgYF5RcPxzIhmLPrNVzo,11720
|
21
21
|
gohumanloop/utils/__init__.py,sha256=idlE5ZNCELVNF9WIiyhtyzG9HJuQQCOlKeTr2aHJ2-Q,56
|
22
22
|
gohumanloop/utils/context_formatter.py,sha256=v4vdgKNJCHjnTtIMq83AkyXwltL14vx-D4KahwcZhIQ,2171
|
23
23
|
gohumanloop/utils/threadsafedict.py,sha256=0-Pmre2-lqHkUPal9wSaqh3fLaEtbo-OnJ3Wbi_knWE,9601
|
24
|
-
gohumanloop/utils/utils.py,sha256=
|
25
|
-
gohumanloop-0.0.
|
26
|
-
gohumanloop-0.0.
|
27
|
-
gohumanloop-0.0.
|
28
|
-
gohumanloop-0.0.
|
29
|
-
gohumanloop-0.0.
|
30
|
-
gohumanloop-0.0.
|
24
|
+
gohumanloop/utils/utils.py,sha256=iwfIAYuuKSyuEpOUv4ftf7zRDqSvJ6ALgqceHaZNeO4,2102
|
25
|
+
gohumanloop-0.0.3.dist-info/licenses/LICENSE,sha256=-U5tuCcSpndQwSKWtZbFbazb-_AtZcZL2kQgHbSLg-M,1064
|
26
|
+
gohumanloop-0.0.3.dist-info/METADATA,sha256=e7exfCd8QVCiMbcAjFwgnAbqoziS1WMUnYh7GL7eZPc,1557
|
27
|
+
gohumanloop-0.0.3.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
28
|
+
gohumanloop-0.0.3.dist-info/entry_points.txt,sha256=wM6jqRRD8bQXkvIduRVCuAJIlbyWg_F5EDXo5OZ_PwY,88
|
29
|
+
gohumanloop-0.0.3.dist-info/top_level.txt,sha256=LvOXBqS6Mspmcuqp81uz0Vjx_m_YI0w06DOPCiI1BfY,12
|
30
|
+
gohumanloop-0.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|