gohumanloop 0.0.4__tar.gz → 0.0.5__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.
Files changed (35) hide show
  1. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/PKG-INFO +1 -1
  2. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/__init__.py +11 -3
  3. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/adapters/langgraph_adapter.py +17 -13
  4. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/core/manager.py +24 -111
  5. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/PKG-INFO +1 -1
  6. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/pyproject.toml +1 -1
  7. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/LICENSE +0 -0
  8. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/README.md +0 -0
  9. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/__main__.py +0 -0
  10. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/adapters/__init__.py +0 -0
  11. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/cli/__init__.py +0 -0
  12. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/cli/main.py +0 -0
  13. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/core/__init__.py +0 -0
  14. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/core/interface.py +0 -0
  15. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/manager/__init__.py +0 -0
  16. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/manager/ghl_manager.py +0 -0
  17. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/models/__init__.py +0 -0
  18. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/models/api_model.py +0 -0
  19. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/models/glh_model.py +0 -0
  20. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/__init__.py +0 -0
  21. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/api_provider.py +0 -0
  22. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/base.py +0 -0
  23. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/email_provider.py +0 -0
  24. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/ghl_provider.py +0 -0
  25. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/providers/terminal_provider.py +0 -0
  26. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/utils/__init__.py +0 -0
  27. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/utils/context_formatter.py +0 -0
  28. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/utils/threadsafedict.py +0 -0
  29. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop/utils/utils.py +0 -0
  30. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/SOURCES.txt +0 -0
  31. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/dependency_links.txt +0 -0
  32. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/entry_points.txt +0 -0
  33. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/requires.txt +0 -0
  34. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/gohumanloop.egg-info/top_level.txt +0 -0
  35. {gohumanloop-0.0.4 → gohumanloop-0.0.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gohumanloop
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: Perfecting AI workflows with human intelligence
5
5
  Author-email: gohumanloop authors <baird0917@163.com>
6
6
  Project-URL: repository, https://github.com/ptonlix/gohumanloop
@@ -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
- import logging
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
- lg_humanloop.manager.request_humanloop(
743
- task_id="lg_interrupt",
744
- conversation_id=default_conversation_id,
745
- loop_type=HumanLoopType.INFORMATION,
746
- context={
747
- "message": f"{value}",
748
- "question": "The execution has been interrupted. Please review the above information and provide your input to continue.",
749
- },
750
- blocking=False,
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
@@ -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
- loop = asyncio.get_event_loop()
154
- if loop.is_running():
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
- finally:
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
- loop = asyncio.get_event_loop()
271
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
338
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
398
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
460
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
551
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
586
- if loop.is_running():
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
- loop = asyncio.get_event_loop()
608
- if loop.is_running():
609
- # 如果事件循环已经在运行,创建一个新的事件循环
610
- new_loop = asyncio.new_event_loop()
611
- asyncio.set_event_loop(new_loop)
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
- loop = asyncio.get_event_loop()
639
- if loop.is_running():
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gohumanloop
3
- Version: 0.0.4
3
+ Version: 0.0.5
4
4
  Summary: Perfecting AI workflows with human intelligence
5
5
  Author-email: gohumanloop authors <baird0917@163.com>
6
6
  Project-URL: repository, https://github.com/ptonlix/gohumanloop
@@ -3,7 +3,7 @@ authors = [
3
3
  {name = "gohumanloop authors", email = "baird0917@163.com"},
4
4
  ]
5
5
  name = "gohumanloop"
6
- version = "0.0.4"
6
+ version = "0.0.5"
7
7
  description = "Perfecting AI workflows with human intelligence"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.10"
File without changes
File without changes
File without changes