aip-agents-binary 0.5.25__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.
Files changed (109) hide show
  1. aip_agents/agent/__init__.py +44 -4
  2. aip_agents/agent/base_langgraph_agent.py +163 -74
  3. aip_agents/agent/base_langgraph_agent.pyi +3 -2
  4. aip_agents/agent/langgraph_memory_enhancer_agent.py +368 -34
  5. aip_agents/agent/langgraph_memory_enhancer_agent.pyi +3 -2
  6. aip_agents/agent/langgraph_react_agent.py +329 -22
  7. aip_agents/agent/langgraph_react_agent.pyi +41 -2
  8. aip_agents/examples/hello_world_ptc.py +49 -0
  9. aip_agents/examples/hello_world_ptc.pyi +5 -0
  10. aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
  11. aip_agents/examples/hello_world_ptc_custom_tools.pyi +7 -0
  12. aip_agents/examples/hello_world_tool_output_client.py +9 -0
  13. aip_agents/examples/tools/multiply_tool.py +43 -0
  14. aip_agents/examples/tools/multiply_tool.pyi +18 -0
  15. aip_agents/guardrails/engines/base.py +6 -6
  16. aip_agents/mcp/client/__init__.py +38 -2
  17. aip_agents/mcp/client/connection_manager.py +36 -1
  18. aip_agents/mcp/client/connection_manager.pyi +3 -0
  19. aip_agents/mcp/client/persistent_session.py +318 -68
  20. aip_agents/mcp/client/persistent_session.pyi +9 -0
  21. aip_agents/mcp/client/transports.py +37 -2
  22. aip_agents/mcp/client/transports.pyi +9 -0
  23. aip_agents/memory/adapters/base_adapter.py +98 -0
  24. aip_agents/memory/adapters/base_adapter.pyi +25 -0
  25. aip_agents/ptc/__init__.py +87 -0
  26. aip_agents/ptc/__init__.pyi +14 -0
  27. aip_agents/ptc/custom_tools.py +473 -0
  28. aip_agents/ptc/custom_tools.pyi +184 -0
  29. aip_agents/ptc/custom_tools_payload.py +400 -0
  30. aip_agents/ptc/custom_tools_payload.pyi +31 -0
  31. aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
  32. aip_agents/ptc/custom_tools_templates/__init__.pyi +0 -0
  33. aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +23 -0
  34. aip_agents/ptc/custom_tools_templates/custom_init.py.template +15 -0
  35. aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +60 -0
  36. aip_agents/ptc/custom_tools_templates/custom_registry.py.template +87 -0
  37. aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
  38. aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +19 -0
  39. aip_agents/ptc/doc_gen.py +122 -0
  40. aip_agents/ptc/doc_gen.pyi +40 -0
  41. aip_agents/ptc/exceptions.py +57 -0
  42. aip_agents/ptc/exceptions.pyi +37 -0
  43. aip_agents/ptc/executor.py +261 -0
  44. aip_agents/ptc/executor.pyi +99 -0
  45. aip_agents/ptc/mcp/__init__.py +45 -0
  46. aip_agents/ptc/mcp/__init__.pyi +7 -0
  47. aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
  48. aip_agents/ptc/mcp/sandbox_bridge.pyi +47 -0
  49. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  50. aip_agents/ptc/mcp/templates/__init__.pyi +0 -0
  51. aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
  52. aip_agents/ptc/naming.py +196 -0
  53. aip_agents/ptc/naming.pyi +85 -0
  54. aip_agents/ptc/payload.py +26 -0
  55. aip_agents/ptc/payload.pyi +15 -0
  56. aip_agents/ptc/prompt_builder.py +673 -0
  57. aip_agents/ptc/prompt_builder.pyi +59 -0
  58. aip_agents/ptc/ptc_helper.py +16 -0
  59. aip_agents/ptc/ptc_helper.pyi +1 -0
  60. aip_agents/ptc/sandbox_bridge.py +256 -0
  61. aip_agents/ptc/sandbox_bridge.pyi +38 -0
  62. aip_agents/ptc/template_utils.py +33 -0
  63. aip_agents/ptc/template_utils.pyi +13 -0
  64. aip_agents/ptc/templates/__init__.py +1 -0
  65. aip_agents/ptc/templates/__init__.pyi +0 -0
  66. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  67. aip_agents/ptc/tool_def_helpers.py +101 -0
  68. aip_agents/ptc/tool_def_helpers.pyi +38 -0
  69. aip_agents/ptc/tool_enrichment.py +163 -0
  70. aip_agents/ptc/tool_enrichment.pyi +60 -0
  71. aip_agents/sandbox/__init__.py +43 -0
  72. aip_agents/sandbox/__init__.pyi +5 -0
  73. aip_agents/sandbox/defaults.py +205 -0
  74. aip_agents/sandbox/defaults.pyi +30 -0
  75. aip_agents/sandbox/e2b_runtime.py +295 -0
  76. aip_agents/sandbox/e2b_runtime.pyi +57 -0
  77. aip_agents/sandbox/template_builder.py +131 -0
  78. aip_agents/sandbox/template_builder.pyi +36 -0
  79. aip_agents/sandbox/types.py +24 -0
  80. aip_agents/sandbox/types.pyi +14 -0
  81. aip_agents/sandbox/validation.py +50 -0
  82. aip_agents/sandbox/validation.pyi +20 -0
  83. aip_agents/sentry/sentry.py +29 -8
  84. aip_agents/sentry/sentry.pyi +3 -2
  85. aip_agents/tools/__init__.py +13 -2
  86. aip_agents/tools/__init__.pyi +3 -1
  87. aip_agents/tools/browser_use/browser_use_tool.py +8 -0
  88. aip_agents/tools/browser_use/streaming.py +2 -0
  89. aip_agents/tools/date_range_tool.py +554 -0
  90. aip_agents/tools/date_range_tool.pyi +21 -0
  91. aip_agents/tools/execute_ptc_code.py +357 -0
  92. aip_agents/tools/execute_ptc_code.pyi +90 -0
  93. aip_agents/tools/memory_search/__init__.py +8 -1
  94. aip_agents/tools/memory_search/__init__.pyi +3 -3
  95. aip_agents/tools/memory_search/mem0.py +114 -1
  96. aip_agents/tools/memory_search/mem0.pyi +11 -1
  97. aip_agents/tools/memory_search/schema.py +33 -0
  98. aip_agents/tools/memory_search/schema.pyi +10 -0
  99. aip_agents/tools/memory_search_tool.py +8 -0
  100. aip_agents/tools/memory_search_tool.pyi +2 -2
  101. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +26 -1
  102. aip_agents/utils/langgraph/tool_output_management.py +80 -0
  103. aip_agents/utils/langgraph/tool_output_management.pyi +37 -0
  104. {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/METADATA +9 -19
  105. {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/RECORD +107 -41
  106. {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/WHEEL +1 -1
  107. aip_agents/examples/demo_memory_recall.py +0 -401
  108. aip_agents/examples/demo_memory_recall.pyi +0 -58
  109. {aip_agents_binary-0.5.25.dist-info → aip_agents_binary-0.6.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,83 @@
1
+ """Minimal PTC hello world example with custom tools.
2
+
3
+ Author: Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
4
+
5
+ Required environment variables:
6
+ - OPENAI_API_KEY
7
+ - E2B_API_KEY
8
+ """
9
+
10
+ import asyncio
11
+ import json
12
+ from pathlib import Path
13
+
14
+ from langchain_openai import ChatOpenAI
15
+
16
+ from aip_agents.agent import LangGraphReactAgent
17
+ from aip_agents.examples.tools.multiply_tool import MultiplyTool
18
+ from aip_agents.ptc import PromptConfig, PTCCustomToolConfig, PTCSandboxConfig, file_tool, package_tool
19
+ from aip_agents.tools.time_tool import TimeTool
20
+
21
+
22
+ async def main() -> None:
23
+ """Run a hello-world PTC flow with custom tools."""
24
+ repo_root = Path.cwd()
25
+ multiply_tool_path = repo_root / "aip_agents/examples/tools/multiply_tool.py"
26
+
27
+ instruction = (
28
+ "You are a helpful assistant with access to execute_ptc_code. "
29
+ "Use execute_ptc_code to run Python and print output. "
30
+ "Custom tools are available under tools.custom (import with "
31
+ "'from tools.custom import <tool_name>')."
32
+ )
33
+
34
+ agent = LangGraphReactAgent(
35
+ name="ptc_custom_tools_hello_world",
36
+ instruction=instruction,
37
+ model=ChatOpenAI(model="gpt-5.2"),
38
+ tools=[TimeTool(), MultiplyTool()],
39
+ tool_configs={"multiply": {"offset": 20}},
40
+ ptc_config=PTCSandboxConfig(
41
+ enabled=True,
42
+ sandbox_timeout=180.0,
43
+ prompt=PromptConfig(mode="auto"),
44
+ custom_tools=PTCCustomToolConfig(
45
+ enabled=True,
46
+ bundle_roots=[str(repo_root)],
47
+ requirements=[],
48
+ tools=[
49
+ package_tool(
50
+ "time_tool",
51
+ import_path="aip_agents.tools.time_tool",
52
+ class_name="TimeTool",
53
+ ),
54
+ file_tool(
55
+ "multiply",
56
+ file_path=str(multiply_tool_path),
57
+ class_name="MultiplyTool",
58
+ ),
59
+ ],
60
+ ),
61
+ ),
62
+ )
63
+
64
+ try:
65
+ # Pass tool config at runtime via metadata
66
+ # The multiply tool will use offset=10, so multiply(a=6, b=7) returns 6*7+10=52
67
+ print("execute_ptc_code output: ", end="")
68
+ last_chunk = None
69
+ async for chunk in agent.arun_sse_stream(
70
+ query=("Use execute_ptc_code to import from tools.custom. Print time_tool() and multiply(a=6, b=7)."),
71
+ metadata={"tool_configs": {"multiply": {"offset": 10}}},
72
+ ):
73
+ last_chunk = chunk
74
+ print(json.dumps(chunk))
75
+ print("-" * 20)
76
+ finally:
77
+ await agent.cleanup()
78
+
79
+ print("execute_ptc_code output: ", last_chunk["content"])
80
+
81
+
82
+ if __name__ == "__main__":
83
+ asyncio.run(main())
@@ -0,0 +1,7 @@
1
+ from aip_agents.agent import LangGraphReactAgent as LangGraphReactAgent
2
+ from aip_agents.examples.tools.multiply_tool import MultiplyTool as MultiplyTool
3
+ from aip_agents.ptc import PTCCustomToolConfig as PTCCustomToolConfig, PTCSandboxConfig as PTCSandboxConfig, PromptConfig as PromptConfig, file_tool as file_tool, package_tool as package_tool
4
+ from aip_agents.tools.time_tool import TimeTool as TimeTool
5
+
6
+ async def main() -> None:
7
+ """Run a hello-world PTC flow with custom tools."""
@@ -39,6 +39,15 @@ async def main():
39
39
  print(chunk["content"], end="", flush=True)
40
40
  if chunk.get("metadata"):
41
41
  print(f"\nMetadata: {chunk['metadata']}", end="\n\n", flush=True)
42
+ tool_info = chunk.get("metadata", {}).get("tool_info") if isinstance(chunk.get("metadata"), dict) else None
43
+ if isinstance(tool_info, dict):
44
+ for tool_call in tool_info.get("tool_calls", []):
45
+ if tool_call.get("name") == "data_visualizer":
46
+ data_source = tool_call.get("args", {}).get("data_source")
47
+ if not (isinstance(data_source, str) and data_source.startswith("$tool_output.")):
48
+ raise RuntimeError(
49
+ "Tool output sharing failed: expected data_source to reference $tool_output.<call_id>."
50
+ )
42
51
  print("\n")
43
52
 
44
53
 
@@ -0,0 +1,43 @@
1
+ """Tool to multiply two integers.
2
+
3
+ Author: Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
4
+ """
5
+
6
+ from langchain_core.tools import BaseTool
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class MultiplyToolInput(BaseModel):
11
+ """Input schema for the MultiplyTool."""
12
+
13
+ a: int = Field(..., description="First factor.")
14
+ b: int = Field(..., description="Second factor.")
15
+
16
+
17
+ class MultiplyToolConfig(BaseModel):
18
+ """Configuration for MultiplyTool."""
19
+
20
+ offset: int = Field(default=0, description="Offset to add to the result.")
21
+
22
+
23
+ class MultiplyTool(BaseTool):
24
+ """Tool to multiply two integers."""
25
+
26
+ name: str = "multiply"
27
+ description: str = "Multiply two integers."
28
+ args_schema: type[BaseModel] = MultiplyToolInput
29
+ tool_config_schema: type[BaseModel] = MultiplyToolConfig
30
+
31
+ def _run(self, a: int, b: int) -> int:
32
+ """Return the product of two integers."""
33
+ offset = 0
34
+ if hasattr(self, "get_tool_config"):
35
+ config = self.get_tool_config()
36
+ if config:
37
+ offset = getattr(config, "offset", 0)
38
+
39
+ return a * b + offset
40
+
41
+ async def _arun(self, a: int, b: int) -> int:
42
+ """Return the product of two integers asynchronously."""
43
+ return self._run(a=a, b=b)
@@ -0,0 +1,18 @@
1
+ from langchain_core.tools import BaseTool
2
+ from pydantic import BaseModel
3
+
4
+ class MultiplyToolInput(BaseModel):
5
+ """Input schema for the MultiplyTool."""
6
+ a: int
7
+ b: int
8
+
9
+ class MultiplyToolConfig(BaseModel):
10
+ """Configuration for MultiplyTool."""
11
+ offset: int
12
+
13
+ class MultiplyTool(BaseTool):
14
+ """Tool to multiply two integers."""
15
+ name: str
16
+ description: str
17
+ args_schema: type[BaseModel]
18
+ tool_config_schema: type[BaseModel]
@@ -39,7 +39,7 @@ class GuardrailEngine(Protocol):
39
39
  Returns:
40
40
  GuardrailResult indicating if content is safe
41
41
  """
42
- ...
42
+ ... # pragma: no cover
43
43
 
44
44
  @abstractmethod
45
45
  async def check_output(self, content: str) -> GuardrailResult:
@@ -51,12 +51,12 @@ class GuardrailEngine(Protocol):
51
51
  Returns:
52
52
  GuardrailResult indicating if content is safe
53
53
  """
54
- ...
54
+ ... # pragma: no cover
55
55
 
56
56
  @abstractmethod
57
57
  def model_dump(self) -> dict:
58
58
  """Serialize engine configuration into a JSON-compatible dictionary."""
59
- ...
59
+ ... # pragma: no cover
60
60
 
61
61
 
62
62
  class BaseGuardrailEngine(ABC):
@@ -77,14 +77,14 @@ class BaseGuardrailEngine(ABC):
77
77
  @abstractmethod
78
78
  async def check_input(self, content: str) -> GuardrailResult:
79
79
  """Check user input content for safety violations."""
80
- ...
80
+ ... # pragma: no cover
81
81
 
82
82
  @abstractmethod
83
83
  async def check_output(self, content: str) -> GuardrailResult:
84
84
  """Check AI output content for safety violations."""
85
- ...
85
+ ... # pragma: no cover
86
86
 
87
87
  @abstractmethod
88
88
  def model_dump(self) -> dict:
89
89
  """Serialize engine configuration into a JSON-compatible dictionary."""
90
- ...
90
+ ... # pragma: no cover
@@ -7,8 +7,44 @@ Authors:
7
7
  Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
8
8
  """
9
9
 
10
+ from __future__ import annotations
11
+
12
+ from typing import TYPE_CHECKING, Any
13
+
10
14
  from aip_agents.mcp.client.base_mcp_client import BaseMCPClient
11
- from aip_agents.mcp.client.google_adk.client import GoogleADKMCPClient
12
- from aip_agents.mcp.client.langchain.client import LangchainMCPClient
15
+
16
+ if TYPE_CHECKING:
17
+ from aip_agents.mcp.client.google_adk.client import GoogleADKMCPClient
18
+ from aip_agents.mcp.client.langchain.client import LangchainMCPClient
13
19
 
14
20
  __all__ = ["GoogleADKMCPClient", "LangchainMCPClient", "BaseMCPClient"]
21
+
22
+
23
+ def __getattr__(name: str) -> Any:
24
+ """Lazy import of MCP client implementations.
25
+
26
+ This avoids importing heavy dependencies (Google ADK, Vertex AI, etc.)
27
+ when they are not needed.
28
+
29
+ Args:
30
+ name: Attribute name to import.
31
+
32
+ Returns:
33
+ The requested class.
34
+
35
+ Raises:
36
+ AttributeError: If attribute is not found.
37
+ """
38
+ if name == "GoogleADKMCPClient":
39
+ from aip_agents.mcp.client.google_adk.client import (
40
+ GoogleADKMCPClient as _GoogleADKMCPClient,
41
+ )
42
+
43
+ return _GoogleADKMCPClient
44
+ elif name == "LangchainMCPClient":
45
+ from aip_agents.mcp.client.langchain.client import (
46
+ LangchainMCPClient as _LangchainMCPClient,
47
+ )
48
+
49
+ return _LangchainMCPClient
50
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -60,6 +60,9 @@ class MCPConnectionManager:
60
60
  async def start(self) -> tuple[Any, Any]:
61
61
  """Start connection in background task.
62
62
 
63
+ For HTTP/SSE transports, establishes connection directly to avoid anyio context issues.
64
+ For stdio transport, uses background task to manage subprocess lifecycle.
65
+
63
66
  Returns:
64
67
  tuple[Any, Any]: Tuple of (read_stream, write_stream) for ClientSession
65
68
 
@@ -67,6 +70,17 @@ class MCPConnectionManager:
67
70
  Exception: If connection establishment fails
68
71
  """
69
72
  logger.debug(f"Starting connection manager for {self.server_name}")
73
+
74
+ # Determine transport type first
75
+ self.transport_type = self._get_transport_type()
76
+
77
+ # For HTTP/SSE: connect directly (no background task needed)
78
+ # This avoids anyio.BrokenResourceError when streams cross task boundaries
79
+ if self.transport_type in (TransportType.HTTP, TransportType.SSE):
80
+ await self._establish_connection()
81
+ return self._connection
82
+
83
+ # For stdio: use background task to manage subprocess
70
84
  self._task = asyncio.create_task(self._connection_task())
71
85
  await self._ready_event.wait()
72
86
 
@@ -78,6 +92,20 @@ class MCPConnectionManager:
78
92
  async def stop(self) -> None:
79
93
  """Stop connection gracefully."""
80
94
  logger.debug(f"Stopping connection manager for {self.server_name}")
95
+
96
+ # For HTTP/SSE (no background task), just close transport
97
+ if self.transport_type in (TransportType.HTTP, TransportType.SSE):
98
+ if self._transport:
99
+ try:
100
+ close_result = self._transport.close()
101
+ if inspect.isawaitable(close_result):
102
+ await close_result
103
+ except Exception as exc:
104
+ logger.warning(f"Failed to close transport cleanly for {self.server_name}: {exc}")
105
+ self._connection = None
106
+ return
107
+
108
+ # For stdio (with background task), wait for task to finish
81
109
  if self._task and not self._task.done():
82
110
  self._stop_event.set()
83
111
  try:
@@ -94,6 +122,11 @@ class MCPConnectionManager:
94
122
  Returns:
95
123
  bool: True if connected, False otherwise
96
124
  """
125
+ # For HTTP/SSE (no background task), just check if connection exists
126
+ if self.transport_type in (TransportType.HTTP, TransportType.SSE):
127
+ return self._connection is not None
128
+
129
+ # For stdio (with background task), check task status too
97
130
  return (
98
131
  self._connection is not None
99
132
  and self._task is not None
@@ -144,7 +177,9 @@ class MCPConnectionManager:
144
177
  Raises:
145
178
  ConnectionError: If all connection attempts fail
146
179
  """
147
- self.transport_type = self._get_transport_type()
180
+ # transport_type may already be set by start() for HTTP/SSE
181
+ if not self.transport_type:
182
+ self.transport_type = self._get_transport_type()
148
183
  details = f"URL: {self.config.get('url', 'N/A')}, Command: {self.config.get('command', 'N/A')}"
149
184
  logger.info(f"Establishing connection to {self.server_name} via {self.transport_type} ({details})")
150
185
 
@@ -31,6 +31,9 @@ class MCPConnectionManager:
31
31
  async def start(self) -> tuple[Any, Any]:
32
32
  """Start connection in background task.
33
33
 
34
+ For HTTP/SSE transports, establishes connection directly to avoid anyio context issues.
35
+ For stdio transport, uses background task to manage subprocess lifecycle.
36
+
34
37
  Returns:
35
38
  tuple[Any, Any]: Tuple of (read_stream, write_stream) for ClientSession
36
39