gohumanloop 0.0.4__py3-none-any.whl → 0.0.5__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/__init__.py +11 -3
- gohumanloop/adapters/langgraph_adapter.py +17 -13
- gohumanloop/core/manager.py +24 -111
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/METADATA +1 -1
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/RECORD +9 -9
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/WHEEL +0 -0
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/entry_points.txt +0 -0
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/licenses/LICENSE +0 -0
- {gohumanloop-0.0.4.dist-info → gohumanloop-0.0.5.dist-info}/top_level.txt +0 -0
gohumanloop/__init__.py
CHANGED
@@ -12,12 +12,18 @@ from gohumanloop.manager.ghl_manager import GoHumanLoopManager
|
|
12
12
|
|
13
13
|
from gohumanloop.providers.ghl_provider import GoHumanLoopProvider
|
14
14
|
from gohumanloop.providers.api_provider import APIProvider
|
15
|
-
from gohumanloop.providers.email_provider import EmailProvider
|
16
15
|
from gohumanloop.providers.base import BaseProvider
|
17
16
|
from gohumanloop.providers.terminal_provider import TerminalProvider
|
18
17
|
|
19
18
|
from gohumanloop.utils import run_async_safely, get_secret_from_env
|
20
19
|
|
20
|
+
# Conditionally import EmailProvider
|
21
|
+
try:
|
22
|
+
from gohumanloop.providers.email_provider import EmailProvider
|
23
|
+
_has_email = True
|
24
|
+
except ImportError:
|
25
|
+
_has_email = False
|
26
|
+
|
21
27
|
# Dynamically get version number
|
22
28
|
try:
|
23
29
|
from importlib.metadata import version, PackageNotFoundError
|
@@ -53,7 +59,6 @@ __all__ = [
|
|
53
59
|
"BaseProvider",
|
54
60
|
"APIProvider",
|
55
61
|
"GoHumanLoopProvider",
|
56
|
-
"EmailProvider",
|
57
62
|
"TerminalProvider",
|
58
63
|
|
59
64
|
# Utility Functions
|
@@ -62,4 +67,7 @@ __all__ = [
|
|
62
67
|
|
63
68
|
# Version Information
|
64
69
|
"__version__",
|
65
|
-
]
|
70
|
+
]
|
71
|
+
|
72
|
+
if _has_email:
|
73
|
+
__all__.append("EmailProvider")
|
@@ -5,12 +5,15 @@ import uuid
|
|
5
5
|
import time
|
6
6
|
from inspect import iscoroutinefunction
|
7
7
|
from contextlib import asynccontextmanager, contextmanager
|
8
|
+
import logging
|
8
9
|
|
9
10
|
from gohumanloop.utils import run_async_safely
|
10
11
|
from gohumanloop.core.interface import (
|
11
12
|
HumanLoopManager, HumanLoopResult, HumanLoopStatus, HumanLoopType, HumanLoopCallback, HumanLoopProvider
|
12
13
|
)
|
13
14
|
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
14
17
|
# Define TypeVars for input and output types
|
15
18
|
T = TypeVar("T")
|
16
19
|
R = TypeVar('R')
|
@@ -658,9 +661,7 @@ def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback
|
|
658
661
|
Returns:
|
659
662
|
Configured LangGraphHumanLoopCallback instance
|
660
663
|
"""
|
661
|
-
|
662
|
-
|
663
|
-
logger = logging.getLogger("gohumanloop.langgraph")
|
664
|
+
|
664
665
|
|
665
666
|
async def async_on_update(state, provider: HumanLoopProvider, result: HumanLoopResult):
|
666
667
|
"""Log human interaction update events"""
|
@@ -739,16 +740,19 @@ def interrupt(value: Any, lg_humanloop: LangGraphAdapter = default_adapter) -> A
|
|
739
740
|
|
740
741
|
if not _SKIP_NEXT_HUMANLOOP:
|
741
742
|
# Get current event loop or create new one
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
743
|
+
try:
|
744
|
+
lg_humanloop.manager.request_humanloop(
|
745
|
+
task_id="lg_interrupt",
|
746
|
+
conversation_id=default_conversation_id,
|
747
|
+
loop_type=HumanLoopType.INFORMATION,
|
748
|
+
context={
|
749
|
+
"message": f"{value}",
|
750
|
+
"question": "The execution has been interrupted. Please review the above information and provide your input to continue.",
|
751
|
+
},
|
752
|
+
blocking=False,
|
753
|
+
)
|
754
|
+
except Exception as e:
|
755
|
+
logger.exception(f"Error in interrupt: {e}")
|
752
756
|
else:
|
753
757
|
# Reset flag to allow normal human intervention trigger next time
|
754
758
|
_SKIP_NEXT_HUMANLOOP = False
|
gohumanloop/core/manager.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import Dict, Any, Optional, List, Union, Set
|
2
2
|
import asyncio
|
3
3
|
import time
|
4
|
+
from gohumanloop.utils import run_async_safely
|
4
5
|
|
5
6
|
from gohumanloop.core.interface import (
|
6
7
|
HumanLoopManager, HumanLoopProvider, HumanLoopCallback,
|
@@ -150,15 +151,8 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
150
151
|
blocking: bool = False,
|
151
152
|
) -> Union[str, HumanLoopResult]:
|
152
153
|
"""请求人机循环(同步版本)"""
|
153
|
-
|
154
|
-
|
155
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
156
|
-
new_loop = asyncio.new_event_loop()
|
157
|
-
asyncio.set_event_loop(new_loop)
|
158
|
-
loop = new_loop
|
159
|
-
|
160
|
-
try:
|
161
|
-
return loop.run_until_complete(
|
154
|
+
|
155
|
+
return run_async_safely(
|
162
156
|
self.async_request_humanloop(
|
163
157
|
task_id=task_id,
|
164
158
|
conversation_id=conversation_id,
|
@@ -171,9 +165,7 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
171
165
|
blocking=blocking
|
172
166
|
)
|
173
167
|
)
|
174
|
-
|
175
|
-
if loop != asyncio.get_event_loop():
|
176
|
-
loop.close()
|
168
|
+
|
177
169
|
|
178
170
|
async def async_continue_humanloop(
|
179
171
|
self,
|
@@ -267,15 +259,8 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
267
259
|
blocking: bool = False,
|
268
260
|
) -> Union[str, HumanLoopResult]:
|
269
261
|
"""继续人机循环(同步版本)"""
|
270
|
-
|
271
|
-
|
272
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
273
|
-
new_loop = asyncio.new_event_loop()
|
274
|
-
asyncio.set_event_loop(new_loop)
|
275
|
-
loop = new_loop
|
276
|
-
|
277
|
-
try:
|
278
|
-
return loop.run_until_complete(
|
262
|
+
|
263
|
+
return run_async_safely(
|
279
264
|
self.async_continue_humanloop(
|
280
265
|
conversation_id=conversation_id,
|
281
266
|
context=context,
|
@@ -286,9 +271,6 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
286
271
|
blocking=blocking
|
287
272
|
)
|
288
273
|
)
|
289
|
-
finally:
|
290
|
-
if loop != asyncio.get_event_loop():
|
291
|
-
loop.close()
|
292
274
|
|
293
275
|
async def async_check_request_status(
|
294
276
|
self,
|
@@ -334,24 +316,14 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
334
316
|
provider_id: Optional[str] = None
|
335
317
|
) -> HumanLoopResult:
|
336
318
|
"""检查请求状态(同步版本)"""
|
337
|
-
|
338
|
-
|
339
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
340
|
-
new_loop = asyncio.new_event_loop()
|
341
|
-
asyncio.set_event_loop(new_loop)
|
342
|
-
loop = new_loop
|
343
|
-
|
344
|
-
try:
|
345
|
-
return loop.run_until_complete(
|
319
|
+
|
320
|
+
return run_async_safely(
|
346
321
|
self.async_check_request_status(
|
347
322
|
conversation_id=conversation_id,
|
348
323
|
request_id=request_id,
|
349
324
|
provider_id=provider_id
|
350
325
|
)
|
351
326
|
)
|
352
|
-
finally:
|
353
|
-
if loop != asyncio.get_event_loop():
|
354
|
-
loop.close()
|
355
327
|
|
356
328
|
|
357
329
|
async def async_check_conversation_status(
|
@@ -394,23 +366,13 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
394
366
|
provider_id: Optional[str] = None
|
395
367
|
) -> HumanLoopResult:
|
396
368
|
"""检查对话状态(同步版本)"""
|
397
|
-
|
398
|
-
|
399
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
400
|
-
new_loop = asyncio.new_event_loop()
|
401
|
-
asyncio.set_event_loop(new_loop)
|
402
|
-
loop = new_loop
|
403
|
-
|
404
|
-
try:
|
405
|
-
return loop.run_until_complete(
|
369
|
+
|
370
|
+
return run_async_safely(
|
406
371
|
self.async_check_conversation_status(
|
407
372
|
conversation_id=conversation_id,
|
408
373
|
provider_id=provider_id
|
409
374
|
)
|
410
375
|
)
|
411
|
-
finally:
|
412
|
-
if loop != asyncio.get_event_loop():
|
413
|
-
loop.close()
|
414
376
|
|
415
377
|
async def async_cancel_request(
|
416
378
|
self,
|
@@ -456,25 +418,14 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
456
418
|
provider_id: Optional[str] = None
|
457
419
|
) -> bool:
|
458
420
|
"""取消特定请求(同步版本)"""
|
459
|
-
|
460
|
-
|
461
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
462
|
-
new_loop = asyncio.new_event_loop()
|
463
|
-
asyncio.set_event_loop(new_loop)
|
464
|
-
loop = new_loop
|
465
|
-
|
466
|
-
try:
|
467
|
-
return loop.run_until_complete(
|
421
|
+
|
422
|
+
return run_async_safely(
|
468
423
|
self.async_cancel_request(
|
469
424
|
conversation_id=conversation_id,
|
470
425
|
request_id=request_id,
|
471
426
|
provider_id=provider_id
|
472
427
|
)
|
473
428
|
)
|
474
|
-
finally:
|
475
|
-
if loop != asyncio.get_event_loop():
|
476
|
-
loop.close()
|
477
|
-
|
478
429
|
|
479
430
|
async def async_cancel_conversation(
|
480
431
|
self,
|
@@ -547,25 +498,14 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
547
498
|
provider_id: Optional[str] = None
|
548
499
|
) -> bool:
|
549
500
|
"""取消整个对话(同步版本)"""
|
550
|
-
|
551
|
-
|
552
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
553
|
-
new_loop = asyncio.new_event_loop()
|
554
|
-
asyncio.set_event_loop(new_loop)
|
555
|
-
loop = new_loop
|
556
|
-
|
557
|
-
try:
|
558
|
-
return loop.run_until_complete(
|
501
|
+
|
502
|
+
return run_async_safely(
|
559
503
|
self.async_cancel_conversation(
|
560
504
|
conversation_id=conversation_id,
|
561
505
|
provider_id=provider_id
|
562
506
|
)
|
563
507
|
)
|
564
|
-
finally:
|
565
|
-
if loop != asyncio.get_event_loop():
|
566
|
-
loop.close()
|
567
508
|
|
568
|
-
|
569
509
|
async def async_get_provider(
|
570
510
|
self,
|
571
511
|
provider_id: Optional[str] = None
|
@@ -582,20 +522,10 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
582
522
|
provider_id: Optional[str] = None
|
583
523
|
) -> HumanLoopProvider:
|
584
524
|
"""获取指定的提供者实例(同步版本)"""
|
585
|
-
|
586
|
-
|
587
|
-
# 如果事件循环已经在运行,创建一个新的事件循环
|
588
|
-
new_loop = asyncio.new_event_loop()
|
589
|
-
asyncio.set_event_loop(new_loop)
|
590
|
-
loop = new_loop
|
591
|
-
|
592
|
-
try:
|
593
|
-
return loop.run_until_complete(
|
525
|
+
|
526
|
+
return run_async_safely(
|
594
527
|
self.async_get_provider(provider_id=provider_id)
|
595
528
|
)
|
596
|
-
finally:
|
597
|
-
if loop != asyncio.get_event_loop():
|
598
|
-
loop.close()
|
599
529
|
|
600
530
|
async def async_list_providers(self) -> Dict[str, HumanLoopProvider]:
|
601
531
|
"""列出所有注册的提供者"""
|
@@ -604,18 +534,11 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
604
534
|
|
605
535
|
def list_providers(self) -> Dict[str, HumanLoopProvider]:
|
606
536
|
"""列出所有注册的提供者(同步版本)"""
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
loop = new_loop
|
613
|
-
|
614
|
-
try:
|
615
|
-
return loop.run_until_complete(self.async_list_providers())
|
616
|
-
finally:
|
617
|
-
if loop != asyncio.get_event_loop():
|
618
|
-
loop.close()
|
537
|
+
|
538
|
+
return run_async_safely(
|
539
|
+
self.async_list_providers()
|
540
|
+
)
|
541
|
+
|
619
542
|
|
620
543
|
|
621
544
|
async def async_set_default_provider(
|
@@ -635,21 +558,11 @@ class DefaultHumanLoopManager(HumanLoopManager):
|
|
635
558
|
provider_id: str
|
636
559
|
) -> bool:
|
637
560
|
"""设置默认提供者(同步版本)"""
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
new_loop = asyncio.new_event_loop()
|
642
|
-
asyncio.set_event_loop(new_loop)
|
643
|
-
loop = new_loop
|
644
|
-
|
645
|
-
try:
|
646
|
-
return loop.run_until_complete(
|
561
|
+
|
562
|
+
|
563
|
+
return run_async_safely(
|
647
564
|
self.async_set_default_provider(provider_id=provider_id)
|
648
565
|
)
|
649
|
-
finally:
|
650
|
-
if loop != asyncio.get_event_loop():
|
651
|
-
loop.close()
|
652
|
-
|
653
566
|
|
654
567
|
async def _async_create_timeout_task(
|
655
568
|
self,
|
@@ -1,12 +1,12 @@
|
|
1
|
-
gohumanloop/__init__.py,sha256=
|
1
|
+
gohumanloop/__init__.py,sha256=5eLYP_lpIgvrzMEAON6KMBxmc92Iy9rzEwfW8tCbTbo,1988
|
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=nQp_aHyXrlvn-3Nf76WbAwZYBl2er32b1UOBX7IzcaY,34470
|
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
8
|
gohumanloop/core/interface.py,sha256=UjeEBKGS_JjwIsT5sBzyq6_IhUkDFrUvBXqpkxkFrAA,22696
|
9
|
-
gohumanloop/core/manager.py,sha256=
|
9
|
+
gohumanloop/core/manager.py,sha256=gOEQEd15J3ymNG9ywhDlmZRU5dScAIpdnTWIWLELvww,29526
|
10
10
|
gohumanloop/manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
gohumanloop/manager/ghl_manager.py,sha256=Td54EcPg1r9Q5JfzS90QjzxiAhcMBYMigaERImLjp7M,21993
|
12
12
|
gohumanloop/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -22,9 +22,9 @@ gohumanloop/utils/__init__.py,sha256=idlE5ZNCELVNF9WIiyhtyzG9HJuQQCOlKeTr2aHJ2-Q
|
|
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
24
|
gohumanloop/utils/utils.py,sha256=3f53fHdWLPve-WTn9mGiz3SB0CE7l39caC5Dz0hm85U,2167
|
25
|
-
gohumanloop-0.0.
|
26
|
-
gohumanloop-0.0.
|
27
|
-
gohumanloop-0.0.
|
28
|
-
gohumanloop-0.0.
|
29
|
-
gohumanloop-0.0.
|
30
|
-
gohumanloop-0.0.
|
25
|
+
gohumanloop-0.0.5.dist-info/licenses/LICENSE,sha256=-U5tuCcSpndQwSKWtZbFbazb-_AtZcZL2kQgHbSLg-M,1064
|
26
|
+
gohumanloop-0.0.5.dist-info/METADATA,sha256=LszSA1v9pSFS0G8VfuknuZwosUN-NQIebRfRy3jDZ9Q,1557
|
27
|
+
gohumanloop-0.0.5.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
28
|
+
gohumanloop-0.0.5.dist-info/entry_points.txt,sha256=wM6jqRRD8bQXkvIduRVCuAJIlbyWg_F5EDXo5OZ_PwY,88
|
29
|
+
gohumanloop-0.0.5.dist-info/top_level.txt,sha256=LvOXBqS6Mspmcuqp81uz0Vjx_m_YI0w06DOPCiI1BfY,12
|
30
|
+
gohumanloop-0.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|