gohumanloop 0.0.2__tar.gz → 0.0.3__tar.gz
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-0.0.2 → gohumanloop-0.0.3}/PKG-INFO +1 -1
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/adapters/langgraph_adapter.py +39 -41
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/core/interface.py +342 -21
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/core/manager.py +302 -39
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/manager/ghl_manager.py +22 -22
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/api_provider.py +18 -18
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/base.py +239 -9
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/email_provider.py +15 -15
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/terminal_provider.py +12 -13
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/utils/utils.py +30 -3
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/PKG-INFO +1 -1
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/pyproject.toml +1 -1
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/LICENSE +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/README.md +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/__main__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/adapters/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/cli/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/cli/main.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/core/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/manager/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/models/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/models/api_model.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/models/glh_model.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/providers/ghl_provider.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/utils/__init__.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/utils/context_formatter.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop/utils/threadsafedict.py +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/SOURCES.txt +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/dependency_links.txt +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/entry_points.txt +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/requires.txt +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/gohumanloop.egg-info/top_level.txt +0 -0
- {gohumanloop-0.0.2 → gohumanloop-0.0.3}/setup.cfg +0 -0
@@ -2,6 +2,7 @@ from typing import Dict, Any, Optional, Callable, Awaitable, TypeVar, Union, Lis
|
|
2
2
|
from functools import wraps
|
3
3
|
import asyncio
|
4
4
|
import uuid
|
5
|
+
import time
|
5
6
|
from inspect import iscoroutinefunction
|
6
7
|
from contextlib import asynccontextmanager, contextmanager
|
7
8
|
|
@@ -209,7 +210,7 @@ class LangGraphAdapter:
|
|
209
210
|
else:
|
210
211
|
cb = callback
|
211
212
|
|
212
|
-
result = await self.manager.
|
213
|
+
result = await self.manager.async_request_humanloop(
|
213
214
|
task_id=task_id,
|
214
215
|
conversation_id=conversation_id,
|
215
216
|
loop_type=HumanLoopType.APPROVAL,
|
@@ -374,12 +375,12 @@ class LangGraphAdapter:
|
|
374
375
|
question_content = f"Please respond to the following information:\n{node_input}"
|
375
376
|
|
376
377
|
# Check if conversation exists to determine whether to use request_humanloop or continue_humanloop
|
377
|
-
conversation_requests = await self.manager.
|
378
|
+
conversation_requests = await self.manager.async_check_conversation_exist(task_id, conversation_id)
|
378
379
|
|
379
380
|
result = None
|
380
381
|
if conversation_requests:
|
381
382
|
# Existing conversation, use continue_humanloop
|
382
|
-
result = await self.manager.
|
383
|
+
result = await self.manager.async_continue_humanloop(
|
383
384
|
conversation_id=conversation_id,
|
384
385
|
context={
|
385
386
|
"message": {
|
@@ -400,7 +401,7 @@ class LangGraphAdapter:
|
|
400
401
|
)
|
401
402
|
else:
|
402
403
|
# New conversation, use request_humanloop
|
403
|
-
result = await self.manager.
|
404
|
+
result = await self.manager.async_request_humanloop(
|
404
405
|
task_id=task_id,
|
405
406
|
conversation_id=conversation_id,
|
406
407
|
loop_type=HumanLoopType.CONVERSATION,
|
@@ -543,7 +544,7 @@ class LangGraphAdapter:
|
|
543
544
|
else:
|
544
545
|
cb = callback
|
545
546
|
|
546
|
-
result = await self.manager.
|
547
|
+
result = await self.manager.async_request_humanloop(
|
547
548
|
task_id=task_id,
|
548
549
|
conversation_id=conversation_id,
|
549
550
|
loop_type=HumanLoopType.INFORMATION,
|
@@ -608,37 +609,37 @@ class LangGraphHumanLoopCallback(HumanLoopCallback):
|
|
608
609
|
def __init__(
|
609
610
|
self,
|
610
611
|
state: Any,
|
611
|
-
|
612
|
-
|
613
|
-
|
612
|
+
async_on_update: Optional[Callable[[Any, HumanLoopProvider, HumanLoopResult], Awaitable[None]]] = None,
|
613
|
+
async_on_timeout: Optional[Callable[[Any, HumanLoopProvider], Awaitable[None]]] = None,
|
614
|
+
async_on_error: Optional[Callable[[Any, HumanLoopProvider, Exception], Awaitable[None]]] = None,
|
614
615
|
):
|
615
616
|
self.state = state
|
616
|
-
self.
|
617
|
-
self.
|
618
|
-
self.
|
617
|
+
self.async_on_update = async_on_update
|
618
|
+
self.async_on_timeout = async_on_timeout
|
619
|
+
self.async_on_error = async_on_error
|
619
620
|
|
620
|
-
async def
|
621
|
+
async def async_on_humanloop_update(
|
621
622
|
self,
|
622
623
|
provider: HumanLoopProvider,
|
623
624
|
result: HumanLoopResult
|
624
625
|
):
|
625
|
-
if self.
|
626
|
-
await self.
|
626
|
+
if self.async_on_update:
|
627
|
+
await self.async_on_update(self.state, provider, result)
|
627
628
|
|
628
|
-
async def
|
629
|
+
async def async_on_humanloop_timeout(
|
629
630
|
self,
|
630
631
|
provider: HumanLoopProvider,
|
631
632
|
):
|
632
|
-
if self.
|
633
|
-
await self.
|
633
|
+
if self.async_on_timeout:
|
634
|
+
await self.async_on_timeout(self.state, provider)
|
634
635
|
|
635
|
-
async def
|
636
|
+
async def async_humanloop_on_error(
|
636
637
|
self,
|
637
638
|
provider: HumanLoopProvider,
|
638
639
|
error: Exception
|
639
640
|
):
|
640
|
-
if self.
|
641
|
-
await self.
|
641
|
+
if self.async_on_error:
|
642
|
+
await self.async_on_error(self.state, provider, error)
|
642
643
|
|
643
644
|
|
644
645
|
def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback:
|
@@ -661,7 +662,7 @@ def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback
|
|
661
662
|
|
662
663
|
logger = logging.getLogger("gohumanloop.langgraph")
|
663
664
|
|
664
|
-
async def
|
665
|
+
async def async_on_update(state, provider: HumanLoopProvider, result: HumanLoopResult):
|
665
666
|
"""Log human interaction update events"""
|
666
667
|
logger.info(f"Provider ID: {provider.name}")
|
667
668
|
logger.info(
|
@@ -673,8 +674,9 @@ def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback
|
|
673
674
|
f"feedback={result.feedback}"
|
674
675
|
)
|
675
676
|
|
677
|
+
|
676
678
|
|
677
|
-
async def
|
679
|
+
async def async_on_timeout(state, provider: HumanLoopProvider):
|
678
680
|
"""Log human interaction timeout events"""
|
679
681
|
|
680
682
|
logger.info(f"Provider ID: {provider.name}")
|
@@ -685,7 +687,7 @@ def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback
|
|
685
687
|
|
686
688
|
# Alert logic can be added here, such as sending notifications
|
687
689
|
|
688
|
-
async def
|
690
|
+
async def async_on_error(state, provider: HumanLoopProvider, error: Exception):
|
689
691
|
"""Log human interaction error events"""
|
690
692
|
|
691
693
|
logger.info(f"Provider ID: {provider.name}")
|
@@ -695,9 +697,9 @@ def default_langgraph_callback_factory(state: Any) -> LangGraphHumanLoopCallback
|
|
695
697
|
|
696
698
|
return LangGraphHumanLoopCallback(
|
697
699
|
state=state,
|
698
|
-
|
699
|
-
|
700
|
-
|
700
|
+
async_on_update=async_on_update,
|
701
|
+
async_on_timeout=async_on_timeout,
|
702
|
+
async_on_error=async_on_error
|
701
703
|
)
|
702
704
|
|
703
705
|
from gohumanloop.core.manager import DefaultHumanLoopManager
|
@@ -731,14 +733,7 @@ def interrupt(value: Any, lg_humanloop: LangGraphAdapter = default_adapter) -> A
|
|
731
733
|
)
|
732
734
|
|
733
735
|
# Get current event loop or create new one
|
734
|
-
|
735
|
-
loop = asyncio.get_event_loop()
|
736
|
-
except RuntimeError:
|
737
|
-
# If no event loop exists, create a new one
|
738
|
-
loop = asyncio.new_event_loop()
|
739
|
-
asyncio.set_event_loop(loop)
|
740
|
-
|
741
|
-
loop.create_task(lg_humanloop.manager.request_humanloop(
|
736
|
+
lg_humanloop.manager.request_humanloop(
|
742
737
|
task_id="lg_interrupt",
|
743
738
|
conversation_id=default_conversation_id,
|
744
739
|
loop_type=HumanLoopType.INFORMATION,
|
@@ -747,8 +742,8 @@ def interrupt(value: Any, lg_humanloop: LangGraphAdapter = default_adapter) -> A
|
|
747
742
|
"question": "The execution has been interrupted. Please review the above information and provide your input to continue.",
|
748
743
|
},
|
749
744
|
blocking=False,
|
750
|
-
)
|
751
|
-
|
745
|
+
)
|
746
|
+
|
752
747
|
# Return LangGraph's interrupt
|
753
748
|
return _lg_interrupt(value)
|
754
749
|
def create_resume_command(lg_humanloop: LangGraphAdapter = default_adapter) -> Any:
|
@@ -770,18 +765,21 @@ def create_resume_command(lg_humanloop: LangGraphAdapter = default_adapter) -> A
|
|
770
765
|
)
|
771
766
|
|
772
767
|
# Define async polling function
|
773
|
-
|
768
|
+
def poll_for_result():
|
774
769
|
poll_interval = 1.0 # Polling interval (seconds)
|
775
770
|
while True:
|
776
|
-
result =
|
771
|
+
result = lg_humanloop.manager.check_conversation_status(default_conversation_id)
|
772
|
+
print(result)
|
777
773
|
# If status is final state (not PENDING), return result
|
778
774
|
if result.status != HumanLoopStatus.PENDING:
|
779
775
|
return result.response
|
780
776
|
# Wait before polling again
|
781
|
-
|
777
|
+
time.sleep(poll_interval)
|
782
778
|
|
783
779
|
# Wait for async result synchronously
|
784
|
-
|
780
|
+
# loop = asyncio.get_event_loop() # In synchronous environment
|
781
|
+
|
782
|
+
response = poll_for_result()
|
785
783
|
return _lg_Command(resume=response)
|
786
784
|
|
787
785
|
async def acreate_resume_command(lg_humanloop: LangGraphAdapter = default_adapter) -> Any:
|
@@ -806,7 +804,7 @@ async def acreate_resume_command(lg_humanloop: LangGraphAdapter = default_adapte
|
|
806
804
|
async def poll_for_result():
|
807
805
|
poll_interval = 1.0 # Polling interval (seconds)
|
808
806
|
while True:
|
809
|
-
result = await lg_humanloop.manager.
|
807
|
+
result = await lg_humanloop.manager.async_check_conversation_status(default_conversation_id)
|
810
808
|
# If status is final state (not PENDING), return result
|
811
809
|
if result.status != HumanLoopStatus.PENDING:
|
812
810
|
return result.response
|