aip-agents-binary 0.5.25b9__py3-none-any.whl → 0.6.1__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.

Potentially problematic release.


This version of aip-agents-binary might be problematic. Click here for more details.

Files changed (73) hide show
  1. aip_agents/agent/base_langgraph_agent.py +137 -68
  2. aip_agents/agent/base_langgraph_agent.pyi +3 -2
  3. aip_agents/agent/langgraph_react_agent.py +252 -16
  4. aip_agents/agent/langgraph_react_agent.pyi +40 -1
  5. aip_agents/examples/compare_streaming_client.py +2 -2
  6. aip_agents/examples/compare_streaming_server.py +1 -1
  7. aip_agents/examples/hello_world_ptc.py +51 -0
  8. aip_agents/examples/hello_world_ptc.pyi +5 -0
  9. aip_agents/examples/hello_world_tool_output_client.py +9 -0
  10. aip_agents/examples/todolist_planning_a2a_langchain_client.py +2 -2
  11. aip_agents/examples/todolist_planning_a2a_langgraph_server.py +1 -1
  12. aip_agents/guardrails/engines/base.py +6 -6
  13. aip_agents/mcp/client/connection_manager.py +36 -1
  14. aip_agents/mcp/client/connection_manager.pyi +3 -0
  15. aip_agents/mcp/client/persistent_session.py +318 -68
  16. aip_agents/mcp/client/persistent_session.pyi +9 -0
  17. aip_agents/mcp/client/transports.py +33 -2
  18. aip_agents/mcp/client/transports.pyi +9 -0
  19. aip_agents/ptc/__init__.py +48 -0
  20. aip_agents/ptc/__init__.pyi +10 -0
  21. aip_agents/ptc/doc_gen.py +122 -0
  22. aip_agents/ptc/doc_gen.pyi +40 -0
  23. aip_agents/ptc/exceptions.py +39 -0
  24. aip_agents/ptc/exceptions.pyi +22 -0
  25. aip_agents/ptc/executor.py +143 -0
  26. aip_agents/ptc/executor.pyi +73 -0
  27. aip_agents/ptc/mcp/__init__.py +45 -0
  28. aip_agents/ptc/mcp/__init__.pyi +7 -0
  29. aip_agents/ptc/mcp/sandbox_bridge.py +668 -0
  30. aip_agents/ptc/mcp/sandbox_bridge.pyi +47 -0
  31. aip_agents/ptc/mcp/templates/__init__.py +1 -0
  32. aip_agents/ptc/mcp/templates/__init__.pyi +0 -0
  33. aip_agents/ptc/mcp/templates/mcp_client.py.template +239 -0
  34. aip_agents/ptc/naming.py +184 -0
  35. aip_agents/ptc/naming.pyi +76 -0
  36. aip_agents/ptc/payload.py +26 -0
  37. aip_agents/ptc/payload.pyi +15 -0
  38. aip_agents/ptc/prompt_builder.py +571 -0
  39. aip_agents/ptc/prompt_builder.pyi +55 -0
  40. aip_agents/ptc/ptc_helper.py +16 -0
  41. aip_agents/ptc/ptc_helper.pyi +1 -0
  42. aip_agents/ptc/sandbox_bridge.py +58 -0
  43. aip_agents/ptc/sandbox_bridge.pyi +25 -0
  44. aip_agents/ptc/template_utils.py +33 -0
  45. aip_agents/ptc/template_utils.pyi +13 -0
  46. aip_agents/ptc/templates/__init__.py +1 -0
  47. aip_agents/ptc/templates/__init__.pyi +0 -0
  48. aip_agents/ptc/templates/ptc_helper.py.template +134 -0
  49. aip_agents/sandbox/__init__.py +43 -0
  50. aip_agents/sandbox/__init__.pyi +5 -0
  51. aip_agents/sandbox/defaults.py +9 -0
  52. aip_agents/sandbox/defaults.pyi +2 -0
  53. aip_agents/sandbox/e2b_runtime.py +267 -0
  54. aip_agents/sandbox/e2b_runtime.pyi +51 -0
  55. aip_agents/sandbox/template_builder.py +131 -0
  56. aip_agents/sandbox/template_builder.pyi +36 -0
  57. aip_agents/sandbox/types.py +24 -0
  58. aip_agents/sandbox/types.pyi +14 -0
  59. aip_agents/sandbox/validation.py +50 -0
  60. aip_agents/sandbox/validation.pyi +20 -0
  61. aip_agents/tools/__init__.py +2 -0
  62. aip_agents/tools/__init__.pyi +2 -1
  63. aip_agents/tools/browser_use/browser_use_tool.py +8 -0
  64. aip_agents/tools/browser_use/streaming.py +2 -0
  65. aip_agents/tools/execute_ptc_code.py +305 -0
  66. aip_agents/tools/execute_ptc_code.pyi +87 -0
  67. aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.py +26 -1
  68. aip_agents/utils/langgraph/tool_output_management.py +80 -0
  69. aip_agents/utils/langgraph/tool_output_management.pyi +37 -0
  70. {aip_agents_binary-0.5.25b9.dist-info → aip_agents_binary-0.6.1.dist-info}/METADATA +51 -48
  71. {aip_agents_binary-0.5.25b9.dist-info → aip_agents_binary-0.6.1.dist-info}/RECORD +73 -27
  72. {aip_agents_binary-0.5.25b9.dist-info → aip_agents_binary-0.6.1.dist-info}/WHEEL +0 -0
  73. {aip_agents_binary-0.5.25b9.dist-info → aip_agents_binary-0.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,87 @@
1
+ from _typeshed import Incomplete
2
+ from aip_agents.mcp.client.base_mcp_client import BaseMCPClient as BaseMCPClient
3
+ from aip_agents.ptc.executor import PTCSandboxConfig as PTCSandboxConfig, PTCSandboxExecutor as PTCSandboxExecutor
4
+ from aip_agents.ptc.naming import sanitize_function_name as sanitize_function_name
5
+ from aip_agents.sandbox.e2b_runtime import E2BSandboxRuntime as E2BSandboxRuntime
6
+ from aip_agents.tools.tool_config_injector import TOOL_CONFIGS_KEY as TOOL_CONFIGS_KEY
7
+ from aip_agents.utils.logger import get_logger as get_logger
8
+ from langchain_core.tools import BaseTool
9
+ from typing import Any
10
+
11
+ logger: Incomplete
12
+
13
+ def merge_tool_configs(agent_configs: dict[str, Any] | None, runtime_configs: dict[str, Any] | None) -> dict[str, dict[str, Any]]:
14
+ '''Merge agent-level and runtime tool configs with sanitized keys.
15
+
16
+ Merges tool configurations from two sources:
17
+ 1. Agent-level defaults (from agent.tool_configs)
18
+ 2. Runtime overrides (from RunnableConfig.metadata["tool_configs"])
19
+
20
+ Both sources support two formats (matching LangGraphReactAgent behavior):
21
+ - Direct per-tool keys: {"time_tool": {"timezone": "UTC"}}
22
+ - Nested structure: {"tool_configs": {"time_tool": {"timezone": "UTC"}}}
23
+
24
+ The nested "tool_configs" key has higher precedence than direct keys.
25
+ Tool names are sanitized to match sandbox expectations (e.g., "Time Tool" -> "time_tool").
26
+
27
+ Args:
28
+ agent_configs: Agent-level tool configs (may be None or contain nested dicts)
29
+ runtime_configs: Runtime overrides from metadata (may be None)
30
+
31
+ Returns:
32
+ Merged dict with sanitized tool names as keys and config dicts as values.
33
+ Only includes entries that are dicts (non-dict values are agent-wide defaults).
34
+ '''
35
+
36
+ class PTCCodeTool(BaseTool):
37
+ """Tool for executing Python code with MCP tool access in a sandbox.
38
+
39
+ This tool uses BaseTool to properly access runtime config via run_manager.metadata.
40
+ The config parameter is NOT exposed to the LLM schema - it's extracted from
41
+ the callback manager during execution.
42
+ """
43
+ name: str
44
+ description: str
45
+ def __init__(self, executor: PTCSandboxExecutor, runtime: E2BSandboxRuntime, agent_tool_configs: dict[str, Any] | None = None, **kwargs: Any) -> None:
46
+ """Initialize the PTC code tool.
47
+
48
+ Args:
49
+ executor: The PTC sandbox executor.
50
+ runtime: The E2B sandbox runtime.
51
+ agent_tool_configs: Optional agent-level tool configs.
52
+ **kwargs: Additional keyword arguments passed to BaseTool.
53
+ """
54
+ @property
55
+ def args(self) -> dict[str, Any]:
56
+ """Return the argument schema for the tool."""
57
+ async def cleanup(self) -> None:
58
+ """Clean up the sandbox runtime."""
59
+
60
+ def create_execute_ptc_code_tool(mcp_client: BaseMCPClient | None, config: PTCSandboxConfig | None = None, agent_tool_configs: dict[str, Any] | None = None) -> PTCCodeTool:
61
+ '''Create a tool that executes Python code with MCP tool access.
62
+
63
+ The code runs inside an E2B sandbox with access to generated MCP tool modules.
64
+ This tool is designed for LLM-generated code that needs to call multiple tools
65
+ programmatically in a single execution.
66
+
67
+ Args:
68
+ mcp_client: The MCP client with configured servers.
69
+ config: Optional sandbox executor configuration.
70
+ agent_tool_configs: Optional agent-level tool configs (from agent.tool_configs).
71
+ These are merged with runtime overrides from RunnableConfig.metadata.
72
+
73
+ Returns:
74
+ PTCCodeTool configured for PTC code execution.
75
+
76
+ Example:
77
+ ```python
78
+ from aip_agents.mcp.client import LangchainMCPClient
79
+ from aip_agents.tools.execute_ptc_code import create_execute_ptc_code_tool
80
+
81
+ mcp_client = LangchainMCPClient()
82
+ await mcp_client.add_server("yfinance", {...})
83
+
84
+ tool = create_execute_ptc_code_tool(mcp_client)
85
+ result = await tool.ainvoke({"code": "from tools.yfinance import get_stock\\\\nprint(get_stock(\'AAPL\'))"})
86
+ ```
87
+ '''
@@ -134,7 +134,19 @@ class DelegationToolManager(BaseLangGraphToolManager):
134
134
  Returns:
135
135
  The result from the delegated agent, including artifacts if any.
136
136
  """
137
- writer: StreamWriter = get_stream_writer()
137
+ try:
138
+ writer: StreamWriter = get_stream_writer()
139
+ except Exception as exc:
140
+ logger.warning(
141
+ "DelegationToolManager: Stream writer unavailable; delegation streaming disabled.",
142
+ extra={"error": str(exc), "error_type": type(exc).__name__},
143
+ )
144
+
145
+ def _noop_writer(_: Any) -> None:
146
+ """No-op writer for non-graph execution contexts."""
147
+ return None
148
+
149
+ writer = _noop_writer
138
150
 
139
151
  try:
140
152
  # Check delegation depth limit before executing
@@ -295,6 +307,19 @@ class DelegationToolManager(BaseLangGraphToolManager):
295
307
  cfg_conf = cfg.get("configurable") if isinstance(cfg, dict) else None
296
308
  if isinstance(cfg_conf, dict):
297
309
  parent_step_id = cfg_conf.get("parent_step_id")
310
+ if not parent_step_id:
311
+ metadata = cfg.get("metadata") or {}
312
+ tool_call_id = (
313
+ cfg_conf.get("tool_call_id")
314
+ or metadata.get("tool_call_id")
315
+ or metadata.get("id")
316
+ or (metadata.get("tool_call") or {}).get("id")
317
+ )
318
+ if tool_call_id and self.parent_agent is not None:
319
+ thread_key = getattr(self.parent_agent, "thread_id_key", "thread_id")
320
+ thread_id = cfg_conf.get(thread_key)
321
+ parent_map = self.parent_agent._tool_parent_map_by_thread.get(str(thread_id), {})
322
+ parent_step_id = parent_map.get(str(tool_call_id))
298
323
  _DELEGATION_PARENT_STEP_ID_CVAR.set(parent_step_id)
299
324
  except Exception:
300
325
  _DELEGATION_PARENT_STEP_ID_CVAR.set(None)
@@ -471,6 +471,86 @@ class ToolOutputManager:
471
471
  """
472
472
  return self._generate_json_summary(thread_id, max_entries)
473
473
 
474
+ def get_latest_reference(self, thread_id: str) -> str | None:
475
+ """Return the most recent tool output reference for a thread.
476
+
477
+ Args:
478
+ thread_id: Thread ID to retrieve the latest output reference for.
479
+
480
+ Returns:
481
+ Latest tool output reference string or None when unavailable.
482
+ """
483
+ try:
484
+ summary = json.loads(self.generate_summary(thread_id, max_entries=1))
485
+ except Exception as exc:
486
+ logger.debug("Failed to parse tool output summary: %s", exc)
487
+ return None
488
+
489
+ if not summary:
490
+ return None
491
+ latest = summary[0].get("reference")
492
+ return latest if isinstance(latest, str) and latest else None
493
+
494
+ def has_reference(self, value: Any) -> bool:
495
+ """Check whether a value contains a tool output reference.
496
+
497
+ Args:
498
+ value: Value to inspect for tool output references.
499
+
500
+ Returns:
501
+ True if any tool output reference is present.
502
+ """
503
+ if isinstance(value, str):
504
+ return value.startswith(TOOL_OUTPUT_REFERENCE_PREFIX)
505
+ if isinstance(value, dict):
506
+ return any(self.has_reference(item) for item in value.values())
507
+ if isinstance(value, list):
508
+ return any(self.has_reference(item) for item in value)
509
+ return False
510
+
511
+ def should_replace_with_reference(self, value: Any) -> bool:
512
+ """Check whether a tool argument value should use a tool output reference.
513
+
514
+ Args:
515
+ value: Value to evaluate for replacement.
516
+
517
+ Returns:
518
+ True if the value should be replaced with a reference.
519
+ """
520
+ if isinstance(value, dict | list | tuple):
521
+ return True
522
+ if isinstance(value, str):
523
+ return len(value) > DATA_PREVIEW_TRUNCATION_LENGTH
524
+ return False
525
+
526
+ def rewrite_args_with_latest_reference(self, args: dict[str, Any], thread_id: str) -> dict[str, Any]:
527
+ """Rewrite tool args to use the latest tool output reference when appropriate.
528
+
529
+ Args:
530
+ args: Tool arguments to rewrite.
531
+ thread_id: Thread ID used for resolving stored outputs.
532
+
533
+ Returns:
534
+ Updated args dictionary with references substituted when needed.
535
+ """
536
+ if not self.has_outputs(thread_id):
537
+ return args
538
+ if self.has_reference(args):
539
+ return args
540
+
541
+ latest_reference = self.get_latest_reference(thread_id)
542
+ if not latest_reference:
543
+ return args
544
+
545
+ updated_args = dict(args)
546
+ replaced_any = False
547
+ for key, value in args.items():
548
+ if self.should_replace_with_reference(value):
549
+ updated_args[key] = latest_reference
550
+ replaced_any = True
551
+
552
+ return updated_args if replaced_any else args
553
+
474
554
  def _generate_json_summary(self, thread_id: str, max_entries: int) -> str:
475
555
  """Generate simplified JSON summary optimized for LLM prompts.
476
556
 
@@ -232,6 +232,43 @@ class ToolOutputManager:
232
232
  A JSON string containing structured data about tool outputs. Always returns
233
233
  valid JSON, even when no outputs are stored (empty entries list).
234
234
  """
235
+ def get_latest_reference(self, thread_id: str) -> str | None:
236
+ """Return the most recent tool output reference for a thread.
237
+
238
+ Args:
239
+ thread_id: Thread ID to retrieve the latest output reference for.
240
+
241
+ Returns:
242
+ Latest tool output reference string or None when unavailable.
243
+ """
244
+ def has_reference(self, value: Any) -> bool:
245
+ """Check whether a value contains a tool output reference.
246
+
247
+ Args:
248
+ value: Value to inspect for tool output references.
249
+
250
+ Returns:
251
+ True if any tool output reference is present.
252
+ """
253
+ def should_replace_with_reference(self, value: Any) -> bool:
254
+ """Check whether a tool argument value should use a tool output reference.
255
+
256
+ Args:
257
+ value: Value to evaluate for replacement.
258
+
259
+ Returns:
260
+ True if the value should be replaced with a reference.
261
+ """
262
+ def rewrite_args_with_latest_reference(self, args: dict[str, Any], thread_id: str) -> dict[str, Any]:
263
+ """Rewrite tool args to use the latest tool output reference when appropriate.
264
+
265
+ Args:
266
+ args: Tool arguments to rewrite.
267
+ thread_id: Thread ID used for resolving stored outputs.
268
+
269
+ Returns:
270
+ Updated args dictionary with references substituted when needed.
271
+ """
235
272
  def clear_all(self) -> None:
236
273
  """Clear all stored outputs from both metadata and storage.
237
274
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aip-agents-binary
3
- Version: 0.5.25b9
3
+ Version: 0.6.1
4
4
  Summary: A library for managing agents in Gen AI applications.
5
5
  Author-email: Raymond Christopher <raymond.christopher@gdplabs.id>
6
6
  Requires-Python: <3.13,>=3.11
@@ -21,22 +21,12 @@ Requires-Dist: langchain<0.4.0,>=0.3.0
21
21
  Requires-Dist: langchain-openai<0.4.0,>=0.3.17
22
22
  Requires-Dist: langchain-mcp-adapters<0.1.0,>=0.0.10
23
23
  Requires-Dist: langchain-experimental<0.4.0,>=0.3.4
24
- Requires-Dist: langgraph<0.3.0,>=0.2.16
24
+ Requires-Dist: langgraph<0.7.0,>=0.6.0
25
25
  Requires-Dist: minio<8.0.0,>=7.2.20
26
26
  Requires-Dist: pydantic<3.0.0,>=2.11.7
27
27
  Requires-Dist: python-dotenv<2.0.0,>=1.1.0
28
28
  Requires-Dist: requests<3.0.0,>=2.32.4
29
29
  Requires-Dist: uvicorn<0.35.0,>=0.34.3
30
- Provides-Extra: dev
31
- Requires-Dist: coverage<8.0.0,>=7.4.4; extra == "dev"
32
- Requires-Dist: mypy<2.0.0,>=1.15.0; extra == "dev"
33
- Requires-Dist: pre-commit<4.0.0,>=3.7.0; extra == "dev"
34
- Requires-Dist: pytest<9.0.0,>=8.1.1; extra == "dev"
35
- Requires-Dist: pytest-asyncio<0.24.0,>=0.23.6; extra == "dev"
36
- Requires-Dist: pytest-cov<6.0.0,>=5.0.0; extra == "dev"
37
- Requires-Dist: pytest-xdist>=3.8.0; extra == "dev"
38
- Requires-Dist: ruff<0.7.0,>=0.6.7; extra == "dev"
39
- Requires-Dist: pillow<12.0.0,>=11.3.0; extra == "dev"
40
30
  Provides-Extra: memory
41
31
  Requires-Dist: gllm-memory-binary[mem0ai]<0.2.0,>=0.1.1; extra == "memory"
42
32
  Provides-Extra: privacy
@@ -55,6 +45,17 @@ Requires-Dist: unidecode<2.0.0,>=1.3.0; extra == "local"
55
45
  Requires-Dist: gllm-docproc-binary[docx,pdf,xlsx]<0.8.0,>=0.7.21; extra == "local"
56
46
  Requires-Dist: gllm-multimodal-binary==0.2.0.post1; extra == "local"
57
47
  Requires-Dist: bosa-connectors-binary<0.4.0,>=0.3.1; extra == "local"
48
+ Provides-Extra: dev
49
+ Requires-Dist: coverage<8.0.0,>=7.4.4; extra == "dev"
50
+ Requires-Dist: mypy<2.0.0,>=1.15.0; extra == "dev"
51
+ Requires-Dist: nest-asyncio<2.0.0,>=1.6.0; extra == "dev"
52
+ Requires-Dist: pre-commit<4.0.0,>=3.7.0; extra == "dev"
53
+ Requires-Dist: pytest<9.0.0,>=8.1.1; extra == "dev"
54
+ Requires-Dist: pytest-asyncio<0.24.0,>=0.23.6; extra == "dev"
55
+ Requires-Dist: pytest-cov<6.0.0,>=5.0.0; extra == "dev"
56
+ Requires-Dist: pytest-xdist>=3.8.0; extra == "dev"
57
+ Requires-Dist: ruff<0.7.0,>=0.6.7; extra == "dev"
58
+ Requires-Dist: pillow<12.0.0,>=11.3.0; extra == "dev"
58
59
 
59
60
  # AIP Agents
60
61
 
@@ -73,13 +74,13 @@ You can use `aip-agents` directly for local execution, or let `glaip-sdk` manage
73
74
  ### Prerequisites
74
75
  - Python 3.11 - 3.12 - [Install here](https://www.python.org/downloads/)
75
76
  - Pip (if using Pip) - [Install here](https://pip.pypa.io/en/stable/installation/)
76
- - uv (if using uv) - [Install here](https://docs.astral.sh/uv/)
77
+ - Poetry 1.8.1+ (if using Poetry) - [Install here](https://python-poetry.org/docs/#installation)
77
78
  - Git (if using Git) - [Install here](https://git-scm.com/downloads)
78
79
  - For git installation:
79
80
  - Access to the [GDP Labs SDK repository](https://github.com/GDP-ADMIN/glaip-sdk)
80
81
 
81
82
  ### 1. Installation from the GDP Labs registry
82
- This package is published to the internal GDP Labs registry. Ensure your uv/pip config includes the registry:
83
+ This package is published to the internal GDP Labs registry. Ensure your pip/Poetry config includes the registry:
83
84
  `https://glsdk.gdplabs.id/gen-ai-internal/simple/`.
84
85
 
85
86
  #### Using pip
@@ -87,15 +88,15 @@ This package is published to the internal GDP Labs registry. Ensure your uv/pip
87
88
  pip install aip-agents
88
89
  ```
89
90
 
90
- #### Using uv
91
+ #### Using Poetry
91
92
  ```bash
92
- uv pip install aip-agents
93
+ poetry add aip-agents
93
94
  ```
94
95
 
95
96
  ### 2. Development Installation (Git)
96
97
  For development purposes, you can install directly from the Git repository:
97
98
  ```bash
98
- uv pip install "git+ssh://git@github.com/GDP-ADMIN/glaip-sdk.git#subdirectory=python/aip-agents"
99
+ poetry add "git+ssh://git@github.com/GDP-ADMIN/glaip-sdk.git#subdirectory=python/aip-agents"
99
100
  ```
100
101
 
101
102
  ### 3. Recommended: install via glaip-sdk for local mode
@@ -112,19 +113,21 @@ pip install "aip-agents[privacy]"
112
113
 
113
114
  ## Managing Dependencies
114
115
  1. Go to the `aip-agents` module root, e.g. `cd python/aip-agents`.
115
- 2. Run `uv sync --extra dev` to install the `aip-agents` requirements.
116
- 3. Run `uv lock` if you change any dependency versions in `pyproject.toml`.
116
+ 2. Run `poetry shell` to create a virtual environment.
117
+ 3. Run `poetry install` to install the `aip-agents` requirements (Poetry will generate a local lock file for you if needed; the repository ignores it).
118
+ 4. Run `poetry update` if you change any dependency versions in `pyproject.toml`.
117
119
 
118
120
  ## Contributing
119
121
  Please refer to this [Python Style Guide](https://docs.google.com/document/d/1uRggCrHnVfDPBnG641FyQBwUwLoFw0kTzNqRm92vUwM/edit?usp=sharing)
120
122
  to get information about code style, documentation standard, and SCA that you need to use when contributing to this project
121
123
 
122
124
  1. Activate `pre-commit` hooks using `pre-commit install`
123
- 2. Run `uv sync --extra dev` to install the `aip-agents` requirements.
124
- 3. Run `which python` to get the path to be referenced at Visual Studio Code interpreter path (`Ctrl`+`Shift`+`P` or `Cmd`+`Shift`+`P`)
125
- 4. Try running the unit test to see if it's working:
125
+ 2. Run `poetry shell` to create a virtual environment.
126
+ 3. Run `poetry install` to install the `aip-agents` requirements (this will also create a local lock file that stays local).
127
+ 4. Run `which python` to get the path to be referenced at Visual Studio Code interpreter path (`Ctrl`+`Shift`+`P` or `Cmd`+`Shift`+`P`)
128
+ 5. Try running the unit test to see if it's working:
126
129
  ```bash
127
- uv run pytest -s tests/unit_tests/
130
+ poetry run pytest -s tests/unit_tests/
128
131
  ```
129
132
 
130
133
  ## Hello World Examples
@@ -225,57 +228,57 @@ For STDIO, SSE, and HTTP transports using local servers, open a terminal in the
225
228
  - For STDIO:
226
229
 
227
230
  ```bash
228
- uv run python aip_agents/examples/mcp_servers/mcp_server_stdio.py
231
+ poetry run python aip_agents/examples/mcp_servers/mcp_server_stdio.py
229
232
  ```
230
233
 
231
234
  - For SSE:
232
235
 
233
236
  ```bash
234
- uv run python aip_agents/examples/mcp_servers/mcp_server_sse.py
237
+ poetry run python aip_agents/examples/mcp_servers/mcp_server_sse.py
235
238
  ```
236
239
 
237
240
  - For HTTP:
238
241
 
239
242
  ```bash
240
- uv run python aip_agents/examples/mcp_servers/mcp_server_http.py
243
+ poetry run python aip_agents/examples/mcp_servers/mcp_server_http.py
241
244
  ```
242
245
 
243
246
  Note: Start the appropriate server before running the client examples for that transport.
244
247
 
245
248
  ### Running Examples
246
249
 
247
- All examples are run from the library root using `uv run python aip_agents/examples/<file>.py`. Examples support OpenAI for LangGraph/LangChain and Google ADK where specified.
250
+ All examples are run from the library root using `poetry run python aip_agents/examples/<file>.py`. Examples support OpenAI for LangGraph/LangChain and Google ADK where specified.
248
251
 
249
252
  #### LangChain Examples
250
253
 
251
254
  ##### STDIO Transport
252
255
  - Non-Streaming:
253
256
  ```bash
254
- uv run python aip_agents/examples/hello_world_langchain_mcp_stdio.py
257
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_stdio.py
255
258
  ```
256
259
  - Streaming:
257
260
  ```bash
258
- uv run python aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py
261
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_stdio_stream.py
259
262
  ```
260
263
 
261
264
  ##### SSE Transport
262
265
  - Non-Streaming:
263
266
  ```bash
264
- uv run python aip_agents/examples/hello_world_langchain_mcp_sse.py
267
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_sse.py
265
268
  ```
266
269
  - Streaming:
267
270
  ```bash
268
- uv run python aip_agents/examples/hello_world_langchain_mcp_sse_stream.py
271
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_sse_stream.py
269
272
  ```
270
273
 
271
274
  ##### HTTP Transport
272
275
  - Non-Streaming:
273
276
  ```bash
274
- uv run python aip_agents/examples/hello_world_langchain_mcp_http.py
277
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_http.py
275
278
  ```
276
279
  - Streaming:
277
280
  ```bash
278
- uv run python aip_agents/examples/hello_world_langchain_mcp_http_stream.py
281
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_http_stream.py
279
282
  ```
280
283
 
281
284
  #### Google ADK Examples
@@ -283,31 +286,31 @@ uv run python aip_agents/examples/hello_world_langchain_mcp_http_stream.py
283
286
  ##### STDIO Transport
284
287
  - Non-Streaming:
285
288
  ```bash
286
- uv run python aip_agents/examples/hello_world_google_adk_mcp_stdio.py
289
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_stdio.py
287
290
  ```
288
291
  - Streaming:
289
292
  ```bash
290
- uv run python aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py
293
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.py
291
294
  ```
292
295
 
293
296
  ##### SSE Transport
294
297
  - Non-Streaming:
295
298
  ```bash
296
- uv run python aip_agents/examples/hello_world_google_adk_mcp_sse.py
299
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_sse.py
297
300
  ```
298
301
  - Streaming:
299
302
  ```bash
300
- uv run python aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py
303
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_sse_stream.py
301
304
  ```
302
305
 
303
306
  ##### HTTP Transport
304
307
  - Non-Streaming:
305
308
  ```bash
306
- uv run python aip_agents/examples/hello_world_google_adk_mcp_http.py
309
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_http.py
307
310
  ```
308
311
  - Streaming:
309
312
  ```bash
310
- uv run python aip_agents/examples/hello_world_google_adk_mcp_http_stream.py
313
+ poetry run python aip_agents/examples/hello_world_google_adk_mcp_http_stream.py
311
314
  ```
312
315
 
313
316
  #### LangGraph Examples (OpenAI)
@@ -315,31 +318,31 @@ uv run python aip_agents/examples/hello_world_google_adk_mcp_http_stream.py
315
318
  ##### STDIO Transport
316
319
  - Non-Streaming:
317
320
  ```bash
318
- uv run python aip_agents/examples/hello_world_langgraph_mcp_stdio.py
321
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_stdio.py
319
322
  ```
320
323
  - Streaming:
321
324
  ```bash
322
- uv run python aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py
325
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.py
323
326
  ```
324
327
 
325
328
  ##### SSE Transport
326
329
  - Non-Streaming:
327
330
  ```bash
328
- uv run python aip_agents/examples/hello_world_langgraph_mcp_sse.py
331
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_sse.py
329
332
  ```
330
333
  - Streaming:
331
334
  ```bash
332
- uv run python aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py
335
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_sse_stream.py
333
336
  ```
334
337
 
335
338
  ##### HTTP Transport
336
339
  - Non-Streaming:
337
340
  ```bash
338
- uv run python aip_agents/examples/hello_world_langgraph_mcp_http.py
341
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_http.py
339
342
  ```
340
343
  - Streaming:
341
344
  ```bash
342
- uv run python aip_agents/examples/hello_world_langgraph_mcp_http_stream.py
345
+ poetry run python aip_agents/examples/hello_world_langgraph_mcp_http_stream.py
343
346
  ```
344
347
 
345
348
  ### Multi-Server Example
@@ -355,13 +358,13 @@ npx @playwright/mcp@latest --headless --port 8931
355
358
  2. In another terminal, start the Name Generator SSE server:
356
359
 
357
360
  ```bash
358
- uv run python aip_agents/examples/mcp_servers/mcp_name.py
361
+ poetry run python aip_agents/examples/mcp_servers/mcp_name.py
359
362
  ```
360
363
 
361
364
  3. Run the multi-server client example:
362
365
 
363
366
  ```bash
364
- uv run python aip_agents/examples/hello_world_langchain_mcp_multi_server.py
367
+ poetry run python aip_agents/examples/hello_world_langchain_mcp_multi_server.py
365
368
  ```
366
369
  **3. Running Individual A2A Examples:**
367
370
 
@@ -477,7 +480,7 @@ The library supports Mem0 as a memory backend for long-term conversation recall.
477
480
  Use the coordinator example with memory enabled:
478
481
 
479
482
  ```bash
480
- uv run python aip_agents/examples/hello_world_a2a_mem0_coordinator_server.py
483
+ poetry run python aip_agents/examples/hello_world_a2a_mem0_coordinator_server.py
481
484
  ```
482
485
 
483
486
  In client: