aip-agents-binary 0.5.21__py3-none-macosx_13_0_arm64.whl → 0.6.8__py3-none-macosx_13_0_arm64.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.
- aip_agents/agent/__init__.py +44 -4
- aip_agents/agent/base_langgraph_agent.py +169 -74
- aip_agents/agent/base_langgraph_agent.pyi +3 -2
- aip_agents/agent/langgraph_memory_enhancer_agent.py +368 -34
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +3 -2
- aip_agents/agent/langgraph_react_agent.py +424 -35
- aip_agents/agent/langgraph_react_agent.pyi +46 -2
- aip_agents/examples/{hello_world_langgraph_bosa_twitter.py → hello_world_langgraph_gl_connector_twitter.py} +10 -7
- aip_agents/examples/hello_world_langgraph_gl_connector_twitter.pyi +5 -0
- aip_agents/examples/hello_world_ptc.py +49 -0
- aip_agents/examples/hello_world_ptc.pyi +5 -0
- aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
- aip_agents/examples/hello_world_ptc_custom_tools.pyi +7 -0
- aip_agents/examples/hello_world_sentry.py +2 -2
- aip_agents/examples/hello_world_tool_output_client.py +9 -0
- aip_agents/examples/tools/multiply_tool.py +43 -0
- aip_agents/examples/tools/multiply_tool.pyi +18 -0
- aip_agents/guardrails/__init__.py +83 -0
- aip_agents/guardrails/__init__.pyi +6 -0
- aip_agents/guardrails/engines/__init__.py +69 -0
- aip_agents/guardrails/engines/__init__.pyi +4 -0
- aip_agents/guardrails/engines/base.py +90 -0
- aip_agents/guardrails/engines/base.pyi +61 -0
- aip_agents/guardrails/engines/nemo.py +101 -0
- aip_agents/guardrails/engines/nemo.pyi +46 -0
- aip_agents/guardrails/engines/phrase_matcher.py +113 -0
- aip_agents/guardrails/engines/phrase_matcher.pyi +48 -0
- aip_agents/guardrails/exceptions.py +39 -0
- aip_agents/guardrails/exceptions.pyi +23 -0
- aip_agents/guardrails/manager.py +163 -0
- aip_agents/guardrails/manager.pyi +42 -0
- aip_agents/guardrails/middleware.py +199 -0
- aip_agents/guardrails/middleware.pyi +87 -0
- aip_agents/guardrails/schemas.py +63 -0
- aip_agents/guardrails/schemas.pyi +43 -0
- aip_agents/guardrails/utils.py +45 -0
- aip_agents/guardrails/utils.pyi +19 -0
- aip_agents/mcp/client/__init__.py +38 -2
- aip_agents/mcp/client/connection_manager.py +36 -1
- aip_agents/mcp/client/connection_manager.pyi +3 -0
- aip_agents/mcp/client/persistent_session.py +318 -65
- aip_agents/mcp/client/persistent_session.pyi +9 -0
- aip_agents/mcp/client/transports.py +52 -4
- aip_agents/mcp/client/transports.pyi +9 -0
- aip_agents/memory/adapters/base_adapter.py +98 -0
- aip_agents/memory/adapters/base_adapter.pyi +25 -0
- aip_agents/middleware/base.py +8 -0
- aip_agents/middleware/base.pyi +4 -0
- aip_agents/middleware/manager.py +22 -0
- aip_agents/middleware/manager.pyi +4 -0
- aip_agents/ptc/__init__.py +87 -0
- aip_agents/ptc/__init__.pyi +14 -0
- aip_agents/ptc/custom_tools.py +473 -0
- aip_agents/ptc/custom_tools.pyi +184 -0
- aip_agents/ptc/custom_tools_payload.py +400 -0
- aip_agents/ptc/custom_tools_payload.pyi +31 -0
- aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
- aip_agents/ptc/custom_tools_templates/__init__.pyi +0 -0
- aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +23 -0
- aip_agents/ptc/custom_tools_templates/custom_init.py.template +15 -0
- aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +60 -0
- aip_agents/ptc/custom_tools_templates/custom_registry.py.template +87 -0
- aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
- aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +19 -0
- aip_agents/ptc/doc_gen.py +122 -0
- aip_agents/ptc/doc_gen.pyi +40 -0
- aip_agents/ptc/exceptions.py +57 -0
- aip_agents/ptc/exceptions.pyi +37 -0
- aip_agents/ptc/executor.py +261 -0
- aip_agents/ptc/executor.pyi +99 -0
- aip_agents/ptc/mcp/__init__.py +45 -0
- aip_agents/ptc/mcp/__init__.pyi +7 -0
- aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
- aip_agents/ptc/mcp/sandbox_bridge.pyi +47 -0
- aip_agents/ptc/mcp/templates/__init__.py +1 -0
- aip_agents/ptc/mcp/templates/__init__.pyi +0 -0
- aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
- aip_agents/ptc/naming.py +196 -0
- aip_agents/ptc/naming.pyi +85 -0
- aip_agents/ptc/payload.py +26 -0
- aip_agents/ptc/payload.pyi +15 -0
- aip_agents/ptc/prompt_builder.py +673 -0
- aip_agents/ptc/prompt_builder.pyi +59 -0
- aip_agents/ptc/ptc_helper.py +16 -0
- aip_agents/ptc/ptc_helper.pyi +1 -0
- aip_agents/ptc/sandbox_bridge.py +256 -0
- aip_agents/ptc/sandbox_bridge.pyi +38 -0
- aip_agents/ptc/template_utils.py +33 -0
- aip_agents/ptc/template_utils.pyi +13 -0
- aip_agents/ptc/templates/__init__.py +1 -0
- aip_agents/ptc/templates/__init__.pyi +0 -0
- aip_agents/ptc/templates/ptc_helper.py.template +134 -0
- aip_agents/ptc/tool_def_helpers.py +101 -0
- aip_agents/ptc/tool_def_helpers.pyi +38 -0
- aip_agents/ptc/tool_enrichment.py +163 -0
- aip_agents/ptc/tool_enrichment.pyi +60 -0
- aip_agents/sandbox/__init__.py +43 -0
- aip_agents/sandbox/__init__.pyi +5 -0
- aip_agents/sandbox/defaults.py +205 -0
- aip_agents/sandbox/defaults.pyi +30 -0
- aip_agents/sandbox/e2b_runtime.py +295 -0
- aip_agents/sandbox/e2b_runtime.pyi +57 -0
- aip_agents/sandbox/template_builder.py +131 -0
- aip_agents/sandbox/template_builder.pyi +36 -0
- aip_agents/sandbox/types.py +24 -0
- aip_agents/sandbox/types.pyi +14 -0
- aip_agents/sandbox/validation.py +50 -0
- aip_agents/sandbox/validation.pyi +20 -0
- aip_agents/sentry/__init__.py +1 -1
- aip_agents/sentry/sentry.py +33 -12
- aip_agents/sentry/sentry.pyi +5 -4
- aip_agents/tools/__init__.py +20 -3
- aip_agents/tools/__init__.pyi +4 -2
- aip_agents/tools/browser_use/browser_use_tool.py +8 -0
- aip_agents/tools/browser_use/streaming.py +2 -0
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.py +80 -31
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +25 -9
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.py +6 -6
- aip_agents/tools/constants.py +24 -12
- aip_agents/tools/constants.pyi +14 -11
- aip_agents/tools/date_range_tool.py +554 -0
- aip_agents/tools/date_range_tool.pyi +21 -0
- aip_agents/tools/execute_ptc_code.py +357 -0
- aip_agents/tools/execute_ptc_code.pyi +90 -0
- aip_agents/tools/gl_connector/__init__.py +1 -1
- aip_agents/tools/gl_connector/tool.py +62 -30
- aip_agents/tools/gl_connector/tool.pyi +3 -3
- aip_agents/tools/gl_connector_tools.py +119 -0
- aip_agents/tools/gl_connector_tools.pyi +39 -0
- aip_agents/tools/memory_search/__init__.py +8 -1
- aip_agents/tools/memory_search/__init__.pyi +3 -3
- aip_agents/tools/memory_search/mem0.py +114 -1
- aip_agents/tools/memory_search/mem0.pyi +11 -1
- aip_agents/tools/memory_search/schema.py +33 -0
- aip_agents/tools/memory_search/schema.pyi +10 -0
- aip_agents/tools/memory_search_tool.py +8 -0
- aip_agents/tools/memory_search_tool.pyi +2 -2
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +26 -1
- aip_agents/utils/langgraph/tool_output_management.py +80 -0
- aip_agents/utils/langgraph/tool_output_management.pyi +37 -0
- {aip_agents_binary-0.5.21.dist-info → aip_agents_binary-0.6.8.dist-info}/METADATA +14 -22
- {aip_agents_binary-0.5.21.dist-info → aip_agents_binary-0.6.8.dist-info}/RECORD +144 -58
- {aip_agents_binary-0.5.21.dist-info → aip_agents_binary-0.6.8.dist-info}/WHEEL +1 -1
- aip_agents/examples/demo_memory_recall.py +0 -401
- aip_agents/examples/demo_memory_recall.pyi +0 -58
- aip_agents/examples/hello_world_langgraph_bosa_twitter.pyi +0 -5
- aip_agents/tools/bosa_tools.py +0 -105
- aip_agents/tools/bosa_tools.pyi +0 -37
- {aip_agents_binary-0.5.21.dist-info → aip_agents_binary-0.6.8.dist-info}/top_level.txt +0 -0
aip_agents/sentry/sentry.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""This file contains the Sentry and OpenTelemetry configuration for
|
|
1
|
+
"""This file contains the Sentry and OpenTelemetry configuration for GL Connectors SDK.
|
|
2
2
|
|
|
3
3
|
Authors:
|
|
4
4
|
Saul Sayers (saul.sayers@gdplabs.id)
|
|
@@ -6,6 +6,7 @@ Authors:
|
|
|
6
6
|
|
|
7
7
|
import inspect
|
|
8
8
|
import os
|
|
9
|
+
from typing import Any
|
|
9
10
|
|
|
10
11
|
from bosa_core.telemetry import (
|
|
11
12
|
FastAPIConfig,
|
|
@@ -20,7 +21,7 @@ from bosa_core.telemetry.opentelemetry.instrument.functions import (
|
|
|
20
21
|
from dotenv import load_dotenv
|
|
21
22
|
from fastapi import FastAPI
|
|
22
23
|
|
|
23
|
-
from aip_agents.agent import BaseAgent,
|
|
24
|
+
from aip_agents.agent import BaseAgent, LangChainAgent, LangGraphAgent
|
|
24
25
|
from aip_agents.utils.logger import get_logger
|
|
25
26
|
|
|
26
27
|
load_dotenv()
|
|
@@ -35,12 +36,32 @@ VERSION_NUMBER = os.getenv("VERSION_NUMBER", "0.0.0")
|
|
|
35
36
|
BUILD_NUMBER = os.getenv("BUILD_NUMBER", "0")
|
|
36
37
|
USE_OPENTELEMETRY = os.getenv("USE_OPENTELEMETRY", "true").lower() == "true"
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
# Lazy import of GoogleADKAgent to avoid heavy dependencies when not needed.
|
|
40
|
+
# This is initialized lazily by _get_classes_to_instrument() and can be
|
|
41
|
+
# patched by tests for mocking purposes.
|
|
42
|
+
CLASSES_TO_INSTRUMENT: list[type[Any]] | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _get_classes_to_instrument() -> list[type[Any]]:
|
|
46
|
+
"""Get the list of classes to instrument.
|
|
47
|
+
|
|
48
|
+
This lazily imports GoogleADKAgent only when telemetry is being set up,
|
|
49
|
+
avoiding the heavy Google ADK dependencies during module import.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
List of agent classes to instrument.
|
|
53
|
+
"""
|
|
54
|
+
global CLASSES_TO_INSTRUMENT
|
|
55
|
+
if CLASSES_TO_INSTRUMENT is None:
|
|
56
|
+
from aip_agents.agent import GoogleADKAgent
|
|
57
|
+
|
|
58
|
+
CLASSES_TO_INSTRUMENT = [
|
|
59
|
+
BaseAgent,
|
|
60
|
+
LangGraphAgent,
|
|
61
|
+
LangChainAgent,
|
|
62
|
+
GoogleADKAgent,
|
|
63
|
+
]
|
|
64
|
+
return CLASSES_TO_INSTRUMENT
|
|
44
65
|
|
|
45
66
|
|
|
46
67
|
def get_all_methods(cls: type) -> list:
|
|
@@ -61,12 +82,12 @@ def get_all_methods(cls: type) -> list:
|
|
|
61
82
|
return methods
|
|
62
83
|
|
|
63
84
|
|
|
64
|
-
def
|
|
65
|
-
"""Instrument
|
|
85
|
+
def instrument_gl_functions() -> None:
|
|
86
|
+
"""Instrument GL functions."""
|
|
66
87
|
if BOSAFunctionsInstrumentor is None:
|
|
67
88
|
return
|
|
68
89
|
agent_methods = []
|
|
69
|
-
for cls in
|
|
90
|
+
for cls in _get_classes_to_instrument():
|
|
70
91
|
agent_methods.extend(get_all_methods(cls))
|
|
71
92
|
BOSAFunctionsInstrumentor().instrument(methods=agent_methods)
|
|
72
93
|
|
|
@@ -148,4 +169,4 @@ def setup_telemetry(app: FastAPI) -> None:
|
|
|
148
169
|
setup_sentry_with_open_telemetry(app)
|
|
149
170
|
else:
|
|
150
171
|
setup_sentry_only()
|
|
151
|
-
|
|
172
|
+
instrument_gl_functions()
|
aip_agents/sentry/sentry.pyi
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from _typeshed import Incomplete
|
|
2
|
-
from aip_agents.agent import BaseAgent as BaseAgent,
|
|
2
|
+
from aip_agents.agent import BaseAgent as BaseAgent, LangChainAgent as LangChainAgent, LangGraphAgent as LangGraphAgent
|
|
3
3
|
from aip_agents.utils.logger import get_logger as get_logger
|
|
4
4
|
from fastapi import FastAPI
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
logger: Incomplete
|
|
7
8
|
SENTRY_DSN: Incomplete
|
|
@@ -10,7 +11,7 @@ SENTRY_PROJECT: Incomplete
|
|
|
10
11
|
VERSION_NUMBER: Incomplete
|
|
11
12
|
BUILD_NUMBER: Incomplete
|
|
12
13
|
USE_OPENTELEMETRY: Incomplete
|
|
13
|
-
CLASSES_TO_INSTRUMENT:
|
|
14
|
+
CLASSES_TO_INSTRUMENT: list[type[Any]] | None
|
|
14
15
|
|
|
15
16
|
def get_all_methods(cls) -> list:
|
|
16
17
|
"""Get all methods from a class.
|
|
@@ -21,8 +22,8 @@ def get_all_methods(cls) -> list:
|
|
|
21
22
|
Returns:
|
|
22
23
|
list: A list of methods.
|
|
23
24
|
"""
|
|
24
|
-
def
|
|
25
|
-
"""Instrument
|
|
25
|
+
def instrument_gl_functions() -> None:
|
|
26
|
+
"""Instrument GL functions."""
|
|
26
27
|
def traces_sampler(*args) -> float:
|
|
27
28
|
"""Determine appropriate sampling rate for Sentry transactions.
|
|
28
29
|
|
aip_agents/tools/__init__.py
CHANGED
|
@@ -3,15 +3,26 @@
|
|
|
3
3
|
from importlib import import_module
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
|
-
from aip_agents.tools.
|
|
6
|
+
from aip_agents.tools.date_range_tool import DateRangeTool
|
|
7
7
|
from aip_agents.tools.gl_connector import GLConnectorTool
|
|
8
|
+
from aip_agents.tools.gl_connector_tools import (
|
|
9
|
+
BOSA_AUTOMATED_TOOLS,
|
|
10
|
+
GL_CONNECTORS_AUTOMATED_TOOLS,
|
|
11
|
+
)
|
|
8
12
|
from aip_agents.tools.time_tool import TimeTool
|
|
9
13
|
from aip_agents.tools.web_search import GoogleSerperTool
|
|
10
14
|
from aip_agents.utils.logger import get_logger
|
|
11
15
|
|
|
12
16
|
logger = get_logger(__name__)
|
|
13
17
|
|
|
14
|
-
__all__ = [
|
|
18
|
+
__all__ = [
|
|
19
|
+
"BOSA_AUTOMATED_TOOLS",
|
|
20
|
+
"GL_CONNECTORS_AUTOMATED_TOOLS",
|
|
21
|
+
"GLConnectorTool",
|
|
22
|
+
"GoogleSerperTool",
|
|
23
|
+
"TimeTool",
|
|
24
|
+
"DateRangeTool",
|
|
25
|
+
]
|
|
15
26
|
|
|
16
27
|
|
|
17
28
|
def _register_optional(module_path: str, export_name: str) -> None:
|
|
@@ -40,8 +51,14 @@ _register_optional("aip_agents.tools.code_sandbox", "E2BCodeSandboxTool")
|
|
|
40
51
|
_register_optional("aip_agents.tools.document_loader", "DocxReaderTool")
|
|
41
52
|
_register_optional("aip_agents.tools.document_loader", "ExcelReaderTool")
|
|
42
53
|
_register_optional("aip_agents.tools.document_loader", "PDFReaderTool")
|
|
54
|
+
_register_optional("aip_agents.tools.execute_ptc_code", "create_execute_ptc_code_tool")
|
|
43
55
|
|
|
44
56
|
if TYPE_CHECKING:
|
|
45
57
|
from aip_agents.tools.browser_use import BrowserUseTool
|
|
46
58
|
from aip_agents.tools.code_sandbox import E2BCodeSandboxTool
|
|
47
|
-
from aip_agents.tools.document_loader import
|
|
59
|
+
from aip_agents.tools.document_loader import (
|
|
60
|
+
DocxReaderTool,
|
|
61
|
+
ExcelReaderTool,
|
|
62
|
+
PDFReaderTool,
|
|
63
|
+
)
|
|
64
|
+
from aip_agents.tools.execute_ptc_code import create_execute_ptc_code_tool
|
aip_agents/tools/__init__.pyi
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
from aip_agents.tools.bosa_tools import BOSA_AUTOMATED_TOOLS as BOSA_AUTOMATED_TOOLS
|
|
2
1
|
from aip_agents.tools.browser_use import BrowserUseTool as BrowserUseTool
|
|
3
2
|
from aip_agents.tools.code_sandbox import E2BCodeSandboxTool as E2BCodeSandboxTool
|
|
3
|
+
from aip_agents.tools.date_range_tool import DateRangeTool as DateRangeTool
|
|
4
4
|
from aip_agents.tools.document_loader import DocxReaderTool as DocxReaderTool, ExcelReaderTool as ExcelReaderTool, PDFReaderTool as PDFReaderTool
|
|
5
|
+
from aip_agents.tools.execute_ptc_code import create_execute_ptc_code_tool as create_execute_ptc_code_tool
|
|
5
6
|
from aip_agents.tools.gl_connector import GLConnectorTool as GLConnectorTool
|
|
7
|
+
from aip_agents.tools.gl_connector_tools import BOSA_AUTOMATED_TOOLS as BOSA_AUTOMATED_TOOLS, GL_CONNECTORS_AUTOMATED_TOOLS as GL_CONNECTORS_AUTOMATED_TOOLS
|
|
6
8
|
from aip_agents.tools.time_tool import TimeTool as TimeTool
|
|
7
9
|
from aip_agents.tools.web_search import GoogleSerperTool as GoogleSerperTool
|
|
8
10
|
|
|
9
|
-
__all__ = ['BOSA_AUTOMATED_TOOLS', 'GLConnectorTool', 'GoogleSerperTool', 'TimeTool', 'BrowserUseTool', 'E2BCodeSandboxTool', 'DocxReaderTool', 'ExcelReaderTool', 'PDFReaderTool']
|
|
11
|
+
__all__ = ['BOSA_AUTOMATED_TOOLS', 'GL_CONNECTORS_AUTOMATED_TOOLS', 'GLConnectorTool', 'GoogleSerperTool', 'TimeTool', 'DateRangeTool', 'BrowserUseTool', 'E2BCodeSandboxTool', 'DocxReaderTool', 'ExcelReaderTool', 'PDFReaderTool', 'create_execute_ptc_code_tool']
|
|
@@ -93,6 +93,7 @@ References:
|
|
|
93
93
|
"""
|
|
94
94
|
|
|
95
95
|
import asyncio
|
|
96
|
+
import copy
|
|
96
97
|
import json
|
|
97
98
|
from collections.abc import Callable
|
|
98
99
|
from typing import Any, Literal
|
|
@@ -556,13 +557,20 @@ class BrowserUseTool(BaseTool):
|
|
|
556
557
|
iframe_event = yield_iframe_activity(streaming_state.debug_url, "Receive streaming URL")
|
|
557
558
|
self._log_stream_event("iframe_start", iframe_event)
|
|
558
559
|
yield iframe_event
|
|
560
|
+
last_done_event: dict | None = None
|
|
559
561
|
async for event in self._stream_agent_with_markers(agent, streaming_state, recorder):
|
|
560
562
|
self._log_stream_event("agent_event", event)
|
|
563
|
+
tool_info = event.get("tool_info") if isinstance(event, dict) else None
|
|
564
|
+
tool_calls = tool_info.get("tool_calls", []) if isinstance(tool_info, dict) else []
|
|
565
|
+
if any(call.get("name") == "done" for call in tool_calls if isinstance(call, dict)):
|
|
566
|
+
last_done_event = event
|
|
561
567
|
yield event
|
|
562
568
|
recording_event = self._recording_event(streaming_state)
|
|
563
569
|
if recording_event:
|
|
564
570
|
self._log_stream_event("recording_event", recording_event)
|
|
565
571
|
yield recording_event
|
|
572
|
+
if last_done_event:
|
|
573
|
+
yield copy.deepcopy(last_done_event)
|
|
566
574
|
finally:
|
|
567
575
|
await self._release_session(session, client)
|
|
568
576
|
|
|
@@ -223,6 +223,8 @@ def create_step_response(
|
|
|
223
223
|
if is_done:
|
|
224
224
|
final_tool = _get_done_tool_for_final_response(agent, tool_calls_dict)
|
|
225
225
|
final_output = final_tool.get("output") or TASK_COMPLETED_MESSAGE
|
|
226
|
+
if not any(call.get("name") == "done" for call in tool_calls_dict):
|
|
227
|
+
tool_calls_dict.append(final_tool)
|
|
226
228
|
tool_info = {
|
|
227
229
|
"name": PRIMARY_TOOL_NAME,
|
|
228
230
|
"args": final_tool.get("args", {}),
|
|
@@ -11,12 +11,10 @@ from http import HTTPStatus
|
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
13
|
import requests
|
|
14
|
+
from e2b_code_interpreter import Sandbox
|
|
14
15
|
from gllm_inference.schema import Attachment
|
|
15
|
-
from gllm_tools.code_interpreter.code_sandbox.
|
|
16
|
-
from gllm_tools.code_interpreter.code_sandbox.models import
|
|
17
|
-
ExecutionResult,
|
|
18
|
-
ExecutionStatus,
|
|
19
|
-
)
|
|
16
|
+
from gllm_tools.code_interpreter.code_sandbox.e2b_sandbox import E2BSandbox
|
|
17
|
+
from gllm_tools.code_interpreter.code_sandbox.models import ExecutionResult, ExecutionStatus
|
|
20
18
|
from gllm_tools.code_interpreter.code_sandbox.utils import calculate_duration_ms
|
|
21
19
|
|
|
22
20
|
from aip_agents.tools.code_sandbox.constant import DATA_FILE_PATH
|
|
@@ -123,19 +121,57 @@ class SandboxFileWatcher:
|
|
|
123
121
|
return self._created_files.copy()
|
|
124
122
|
|
|
125
123
|
|
|
126
|
-
class MyE2BCloudSandbox(
|
|
127
|
-
"""Extended E2B
|
|
124
|
+
class MyE2BCloudSandbox(E2BSandbox):
|
|
125
|
+
"""Extended E2B sandbox with filesystem monitoring capabilities.
|
|
128
126
|
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
Use `create()` in production to build a fully initialized sandbox wrapper.
|
|
128
|
+
Direct construction is intentionally blocked to prevent partially initialized
|
|
129
|
+
instances that lack the underlying E2B sandbox clients.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
def __init__(self, language: str = "python", *, _unsafe_allow_init: bool = False) -> None:
|
|
133
|
+
"""Initialize the sandbox wrapper.
|
|
131
134
|
|
|
132
135
|
Args:
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
language (str): Language to execute inside the sandbox.
|
|
137
|
+
_unsafe_allow_init (bool): Escape hatch for tests/mocks only.
|
|
138
|
+
|
|
139
|
+
Raises:
|
|
140
|
+
RuntimeError: When instantiated directly without `create()`.
|
|
135
141
|
"""
|
|
136
|
-
|
|
142
|
+
if not _unsafe_allow_init:
|
|
143
|
+
raise RuntimeError("Use MyE2BCloudSandbox.create(...) to initialize a sandbox instance.")
|
|
144
|
+
super().__init__(language=language)
|
|
137
145
|
self.file_watcher: SandboxFileWatcher | None = None
|
|
138
146
|
|
|
147
|
+
@classmethod
|
|
148
|
+
async def create(
|
|
149
|
+
cls,
|
|
150
|
+
api_key: str,
|
|
151
|
+
domain: str | None = None,
|
|
152
|
+
template: str | None = None,
|
|
153
|
+
language: str = "python",
|
|
154
|
+
additional_packages: list[str] | None = None,
|
|
155
|
+
**kwargs: Any,
|
|
156
|
+
) -> "MyE2BCloudSandbox":
|
|
157
|
+
"""Create a fully initialized sandbox wrapper.
|
|
158
|
+
|
|
159
|
+
This is the supported construction path for production usage. It wires
|
|
160
|
+
the E2B sandbox instance and its filesystem/command clients, then
|
|
161
|
+
installs language dependencies.
|
|
162
|
+
"""
|
|
163
|
+
sandbox = Sandbox.create(api_key=api_key, domain=domain, template=template, **kwargs)
|
|
164
|
+
|
|
165
|
+
instance = cls(language=language, _unsafe_allow_init=True)
|
|
166
|
+
instance.sandbox = sandbox
|
|
167
|
+
instance.files = sandbox.files
|
|
168
|
+
instance.commands = sandbox.commands
|
|
169
|
+
instance.additional_packages = additional_packages or []
|
|
170
|
+
|
|
171
|
+
instance._install_language_dependencies()
|
|
172
|
+
|
|
173
|
+
return instance
|
|
174
|
+
|
|
139
175
|
async def execute_code(
|
|
140
176
|
self,
|
|
141
177
|
code: str,
|
|
@@ -161,11 +197,10 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
161
197
|
Raises:
|
|
162
198
|
RuntimeError: If sandbox is not initialized.
|
|
163
199
|
"""
|
|
164
|
-
if not self.sandbox:
|
|
200
|
+
if not self.sandbox or not self.files or not self.commands:
|
|
165
201
|
raise RuntimeError("Sandbox is not initialized")
|
|
166
202
|
|
|
167
203
|
start_time = time.time()
|
|
168
|
-
|
|
169
204
|
try:
|
|
170
205
|
# Initialize filesystem monitoring
|
|
171
206
|
self.file_watcher = SandboxFileWatcher(self.sandbox)
|
|
@@ -176,8 +211,12 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
176
211
|
# Pre-populate the variable `df` for direct use in the code
|
|
177
212
|
if files:
|
|
178
213
|
logger.info("Pre-populating the variable `df` with the data from the file.")
|
|
179
|
-
self.sandbox.run_code(
|
|
180
|
-
|
|
214
|
+
self.sandbox.run_code(
|
|
215
|
+
f"import pandas as pd; df = pd.read_csv('{DATA_FILE_PATH}')",
|
|
216
|
+
language=self.language,
|
|
217
|
+
timeout=timeout,
|
|
218
|
+
)
|
|
219
|
+
execution = self.sandbox.run_code(code, language=self.language, timeout=timeout)
|
|
181
220
|
duration_ms = calculate_duration_ms(start_time)
|
|
182
221
|
status = ExecutionStatus.ERROR if execution.error else ExecutionStatus.SUCCESS
|
|
183
222
|
|
|
@@ -191,8 +230,8 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
191
230
|
return ExecutionResult.create(
|
|
192
231
|
status=status,
|
|
193
232
|
code=code,
|
|
194
|
-
stdout=(execution.logs.stdout
|
|
195
|
-
stderr=(execution.logs.stderr
|
|
233
|
+
stdout=("\n".join(execution.logs.stdout) if execution.logs and execution.logs.stdout else ""),
|
|
234
|
+
stderr=("\n".join(execution.logs.stderr) if execution.logs and execution.logs.stderr else ""),
|
|
196
235
|
error=(str(execution.error) if execution.error else ""), # Convert to string here
|
|
197
236
|
duration_ms=duration_ms,
|
|
198
237
|
)
|
|
@@ -218,8 +257,8 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
218
257
|
def download_file(self, file_path: str) -> bytes | None:
|
|
219
258
|
"""Download file content from the sandbox.
|
|
220
259
|
|
|
221
|
-
Uses download_url
|
|
222
|
-
|
|
260
|
+
Uses download_url when available to avoid binary corruption issues.
|
|
261
|
+
Falls back to the filesystem API when download_url fails or is unavailable.
|
|
223
262
|
|
|
224
263
|
Args:
|
|
225
264
|
file_path (str): Path to the file in the sandbox.
|
|
@@ -237,18 +276,28 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
237
276
|
if hasattr(self.sandbox, "download_url"):
|
|
238
277
|
logger.info(f"Downloading {file_path} via download_url method")
|
|
239
278
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
response = requests.get(url, timeout=30)
|
|
245
|
-
|
|
246
|
-
if response.status_code == HTTPStatus.OK:
|
|
247
|
-
content = response.content
|
|
248
|
-
logger.info(f"Successfully downloaded {len(content)} bytes via URL")
|
|
249
|
-
return content
|
|
279
|
+
try:
|
|
280
|
+
url = self.sandbox.download_url(file_path)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logger.warning(f"Failed to get download URL: {str(e)}")
|
|
250
283
|
else:
|
|
251
|
-
logger.
|
|
284
|
+
logger.debug(f"Got download URL: {url}")
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
response = requests.get(url, timeout=30)
|
|
288
|
+
except Exception as e:
|
|
289
|
+
logger.warning(f"URL download failed with error: {str(e)}")
|
|
290
|
+
else:
|
|
291
|
+
if response.status_code == HTTPStatus.OK:
|
|
292
|
+
content = response.content
|
|
293
|
+
logger.info(f"Successfully downloaded {len(content)} bytes via URL")
|
|
294
|
+
return content
|
|
295
|
+
logger.warning(f"URL download failed with status {response.status_code}")
|
|
296
|
+
|
|
297
|
+
if self.files:
|
|
298
|
+
logger.info(f"Downloading {file_path} via filesystem API")
|
|
299
|
+
content = self.files.read(file_path, format="bytes")
|
|
300
|
+
return bytes(content)
|
|
252
301
|
|
|
253
302
|
return None
|
|
254
303
|
|
|
@@ -2,7 +2,7 @@ from _typeshed import Incomplete
|
|
|
2
2
|
from aip_agents.tools.code_sandbox.constant import DATA_FILE_PATH as DATA_FILE_PATH
|
|
3
3
|
from aip_agents.utils.logger import get_logger as get_logger
|
|
4
4
|
from gllm_inference.schema import Attachment as Attachment
|
|
5
|
-
from gllm_tools.code_interpreter.code_sandbox.
|
|
5
|
+
from gllm_tools.code_interpreter.code_sandbox.e2b_sandbox import E2BSandbox
|
|
6
6
|
from gllm_tools.code_interpreter.code_sandbox.models import ExecutionResult
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
@@ -34,15 +34,31 @@ class SandboxFileWatcher:
|
|
|
34
34
|
list[str]: List of file paths that were created.
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
class MyE2BCloudSandbox(
|
|
38
|
-
"""Extended E2B
|
|
37
|
+
class MyE2BCloudSandbox(E2BSandbox):
|
|
38
|
+
"""Extended E2B sandbox with filesystem monitoring capabilities.
|
|
39
|
+
|
|
40
|
+
Use `create()` in production to build a fully initialized sandbox wrapper.
|
|
41
|
+
Direct construction is intentionally blocked to prevent partially initialized
|
|
42
|
+
instances that lack the underlying E2B sandbox clients.
|
|
43
|
+
"""
|
|
39
44
|
file_watcher: SandboxFileWatcher | None
|
|
40
|
-
def __init__(self,
|
|
41
|
-
"""Initialize the sandbox
|
|
45
|
+
def __init__(self, language: str = 'python', *, _unsafe_allow_init: bool = False) -> None:
|
|
46
|
+
"""Initialize the sandbox wrapper.
|
|
42
47
|
|
|
43
48
|
Args:
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
language (str): Language to execute inside the sandbox.
|
|
50
|
+
_unsafe_allow_init (bool): Escape hatch for tests/mocks only.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
RuntimeError: When instantiated directly without `create()`.
|
|
54
|
+
"""
|
|
55
|
+
@classmethod
|
|
56
|
+
async def create(cls, api_key: str, domain: str | None = None, template: str | None = None, language: str = 'python', additional_packages: list[str] | None = None, **kwargs: Any) -> MyE2BCloudSandbox:
|
|
57
|
+
"""Create a fully initialized sandbox wrapper.
|
|
58
|
+
|
|
59
|
+
This is the supported construction path for production usage. It wires
|
|
60
|
+
the E2B sandbox instance and its filesystem/command clients, then
|
|
61
|
+
installs language dependencies.
|
|
46
62
|
"""
|
|
47
63
|
async def execute_code(self, code: str, timeout: int = 30, files: list[Attachment] | None = None, **kwargs: Any) -> ExecutionResult:
|
|
48
64
|
"""Execute code in the E2B Cloud sandbox with filesystem monitoring.
|
|
@@ -72,8 +88,8 @@ class MyE2BCloudSandbox(E2BCloudSandbox):
|
|
|
72
88
|
def download_file(self, file_path: str) -> bytes | None:
|
|
73
89
|
"""Download file content from the sandbox.
|
|
74
90
|
|
|
75
|
-
Uses download_url
|
|
76
|
-
|
|
91
|
+
Uses download_url when available to avoid binary corruption issues.
|
|
92
|
+
Falls back to the filesystem API when download_url fails or is unavailable.
|
|
77
93
|
|
|
78
94
|
Args:
|
|
79
95
|
file_path (str): Path to the file in the sandbox.
|
|
@@ -12,7 +12,7 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
import pandas as pd
|
|
14
14
|
from gllm_inference.schema import Attachment
|
|
15
|
-
from gllm_tools.code_interpreter.code_sandbox.
|
|
15
|
+
from gllm_tools.code_interpreter.code_sandbox.sandbox import BaseSandbox
|
|
16
16
|
from langchain_core.tools import BaseTool
|
|
17
17
|
from langgraph.types import Command
|
|
18
18
|
from pydantic import BaseModel, Field
|
|
@@ -260,7 +260,7 @@ class E2BCodeSandboxTool(BaseTool):
|
|
|
260
260
|
"""
|
|
261
261
|
unique_packages = self._prepare_packages(additional_packages)
|
|
262
262
|
|
|
263
|
-
return MyE2BCloudSandbox(
|
|
263
|
+
return await MyE2BCloudSandbox.create(
|
|
264
264
|
api_key=self.api_key,
|
|
265
265
|
language=language,
|
|
266
266
|
additional_packages=unique_packages,
|
|
@@ -304,11 +304,11 @@ class E2BCodeSandboxTool(BaseTool):
|
|
|
304
304
|
except Exception as e:
|
|
305
305
|
logger.warning(f"Error terminating sandbox: {str(e)}")
|
|
306
306
|
|
|
307
|
-
def _create_artifacts_from_files(self, sandbox:
|
|
307
|
+
def _create_artifacts_from_files(self, sandbox: BaseSandbox, file_paths: list[str]) -> list[dict[str, Any]]:
|
|
308
308
|
"""Create artifacts from a list of file paths using ArtifactHandler.
|
|
309
309
|
|
|
310
310
|
Args:
|
|
311
|
-
sandbox (
|
|
311
|
+
sandbox (BaseSandbox): The active sandbox instance.
|
|
312
312
|
file_paths (list[str]): List of file paths to download.
|
|
313
313
|
|
|
314
314
|
Returns:
|
|
@@ -358,11 +358,11 @@ class E2BCodeSandboxTool(BaseTool):
|
|
|
358
358
|
|
|
359
359
|
return execution_summary
|
|
360
360
|
|
|
361
|
-
def _download_and_create_artifact(self, sandbox:
|
|
361
|
+
def _download_and_create_artifact(self, sandbox: BaseSandbox, file_path: str) -> dict[str, Any] | None:
|
|
362
362
|
"""Download a single file and create an artifact using ArtifactHandler.
|
|
363
363
|
|
|
364
364
|
Args:
|
|
365
|
-
sandbox (
|
|
365
|
+
sandbox (BaseSandbox): The active sandbox instance.
|
|
366
366
|
file_path (str): Path to the file in the sandbox.
|
|
367
367
|
|
|
368
368
|
Returns:
|
aip_agents/tools/constants.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Constants for tools using
|
|
1
|
+
"""Constants for tools using GL Connectors.
|
|
2
2
|
|
|
3
3
|
Authors:
|
|
4
4
|
Saul Sayers (saul.sayers@gdplabs.id)
|
|
@@ -7,20 +7,32 @@ Authors:
|
|
|
7
7
|
import os
|
|
8
8
|
from enum import Enum, StrEnum
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
GL_CONNECTORS_BASE_URL = (
|
|
11
|
+
os.getenv("GL_CONNECTORS_BASE_URL")
|
|
12
|
+
or os.getenv("GL_CONNECTORS_API_BASE_URL")
|
|
13
|
+
or os.getenv("BOSA_API_BASE_URL")
|
|
14
|
+
or os.getenv("BOSA_BASE_URL")
|
|
15
|
+
)
|
|
16
|
+
GL_CONNECTORS_API_KEY = os.getenv("GL_CONNECTORS_API_KEY") or os.getenv("BOSA_API_KEY")
|
|
17
|
+
GL_CONNECTORS_FETCH_MAX_RETRIES = int(
|
|
18
|
+
os.getenv("GL_CONNECTORS_FETCH_MAX_RETRIES") or os.getenv("BOSA_FETCH_MAX_RETRIES") or 3
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# For backward compatibility
|
|
22
|
+
BOSA_API_BASE_URL = GL_CONNECTORS_BASE_URL
|
|
23
|
+
BOSA_API_KEY = GL_CONNECTORS_API_KEY
|
|
24
|
+
BOSA_FETCH_MAX_RETRIES = GL_CONNECTORS_FETCH_MAX_RETRIES
|
|
13
25
|
|
|
14
26
|
|
|
15
27
|
class ToolType(StrEnum):
|
|
16
|
-
"""Tool types for
|
|
28
|
+
"""Tool types for GL Connectors."""
|
|
17
29
|
|
|
18
30
|
GLLM = "gllm"
|
|
19
31
|
LANGCHAIN = "langchain"
|
|
20
32
|
|
|
21
33
|
|
|
22
34
|
class Action(Enum):
|
|
23
|
-
"""Actions for
|
|
35
|
+
"""Actions for GL Connectors."""
|
|
24
36
|
|
|
25
37
|
GITHUB = "github"
|
|
26
38
|
GOOGLE = "google"
|
|
@@ -30,7 +42,7 @@ class Action(Enum):
|
|
|
30
42
|
|
|
31
43
|
|
|
32
44
|
class GitHubEndpoint(Enum):
|
|
33
|
-
"""GitHub endpoints for
|
|
45
|
+
"""GitHub endpoints for GL Connectors."""
|
|
34
46
|
|
|
35
47
|
INTEGRATIONS = "integrations"
|
|
36
48
|
USER_HAS_INTEGRATION = "integration-exists"
|
|
@@ -59,7 +71,7 @@ class GitHubEndpoint(Enum):
|
|
|
59
71
|
|
|
60
72
|
|
|
61
73
|
class GoogleDriveEndpoint(Enum):
|
|
62
|
-
"""Google Drive endpoints for
|
|
74
|
+
"""Google Drive endpoints for GL Connectors."""
|
|
63
75
|
|
|
64
76
|
INTEGRATIONS = "integrations"
|
|
65
77
|
USER_HAS_INTEGRATION = "integration-exists"
|
|
@@ -84,7 +96,7 @@ class GoogleDriveEndpoint(Enum):
|
|
|
84
96
|
|
|
85
97
|
|
|
86
98
|
class GoogleDocsEndpoint(Enum):
|
|
87
|
-
"""Google Docs endpoints for
|
|
99
|
+
"""Google Docs endpoints for GL Connectors."""
|
|
88
100
|
|
|
89
101
|
INTEGRATIONS = "integrations"
|
|
90
102
|
USER_HAS_INTEGRATION = "integration-exists"
|
|
@@ -100,7 +112,7 @@ class GoogleDocsEndpoint(Enum):
|
|
|
100
112
|
|
|
101
113
|
|
|
102
114
|
class GoogleEndpoint(Enum):
|
|
103
|
-
"""Google endpoints for
|
|
115
|
+
"""Google endpoints for GL Connectors."""
|
|
104
116
|
|
|
105
117
|
INTEGRATIONS = "integrations"
|
|
106
118
|
USER_HAS_INTEGRATION = "integration-exists"
|
|
@@ -109,7 +121,7 @@ class GoogleEndpoint(Enum):
|
|
|
109
121
|
|
|
110
122
|
|
|
111
123
|
class TwitterEndpoint(Enum):
|
|
112
|
-
"""Twitter endpoints for
|
|
124
|
+
"""Twitter endpoints for GL Connectors."""
|
|
113
125
|
|
|
114
126
|
INTEGRATIONS = "integrations"
|
|
115
127
|
USER_HAS_INTEGRATION = "integration-exists"
|
|
@@ -121,7 +133,7 @@ class TwitterEndpoint(Enum):
|
|
|
121
133
|
|
|
122
134
|
|
|
123
135
|
class GoogleMailEndpoint(Enum):
|
|
124
|
-
"""Google Mail endpoints for
|
|
136
|
+
"""Google Mail endpoints for GL Connectors."""
|
|
125
137
|
|
|
126
138
|
INTEGRATIONS = "integrations"
|
|
127
139
|
USER_HAS_INTEGRATION = "integration-exists"
|
aip_agents/tools/constants.pyi
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
from _typeshed import Incomplete
|
|
2
2
|
from enum import Enum, StrEnum
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
GL_CONNECTORS_BASE_URL: Incomplete
|
|
5
|
+
GL_CONNECTORS_API_KEY: Incomplete
|
|
6
|
+
GL_CONNECTORS_FETCH_MAX_RETRIES: Incomplete
|
|
7
|
+
BOSA_API_BASE_URL = GL_CONNECTORS_BASE_URL
|
|
8
|
+
BOSA_API_KEY = GL_CONNECTORS_API_KEY
|
|
9
|
+
BOSA_FETCH_MAX_RETRIES = GL_CONNECTORS_FETCH_MAX_RETRIES
|
|
7
10
|
|
|
8
11
|
class ToolType(StrEnum):
|
|
9
|
-
"""Tool types for
|
|
12
|
+
"""Tool types for GL Connectors."""
|
|
10
13
|
GLLM: str
|
|
11
14
|
LANGCHAIN: str
|
|
12
15
|
|
|
13
16
|
class Action(Enum):
|
|
14
|
-
"""Actions for
|
|
17
|
+
"""Actions for GL Connectors."""
|
|
15
18
|
GITHUB: str
|
|
16
19
|
GOOGLE: str
|
|
17
20
|
GOOGLE_DRIVE: str
|
|
@@ -19,7 +22,7 @@ class Action(Enum):
|
|
|
19
22
|
TWITTER: str
|
|
20
23
|
|
|
21
24
|
class GitHubEndpoint(Enum):
|
|
22
|
-
"""GitHub endpoints for
|
|
25
|
+
"""GitHub endpoints for GL Connectors."""
|
|
23
26
|
INTEGRATIONS: str
|
|
24
27
|
USER_HAS_INTEGRATION: str
|
|
25
28
|
SUCCESS_AUTHORIZE_CALLBACK: str
|
|
@@ -46,7 +49,7 @@ class GitHubEndpoint(Enum):
|
|
|
46
49
|
LIST_PROJECTS: str
|
|
47
50
|
|
|
48
51
|
class GoogleDriveEndpoint(Enum):
|
|
49
|
-
"""Google Drive endpoints for
|
|
52
|
+
"""Google Drive endpoints for GL Connectors."""
|
|
50
53
|
INTEGRATIONS: str
|
|
51
54
|
USER_HAS_INTEGRATION: str
|
|
52
55
|
SUCCESS_AUTHORIZE_CALLBACK: str
|
|
@@ -69,7 +72,7 @@ class GoogleDriveEndpoint(Enum):
|
|
|
69
72
|
DOWNLOAD_FILE: str
|
|
70
73
|
|
|
71
74
|
class GoogleDocsEndpoint(Enum):
|
|
72
|
-
"""Google Docs endpoints for
|
|
75
|
+
"""Google Docs endpoints for GL Connectors."""
|
|
73
76
|
INTEGRATIONS: str
|
|
74
77
|
USER_HAS_INTEGRATION: str
|
|
75
78
|
SUCCESS_AUTHORIZE_CALLBACK: str
|
|
@@ -83,14 +86,14 @@ class GoogleDocsEndpoint(Enum):
|
|
|
83
86
|
SUMMARIZE_COMMENTS: str
|
|
84
87
|
|
|
85
88
|
class GoogleEndpoint(Enum):
|
|
86
|
-
"""Google endpoints for
|
|
89
|
+
"""Google endpoints for GL Connectors."""
|
|
87
90
|
INTEGRATIONS: str
|
|
88
91
|
USER_HAS_INTEGRATION: str
|
|
89
92
|
SUCCESS_AUTHORIZE_CALLBACK: str
|
|
90
93
|
USERINFO: str
|
|
91
94
|
|
|
92
95
|
class TwitterEndpoint(Enum):
|
|
93
|
-
"""Twitter endpoints for
|
|
96
|
+
"""Twitter endpoints for GL Connectors."""
|
|
94
97
|
INTEGRATIONS: str
|
|
95
98
|
USER_HAS_INTEGRATION: str
|
|
96
99
|
SUCCESS_AUTHORIZE_CALLBACK: str
|
|
@@ -100,7 +103,7 @@ class TwitterEndpoint(Enum):
|
|
|
100
103
|
GET_USERS: str
|
|
101
104
|
|
|
102
105
|
class GoogleMailEndpoint(Enum):
|
|
103
|
-
"""Google Mail endpoints for
|
|
106
|
+
"""Google Mail endpoints for GL Connectors."""
|
|
104
107
|
INTEGRATIONS: str
|
|
105
108
|
USER_HAS_INTEGRATION: str
|
|
106
109
|
SUCCESS_AUTHORIZE_CALLBACK: str
|