aip-agents-binary 0.5.11__py3-none-any.whl → 0.5.12__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.
- aip_agents/a2a/server/langgraph_executor.py +4 -1
- aip_agents/agent/hitl/manager.py +10 -0
- aip_agents/agent/hitl/registry.py +149 -0
- {aip_agents_binary-0.5.11.dist-info → aip_agents_binary-0.5.12.dist-info}/METADATA +1 -1
- {aip_agents_binary-0.5.11.dist-info → aip_agents_binary-0.5.12.dist-info}/RECORD +7 -270
- aip_agents/__init__.pyi +0 -19
- aip_agents/a2a/__init__.pyi +0 -3
- aip_agents/a2a/server/__init__.pyi +0 -4
- aip_agents/a2a/server/base_executor.pyi +0 -73
- aip_agents/a2a/server/google_adk_executor.pyi +0 -51
- aip_agents/a2a/server/langflow_executor.pyi +0 -43
- aip_agents/a2a/server/langgraph_executor.pyi +0 -47
- aip_agents/a2a/types.pyi +0 -132
- aip_agents/agent/__init__.pyi +0 -9
- aip_agents/agent/base_agent.pyi +0 -221
- aip_agents/agent/base_langgraph_agent.pyi +0 -232
- aip_agents/agent/google_adk_agent.pyi +0 -141
- aip_agents/agent/google_adk_constants.pyi +0 -3
- aip_agents/agent/hitl/__init__.pyi +0 -6
- aip_agents/agent/hitl/config.pyi +0 -15
- aip_agents/agent/hitl/langgraph_hitl_mixin.pyi +0 -42
- aip_agents/agent/hitl/manager.pyi +0 -199
- aip_agents/agent/hitl/models.pyi +0 -3
- aip_agents/agent/hitl/prompt/__init__.pyi +0 -4
- aip_agents/agent/hitl/prompt/base.pyi +0 -24
- aip_agents/agent/hitl/prompt/deferred.pyi +0 -30
- aip_agents/agent/interface.pyi +0 -81
- aip_agents/agent/interfaces.pyi +0 -44
- aip_agents/agent/langflow_agent.pyi +0 -133
- aip_agents/agent/langgraph_memory_enhancer_agent.pyi +0 -49
- aip_agents/agent/langgraph_react_agent.pyi +0 -126
- aip_agents/agent/system_instruction_context.pyi +0 -13
- aip_agents/clients/__init__.pyi +0 -4
- aip_agents/clients/langflow/__init__.pyi +0 -4
- aip_agents/clients/langflow/client.pyi +0 -140
- aip_agents/clients/langflow/types.pyi +0 -7
- aip_agents/constants.pyi +0 -7
- aip_agents/examples/__init__.pyi +0 -0
- aip_agents/examples/compare_streaming_client.pyi +0 -48
- aip_agents/examples/compare_streaming_server.pyi +0 -18
- aip_agents/examples/demo_memory_recall.pyi +0 -58
- aip_agents/examples/hello_world_a2a_google_adk_client.pyi +0 -9
- aip_agents/examples/hello_world_a2a_google_adk_client_agent.pyi +0 -9
- aip_agents/examples/hello_world_a2a_google_adk_client_streaming.pyi +0 -9
- aip_agents/examples/hello_world_a2a_google_adk_server.pyi +0 -15
- aip_agents/examples/hello_world_a2a_langchain_client.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langchain_client_agent.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langchain_client_lm_invoker.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langchain_client_streaming.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langchain_reference_client_streaming.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langchain_reference_server.pyi +0 -15
- aip_agents/examples/hello_world_a2a_langchain_server.pyi +0 -15
- aip_agents/examples/hello_world_a2a_langchain_server_lm_invoker.pyi +0 -15
- aip_agents/examples/hello_world_a2a_langflow_client.pyi +0 -9
- aip_agents/examples/hello_world_a2a_langflow_server.pyi +0 -14
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langgraph_artifact_client_streaming.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langgraph_artifact_server.pyi +0 -16
- aip_agents/examples/hello_world_a2a_langgraph_client.pyi +0 -9
- aip_agents/examples/hello_world_a2a_langgraph_client_agent.pyi +0 -9
- aip_agents/examples/hello_world_a2a_langgraph_client_agent_lm_invoker.pyi +0 -2
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming.pyi +0 -9
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_lm_invoker.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langgraph_client_streaming_tool_streaming.pyi +0 -5
- aip_agents/examples/hello_world_a2a_langgraph_server.pyi +0 -14
- aip_agents/examples/hello_world_a2a_langgraph_server_lm_invoker.pyi +0 -15
- aip_agents/examples/hello_world_a2a_langgraph_server_tool_streaming.pyi +0 -15
- aip_agents/examples/hello_world_a2a_mcp_langgraph.pyi +0 -48
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_client.pyi +0 -48
- aip_agents/examples/hello_world_a2a_three_level_agent_hierarchy_server.pyi +0 -45
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_client.pyi +0 -5
- aip_agents/examples/hello_world_a2a_with_metadata_langchain_server_lm_invoker.pyi +0 -15
- aip_agents/examples/hello_world_google_adk.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_http.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_http_stream.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_sse.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_sse_stream.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_stdio.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_mcp_stdio_stream.pyi +0 -5
- aip_agents/examples/hello_world_google_adk_stream.pyi +0 -5
- aip_agents/examples/hello_world_langchain.pyi +0 -5
- aip_agents/examples/hello_world_langchain_lm_invoker.pyi +0 -2
- aip_agents/examples/hello_world_langchain_mcp_http.pyi +0 -5
- aip_agents/examples/hello_world_langchain_mcp_http_interactive.pyi +0 -16
- aip_agents/examples/hello_world_langchain_mcp_http_stream.pyi +0 -5
- aip_agents/examples/hello_world_langchain_mcp_multi_server.pyi +0 -18
- aip_agents/examples/hello_world_langchain_mcp_sse.pyi +0 -5
- aip_agents/examples/hello_world_langchain_mcp_sse_stream.pyi +0 -5
- aip_agents/examples/hello_world_langchain_mcp_stdio.pyi +0 -5
- aip_agents/examples/hello_world_langchain_mcp_stdio_stream.pyi +0 -5
- aip_agents/examples/hello_world_langchain_stream.pyi +0 -5
- aip_agents/examples/hello_world_langchain_stream_lm_invoker.pyi +0 -5
- aip_agents/examples/hello_world_langflow_agent.pyi +0 -35
- aip_agents/examples/hello_world_langgraph.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_bosa_twitter.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_http.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_http_stream.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_sse.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_sse_stream.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_stdio.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_mcp_stdio_stream.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_stream.pyi +0 -5
- aip_agents/examples/hello_world_langgraph_stream_lm_invoker.pyi +0 -5
- aip_agents/examples/hello_world_model_switch_cli.pyi +0 -30
- aip_agents/examples/hello_world_multi_agent_adk.pyi +0 -6
- aip_agents/examples/hello_world_multi_agent_langchain.pyi +0 -5
- aip_agents/examples/hello_world_multi_agent_langgraph.pyi +0 -5
- aip_agents/examples/hello_world_multi_agent_langgraph_lm_invoker.pyi +0 -5
- aip_agents/examples/hello_world_pii_logger.pyi +0 -5
- aip_agents/examples/hello_world_sentry.pyi +0 -21
- aip_agents/examples/hello_world_step_limits.pyi +0 -17
- aip_agents/examples/hello_world_stock_a2a_server.pyi +0 -17
- aip_agents/examples/hello_world_tool_output_client.pyi +0 -5
- aip_agents/examples/hello_world_tool_output_server.pyi +0 -19
- aip_agents/examples/hitl_demo.pyi +0 -67
- aip_agents/examples/pii_demo_langgraph_client.pyi +0 -5
- aip_agents/examples/pii_demo_langgraph_server.pyi +0 -20
- aip_agents/examples/pii_demo_multi_agent_client.pyi +0 -5
- aip_agents/examples/pii_demo_multi_agent_server.pyi +0 -40
- aip_agents/examples/todolist_planning_a2a_langchain_client.pyi +0 -5
- aip_agents/examples/todolist_planning_a2a_langgraph_server.pyi +0 -19
- aip_agents/examples/tools/__init__.pyi +0 -9
- aip_agents/examples/tools/adk_arithmetic_tools.pyi +0 -24
- aip_agents/examples/tools/adk_weather_tool.pyi +0 -18
- aip_agents/examples/tools/data_generator_tool.pyi +0 -15
- aip_agents/examples/tools/data_visualization_tool.pyi +0 -19
- aip_agents/examples/tools/image_artifact_tool.pyi +0 -26
- aip_agents/examples/tools/langchain_arithmetic_tools.pyi +0 -17
- aip_agents/examples/tools/langchain_currency_exchange_tool.pyi +0 -20
- aip_agents/examples/tools/langchain_graph_artifact_tool.pyi +0 -25
- aip_agents/examples/tools/langchain_weather_tool.pyi +0 -19
- aip_agents/examples/tools/langgraph_streaming_tool.pyi +0 -43
- aip_agents/examples/tools/mock_retrieval_tool.pyi +0 -13
- aip_agents/examples/tools/pii_demo_tools.pyi +0 -54
- aip_agents/examples/tools/random_chart_tool.pyi +0 -20
- aip_agents/examples/tools/serper_tool.pyi +0 -16
- aip_agents/examples/tools/stock_tools.pyi +0 -36
- aip_agents/examples/tools/table_generator_tool.pyi +0 -22
- aip_agents/examples/tools/time_tool.pyi +0 -15
- aip_agents/examples/tools/weather_forecast_tool.pyi +0 -14
- aip_agents/mcp/__init__.pyi +0 -0
- aip_agents/mcp/client/__init__.pyi +0 -5
- aip_agents/mcp/client/base_mcp_client.pyi +0 -148
- aip_agents/mcp/client/connection_manager.pyi +0 -48
- aip_agents/mcp/client/google_adk/__init__.pyi +0 -3
- aip_agents/mcp/client/google_adk/client.pyi +0 -75
- aip_agents/mcp/client/langchain/__init__.pyi +0 -3
- aip_agents/mcp/client/langchain/client.pyi +0 -48
- aip_agents/mcp/client/persistent_session.pyi +0 -113
- aip_agents/mcp/client/session_pool.pyi +0 -101
- aip_agents/mcp/client/transports.pyi +0 -123
- aip_agents/mcp/utils/__init__.pyi +0 -0
- aip_agents/mcp/utils/config_validator.pyi +0 -82
- aip_agents/memory/__init__.pyi +0 -5
- aip_agents/memory/adapters/__init__.pyi +0 -4
- aip_agents/memory/adapters/base_adapter.pyi +0 -150
- aip_agents/memory/adapters/mem0.pyi +0 -22
- aip_agents/memory/base.pyi +0 -60
- aip_agents/memory/constants.pyi +0 -25
- aip_agents/memory/factory.pyi +0 -24
- aip_agents/memory/guidance.pyi +0 -3
- aip_agents/memory/simple_memory.pyi +0 -23
- aip_agents/middleware/__init__.pyi +0 -5
- aip_agents/middleware/base.pyi +0 -71
- aip_agents/middleware/manager.pyi +0 -80
- aip_agents/middleware/todolist.pyi +0 -125
- aip_agents/schema/__init__.pyi +0 -9
- aip_agents/schema/a2a.pyi +0 -40
- aip_agents/schema/agent.pyi +0 -65
- aip_agents/schema/hitl.pyi +0 -89
- aip_agents/schema/langgraph.pyi +0 -28
- aip_agents/schema/model_id.pyi +0 -54
- aip_agents/schema/step_limit.pyi +0 -63
- aip_agents/schema/storage.pyi +0 -21
- aip_agents/sentry/__init__.pyi +0 -3
- aip_agents/sentry/sentry.pyi +0 -48
- aip_agents/storage/__init__.pyi +0 -8
- aip_agents/storage/base.pyi +0 -58
- aip_agents/storage/clients/__init__.pyi +0 -3
- aip_agents/storage/clients/minio_client.pyi +0 -137
- aip_agents/storage/config.pyi +0 -29
- aip_agents/storage/providers/__init__.pyi +0 -5
- aip_agents/storage/providers/base.pyi +0 -88
- aip_agents/storage/providers/memory.pyi +0 -79
- aip_agents/storage/providers/object_storage.pyi +0 -98
- aip_agents/tools/__init__.pyi +0 -4
- aip_agents/tools/bosa_tools.pyi +0 -37
- aip_agents/tools/browser_use/__init__.pyi +0 -14
- aip_agents/tools/browser_use/action_parser.pyi +0 -18
- aip_agents/tools/browser_use/browser_use_tool.pyi +0 -50
- aip_agents/tools/browser_use/llm_config.pyi +0 -52
- aip_agents/tools/browser_use/minio_storage.pyi +0 -109
- aip_agents/tools/browser_use/schemas.pyi +0 -32
- aip_agents/tools/browser_use/session.pyi +0 -4
- aip_agents/tools/browser_use/session_errors.pyi +0 -53
- aip_agents/tools/browser_use/steel_session_recording.pyi +0 -63
- aip_agents/tools/browser_use/streaming.pyi +0 -81
- aip_agents/tools/browser_use/structured_data_parser.pyi +0 -86
- aip_agents/tools/browser_use/structured_data_recovery.pyi +0 -43
- aip_agents/tools/browser_use/types.pyi +0 -45
- aip_agents/tools/code_sandbox/__init__.pyi +0 -3
- aip_agents/tools/code_sandbox/constant.pyi +0 -4
- aip_agents/tools/code_sandbox/e2b_cloud_sandbox_extended.pyi +0 -86
- aip_agents/tools/code_sandbox/e2b_sandbox_tool.pyi +0 -29
- aip_agents/tools/constants.pyi +0 -135
- aip_agents/tools/document_loader/__init__.pyi +0 -7
- aip_agents/tools/document_loader/base_reader.pyi +0 -62
- aip_agents/tools/document_loader/docx_reader_tool.pyi +0 -6
- aip_agents/tools/document_loader/excel_reader_tool.pyi +0 -26
- aip_agents/tools/document_loader/pdf_reader_tool.pyi +0 -11
- aip_agents/tools/document_loader/pdf_splitter.pyi +0 -18
- aip_agents/tools/gl_connector/__init__.pyi +0 -3
- aip_agents/tools/gl_connector/tool.pyi +0 -74
- aip_agents/tools/memory_search/__init__.pyi +0 -5
- aip_agents/tools/memory_search/base.pyi +0 -69
- aip_agents/tools/memory_search/mem0.pyi +0 -19
- aip_agents/tools/memory_search/schema.pyi +0 -15
- aip_agents/tools/memory_search_tool.pyi +0 -3
- aip_agents/tools/tool_config_injector.pyi +0 -26
- aip_agents/tools/web_search/__init__.pyi +0 -3
- aip_agents/tools/web_search/serper_tool.pyi +0 -19
- aip_agents/types/__init__.pyi +0 -36
- aip_agents/types/a2a_events.pyi +0 -3
- aip_agents/utils/__init__.pyi +0 -11
- aip_agents/utils/a2a_connector.pyi +0 -146
- aip_agents/utils/artifact_helpers.pyi +0 -203
- aip_agents/utils/constants.pyi +0 -10
- aip_agents/utils/datetime/__init__.pyi +0 -4
- aip_agents/utils/datetime/normalization.pyi +0 -95
- aip_agents/utils/datetime/timezone.pyi +0 -48
- aip_agents/utils/env_loader.pyi +0 -10
- aip_agents/utils/event_handler_registry.pyi +0 -23
- aip_agents/utils/file_prompt_utils.pyi +0 -21
- aip_agents/utils/final_response_builder.pyi +0 -34
- aip_agents/utils/formatter_llm_client.pyi +0 -71
- aip_agents/utils/langgraph/__init__.pyi +0 -3
- aip_agents/utils/langgraph/converter.pyi +0 -49
- aip_agents/utils/langgraph/tool_managers/__init__.pyi +0 -5
- aip_agents/utils/langgraph/tool_managers/a2a_tool_manager.pyi +0 -35
- aip_agents/utils/langgraph/tool_managers/base_tool_manager.pyi +0 -48
- aip_agents/utils/langgraph/tool_managers/delegation_tool_manager.pyi +0 -56
- aip_agents/utils/langgraph/tool_output_management.pyi +0 -292
- aip_agents/utils/logger.pyi +0 -60
- aip_agents/utils/metadata/__init__.pyi +0 -5
- aip_agents/utils/metadata/activity_metadata_helper.pyi +0 -25
- aip_agents/utils/metadata/activity_narrative/__init__.pyi +0 -7
- aip_agents/utils/metadata/activity_narrative/builder.pyi +0 -35
- aip_agents/utils/metadata/activity_narrative/constants.pyi +0 -10
- aip_agents/utils/metadata/activity_narrative/context.pyi +0 -32
- aip_agents/utils/metadata/activity_narrative/formatters.pyi +0 -48
- aip_agents/utils/metadata/activity_narrative/utils.pyi +0 -12
- aip_agents/utils/metadata/schemas/__init__.pyi +0 -4
- aip_agents/utils/metadata/schemas/activity_schema.pyi +0 -18
- aip_agents/utils/metadata/schemas/thinking_schema.pyi +0 -20
- aip_agents/utils/metadata/thinking_metadata_helper.pyi +0 -4
- aip_agents/utils/metadata_helper.pyi +0 -117
- aip_agents/utils/name_preprocessor/__init__.pyi +0 -6
- aip_agents/utils/name_preprocessor/base_name_preprocessor.pyi +0 -52
- aip_agents/utils/name_preprocessor/google_name_preprocessor.pyi +0 -38
- aip_agents/utils/name_preprocessor/name_preprocessor.pyi +0 -41
- aip_agents/utils/name_preprocessor/openai_name_preprocessor.pyi +0 -34
- aip_agents/utils/pii/__init__.pyi +0 -5
- aip_agents/utils/pii/pii_handler.pyi +0 -96
- aip_agents/utils/pii/pii_helper.pyi +0 -78
- aip_agents/utils/pii/uuid_deanonymizer_mapping.pyi +0 -73
- aip_agents/utils/reference_helper.pyi +0 -81
- aip_agents/utils/sse_chunk_transformer.pyi +0 -166
- aip_agents/utils/step_limit_manager.pyi +0 -112
- aip_agents/utils/token_usage_helper.pyi +0 -60
- {aip_agents_binary-0.5.11.dist-info → aip_agents_binary-0.5.12.dist-info}/WHEEL +0 -0
- {aip_agents_binary-0.5.11.dist-info → aip_agents_binary-0.5.12.dist-info}/top_level.txt +0 -0
|
@@ -255,6 +255,7 @@ class LangGraphA2AExecutor(BaseA2AExecutor, ABC):
|
|
|
255
255
|
return []
|
|
256
256
|
|
|
257
257
|
normalized_files: list[str | dict[str, Any]] = []
|
|
258
|
+
invalid_entry_logged = False
|
|
258
259
|
for entry in raw_files:
|
|
259
260
|
if isinstance(entry, str) and entry:
|
|
260
261
|
normalized_files.append(entry)
|
|
@@ -262,6 +263,8 @@ class LangGraphA2AExecutor(BaseA2AExecutor, ABC):
|
|
|
262
263
|
if isinstance(entry, dict):
|
|
263
264
|
normalized_files.append(entry)
|
|
264
265
|
continue
|
|
265
|
-
|
|
266
|
+
if not invalid_entry_logged:
|
|
267
|
+
logger.warning("Invalid file metadata entry received; expected string or dict.")
|
|
268
|
+
invalid_entry_logged = True
|
|
266
269
|
|
|
267
270
|
return normalized_files
|
aip_agents/agent/hitl/manager.py
CHANGED
|
@@ -15,6 +15,7 @@ from typing import Any
|
|
|
15
15
|
|
|
16
16
|
from aip_agents.agent.hitl.config import ToolApprovalConfig
|
|
17
17
|
from aip_agents.agent.hitl.prompt import BasePromptHandler, DeferredPromptHandler
|
|
18
|
+
from aip_agents.agent.hitl.registry import hitl_registry
|
|
18
19
|
from aip_agents.schema.hitl import ApprovalDecision, ApprovalDecisionType, ApprovalLogEntry, ApprovalRequest
|
|
19
20
|
|
|
20
21
|
# Constants
|
|
@@ -197,6 +198,9 @@ class ApprovalManager:
|
|
|
197
198
|
|
|
198
199
|
self._active_requests[request.request_id] = request
|
|
199
200
|
|
|
201
|
+
# Register ownership in global registry for hierarchical routing
|
|
202
|
+
hitl_registry.register(request.request_id, self)
|
|
203
|
+
|
|
200
204
|
def get_pending_request(self, request_id: str) -> ApprovalRequest | None:
|
|
201
205
|
"""Get a pending approval request by ID.
|
|
202
206
|
|
|
@@ -312,6 +316,10 @@ class ApprovalManager:
|
|
|
312
316
|
decision.latency_ms = int(latency.total_seconds() * 1000)
|
|
313
317
|
|
|
314
318
|
self._active_requests.pop(request.request_id, None)
|
|
319
|
+
|
|
320
|
+
# Unregister from global registry when finalized
|
|
321
|
+
hitl_registry.unregister(request.request_id)
|
|
322
|
+
|
|
315
323
|
return decision
|
|
316
324
|
|
|
317
325
|
async def prompt_for_decision(
|
|
@@ -459,6 +467,8 @@ class ApprovalManager:
|
|
|
459
467
|
|
|
460
468
|
for request_id in expired_ids:
|
|
461
469
|
self._active_requests.pop(request_id, None)
|
|
470
|
+
# Unregister expired requests from global registry
|
|
471
|
+
hitl_registry.unregister(request_id)
|
|
462
472
|
|
|
463
473
|
return len(expired_ids)
|
|
464
474
|
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Registry for tracking HITL approval manager ownership across agent hierarchies.
|
|
2
|
+
|
|
3
|
+
This module provides a thread-safe singleton registry that maps request IDs to their
|
|
4
|
+
owning ApprovalManager instances. This enables proper decision routing in hierarchical
|
|
5
|
+
agent architectures where sub-agents have HITL enabled but parents do not.
|
|
6
|
+
|
|
7
|
+
Authors:
|
|
8
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import threading
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
from weakref import WeakValueDictionary
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from aip_agents.agent.hitl.manager import ApprovalManager
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class HITLManagerRegistry:
|
|
22
|
+
"""Global registry mapping request_id → owning ApprovalManager.
|
|
23
|
+
|
|
24
|
+
Uses weak references to avoid preventing manager garbage collection.
|
|
25
|
+
Thread-safe for concurrent agent execution.
|
|
26
|
+
|
|
27
|
+
This singleton registry allows the HITL decision endpoint to route decisions
|
|
28
|
+
to the correct manager in hierarchical agent setups, where a sub-agent may
|
|
29
|
+
create a pending request but the parent agent receives the decision.
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
>>> from aip_agents.agent.hitl.registry import hitl_registry
|
|
33
|
+
>>> # Manager auto-registers when creating requests
|
|
34
|
+
>>> manager.create_approval_request(...)
|
|
35
|
+
>>> # Later, decision handler looks up the owning manager
|
|
36
|
+
>>> owning_manager = hitl_registry.get_manager(request_id)
|
|
37
|
+
>>> owning_manager.resolve_pending_request(request_id, "approved")
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
_instance: HITLManagerRegistry | None = None
|
|
41
|
+
_lock = threading.RLock()
|
|
42
|
+
_registry: WeakValueDictionary[str, ApprovalManager]
|
|
43
|
+
_registry_lock: threading.RLock
|
|
44
|
+
|
|
45
|
+
def __new__(cls) -> HITLManagerRegistry:
|
|
46
|
+
"""Ensure only one instance exists (singleton pattern).
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
The singleton HITLManagerRegistry instance.
|
|
50
|
+
"""
|
|
51
|
+
if cls._instance is None:
|
|
52
|
+
with cls._lock:
|
|
53
|
+
if cls._instance is None:
|
|
54
|
+
instance = super().__new__(cls)
|
|
55
|
+
instance._registry = WeakValueDictionary()
|
|
56
|
+
instance._registry_lock = threading.RLock()
|
|
57
|
+
cls._instance = instance
|
|
58
|
+
return cls._instance
|
|
59
|
+
|
|
60
|
+
def register(self, request_id: str, manager: ApprovalManager) -> None:
|
|
61
|
+
"""Register a pending request with its owning manager.
|
|
62
|
+
|
|
63
|
+
This method is typically called automatically by ApprovalManager when
|
|
64
|
+
creating a new pending request. It establishes the ownership mapping
|
|
65
|
+
needed for proper decision routing.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
request_id: Unique identifier for the pending request
|
|
69
|
+
manager: ApprovalManager instance that owns this request
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
>>> hitl_registry.register("req_abc123", my_manager)
|
|
73
|
+
"""
|
|
74
|
+
with self._registry_lock:
|
|
75
|
+
self._registry[request_id] = manager
|
|
76
|
+
|
|
77
|
+
def unregister(self, request_id: str) -> None:
|
|
78
|
+
"""Remove a request from the registry.
|
|
79
|
+
|
|
80
|
+
This method is called when a request is resolved, times out, or expires.
|
|
81
|
+
It's important for cleanup to prevent the registry from growing unbounded.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
request_id: Unique identifier to remove
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
>>> hitl_registry.unregister("req_abc123")
|
|
88
|
+
"""
|
|
89
|
+
with self._registry_lock:
|
|
90
|
+
self._registry.pop(request_id, None)
|
|
91
|
+
|
|
92
|
+
def get_manager(self, request_id: str) -> ApprovalManager | None:
|
|
93
|
+
"""Retrieve the manager owning a specific request.
|
|
94
|
+
|
|
95
|
+
This is the primary lookup method used by decision handlers to route
|
|
96
|
+
decisions to the correct manager in hierarchical agent setups.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
request_id: Unique identifier to lookup
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
ApprovalManager instance if found, None otherwise. None can indicate
|
|
103
|
+
the request was resolved, timed out, or the manager was garbage collected.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
>>> manager = hitl_registry.get_manager("req_abc123")
|
|
107
|
+
>>> if manager:
|
|
108
|
+
... manager.resolve_pending_request("req_abc123", "approved")
|
|
109
|
+
"""
|
|
110
|
+
with self._registry_lock:
|
|
111
|
+
return self._registry.get(request_id)
|
|
112
|
+
|
|
113
|
+
def clear(self) -> None:
|
|
114
|
+
"""Clear all registrations.
|
|
115
|
+
|
|
116
|
+
This method is primarily intended for testing to ensure a clean state
|
|
117
|
+
between test cases. It removes all registered mappings.
|
|
118
|
+
|
|
119
|
+
Warning:
|
|
120
|
+
This should not be called in production code as it will prevent
|
|
121
|
+
pending requests from being resolved.
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
>>> hitl_registry.clear() # For testing only
|
|
125
|
+
"""
|
|
126
|
+
with self._registry_lock:
|
|
127
|
+
self._registry.clear()
|
|
128
|
+
|
|
129
|
+
def list_all(self) -> list[str]:
|
|
130
|
+
"""List all currently registered request IDs.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
List of request IDs currently in the registry.
|
|
134
|
+
|
|
135
|
+
Note:
|
|
136
|
+
Due to weak references, managers may be garbage collected between
|
|
137
|
+
calling this method and accessing them, so the actual available
|
|
138
|
+
managers might be fewer than the returned list length.
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
>>> request_ids = hitl_registry.list_all()
|
|
142
|
+
>>> print(f"Pending requests: {request_ids}")
|
|
143
|
+
"""
|
|
144
|
+
with self._registry_lock:
|
|
145
|
+
return list(self._registry.keys())
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# Global singleton instance
|
|
149
|
+
hitl_registry = HITLManagerRegistry()
|