alita-sdk 0.3.465__py3-none-any.whl → 0.3.486__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 alita-sdk might be problematic. Click here for more details.

Files changed (90) hide show
  1. alita_sdk/cli/agent/__init__.py +5 -0
  2. alita_sdk/cli/agent/default.py +83 -1
  3. alita_sdk/cli/agent_loader.py +6 -9
  4. alita_sdk/cli/agent_ui.py +13 -3
  5. alita_sdk/cli/agents.py +1866 -185
  6. alita_sdk/cli/callbacks.py +96 -25
  7. alita_sdk/cli/cli.py +10 -1
  8. alita_sdk/cli/config.py +151 -9
  9. alita_sdk/cli/context/__init__.py +30 -0
  10. alita_sdk/cli/context/cleanup.py +198 -0
  11. alita_sdk/cli/context/manager.py +731 -0
  12. alita_sdk/cli/context/message.py +285 -0
  13. alita_sdk/cli/context/strategies.py +289 -0
  14. alita_sdk/cli/context/token_estimation.py +127 -0
  15. alita_sdk/cli/input_handler.py +167 -4
  16. alita_sdk/cli/inventory.py +1256 -0
  17. alita_sdk/cli/toolkit.py +14 -17
  18. alita_sdk/cli/toolkit_loader.py +35 -5
  19. alita_sdk/cli/tools/__init__.py +8 -1
  20. alita_sdk/cli/tools/filesystem.py +815 -55
  21. alita_sdk/cli/tools/planning.py +143 -157
  22. alita_sdk/cli/tools/terminal.py +154 -20
  23. alita_sdk/community/__init__.py +64 -8
  24. alita_sdk/community/inventory/__init__.py +224 -0
  25. alita_sdk/community/inventory/config.py +257 -0
  26. alita_sdk/community/inventory/enrichment.py +2137 -0
  27. alita_sdk/community/inventory/extractors.py +1469 -0
  28. alita_sdk/community/inventory/ingestion.py +3172 -0
  29. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  30. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  31. alita_sdk/community/inventory/parsers/base.py +295 -0
  32. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  33. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  34. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  35. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  36. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  37. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  38. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  39. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  40. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  41. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  42. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  43. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  44. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  45. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  46. alita_sdk/community/inventory/patterns/loader.py +348 -0
  47. alita_sdk/community/inventory/patterns/registry.py +198 -0
  48. alita_sdk/community/inventory/presets.py +535 -0
  49. alita_sdk/community/inventory/retrieval.py +1403 -0
  50. alita_sdk/community/inventory/toolkit.py +169 -0
  51. alita_sdk/community/inventory/visualize.py +1370 -0
  52. alita_sdk/configurations/bitbucket.py +0 -3
  53. alita_sdk/runtime/clients/client.py +84 -26
  54. alita_sdk/runtime/langchain/assistant.py +4 -2
  55. alita_sdk/runtime/langchain/langraph_agent.py +122 -31
  56. alita_sdk/runtime/llms/preloaded.py +2 -6
  57. alita_sdk/runtime/toolkits/__init__.py +2 -0
  58. alita_sdk/runtime/toolkits/application.py +1 -1
  59. alita_sdk/runtime/toolkits/mcp.py +46 -36
  60. alita_sdk/runtime/toolkits/planning.py +171 -0
  61. alita_sdk/runtime/toolkits/tools.py +39 -6
  62. alita_sdk/runtime/tools/llm.py +185 -8
  63. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  64. alita_sdk/runtime/tools/planning/models.py +246 -0
  65. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  66. alita_sdk/runtime/tools/vectorstore_base.py +41 -6
  67. alita_sdk/runtime/utils/mcp_oauth.py +80 -0
  68. alita_sdk/runtime/utils/streamlit.py +6 -10
  69. alita_sdk/runtime/utils/toolkit_utils.py +19 -4
  70. alita_sdk/tools/__init__.py +54 -27
  71. alita_sdk/tools/ado/repos/repos_wrapper.py +1 -2
  72. alita_sdk/tools/base_indexer_toolkit.py +98 -19
  73. alita_sdk/tools/bitbucket/__init__.py +2 -2
  74. alita_sdk/tools/chunkers/__init__.py +3 -1
  75. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +95 -6
  76. alita_sdk/tools/chunkers/universal_chunker.py +269 -0
  77. alita_sdk/tools/code_indexer_toolkit.py +55 -22
  78. alita_sdk/tools/elitea_base.py +86 -21
  79. alita_sdk/tools/jira/__init__.py +1 -1
  80. alita_sdk/tools/jira/api_wrapper.py +91 -40
  81. alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
  82. alita_sdk/tools/qtest/__init__.py +1 -1
  83. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +8 -2
  84. alita_sdk/tools/zephyr_essential/api_wrapper.py +12 -13
  85. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/METADATA +2 -1
  86. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/RECORD +90 -50
  87. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/WHEEL +0 -0
  88. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/entry_points.txt +0 -0
  89. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/licenses/LICENSE +0 -0
  90. {alita_sdk-0.3.465.dist-info → alita_sdk-0.3.486.dist-info}/top_level.txt +0 -0
@@ -6,12 +6,11 @@ Following MCP specification: https://modelcontextprotocol.io/specification/2025-
6
6
 
7
7
  import logging
8
8
  import re
9
- import requests
10
9
  import asyncio
11
10
  from typing import List, Optional, Any, Dict, Literal, ClassVar, Union
12
11
 
13
12
  from langchain_core.tools import BaseToolkit, BaseTool
14
- from pydantic import BaseModel, ConfigDict, Field
13
+ from pydantic import BaseModel, ConfigDict, Field, SecretStr
15
14
 
16
15
  from ..tools.mcp_server_tool import McpServerTool
17
16
  from ..tools.mcp_remote_tool import McpRemoteTool
@@ -208,28 +207,32 @@ class McpToolkit(BaseToolkit):
208
207
  }
209
208
  )
210
209
  ),
211
- timeout=(
212
- Union[int, str], # TODO: remove one I will figure out why UI sends str
210
+ client_id=(
211
+ Optional[str],
213
212
  Field(
214
- default=300,
215
- description="Request timeout in seconds (1-3600)"
213
+ default=None,
214
+ description="OAuth Client ID (if applicable)"
216
215
  )
217
216
  ),
218
- discovery_mode=(
219
- Literal['static', 'dynamic', 'hybrid'],
217
+ client_secret=(
218
+ Optional[SecretStr],
220
219
  Field(
221
- default="dynamic",
222
- description="Discovery mode",
223
- json_schema_extra={
224
- 'tooltip': 'static: use registry, dynamic: live discovery, hybrid: try dynamic first'
225
- }
220
+ default=None,
221
+ description="OAuth Client Secret (if applicable)"
226
222
  )
227
223
  ),
228
- discovery_interval=(
229
- Union[int, str],
224
+ scopes=(
225
+ Optional[List[str]],
226
+ Field(
227
+ default=None,
228
+ description="OAuth Scopes (if applicable)"
229
+ )
230
+ ),
231
+ timeout=(
232
+ Union[int, str], # TODO: remove one I will figure out why UI sends str
230
233
  Field(
231
234
  default=300,
232
- description="Discovery interval in seconds (60-3600, for periodic discovery)"
235
+ description="Request timeout in seconds (1-3600)"
233
236
  )
234
237
  ),
235
238
  selected_tools=(
@@ -259,7 +262,7 @@ class McpToolkit(BaseToolkit):
259
262
  __config__=ConfigDict(
260
263
  json_schema_extra={
261
264
  'metadata': {
262
- "label": "Remove MCP",
265
+ "label": "Remote MCP",
263
266
  "icon_url": None,
264
267
  "categories": ["other"],
265
268
  "extra_categories": ["remote tools", "sse", "http"],
@@ -275,8 +278,6 @@ class McpToolkit(BaseToolkit):
275
278
  url: str,
276
279
  headers: Optional[Dict[str, str]] = None,
277
280
  timeout: int = 60,
278
- discovery_mode: str = "hybrid",
279
- discovery_interval: int = 300,
280
281
  selected_tools: List[str] = None,
281
282
  enable_caching: bool = True,
282
283
  cache_ttl: int = 300,
@@ -297,8 +298,6 @@ class McpToolkit(BaseToolkit):
297
298
  url: MCP server HTTP URL
298
299
  headers: HTTP headers for authentication
299
300
  timeout: Request timeout in seconds
300
- discovery_mode: Discovery mode ('static', 'dynamic', 'hybrid')
301
- discovery_interval: Discovery interval in seconds (for periodic discovery)
302
301
  selected_tools: List of specific tools to enable (empty = all tools)
303
302
  enable_caching: Whether to enable caching
304
303
  cache_ttl: Cache TTL in seconds
@@ -317,7 +316,6 @@ class McpToolkit(BaseToolkit):
317
316
 
318
317
  # Convert numeric parameters that may come as strings from UI
319
318
  timeout = safe_int(timeout, 60)
320
- discovery_interval = safe_int(discovery_interval, 300)
321
319
  cache_ttl = safe_int(cache_ttl, 300)
322
320
 
323
321
  logger.info(f"Creating MCP toolkit: {toolkit_name}")
@@ -363,8 +361,7 @@ class McpToolkit(BaseToolkit):
363
361
  connection_config=connection_config,
364
362
  timeout=timeout,
365
363
  selected_tools=selected_tools,
366
- client=client,
367
- discovery_mode=discovery_mode
364
+ client=client
368
365
  )
369
366
 
370
367
  return toolkit
@@ -376,8 +373,7 @@ class McpToolkit(BaseToolkit):
376
373
  connection_config: McpConnectionConfig,
377
374
  timeout: int,
378
375
  selected_tools: List[str],
379
- client,
380
- discovery_mode: str = "dynamic"
376
+ client
381
377
  ) -> List[BaseTool]:
382
378
  """
383
379
  Create tools from a single MCP server. Always performs live discovery when connection config is provided.
@@ -423,19 +419,28 @@ class McpToolkit(BaseToolkit):
423
419
 
424
420
  logger.info(f"Successfully created {len(tools)} MCP tools from toolkit '{toolkit_name}' via direct discovery")
425
421
 
422
+ except McpAuthorizationRequired:
423
+ # Authorization is required; surface upstream so the caller can prompt the user
424
+ logger.info(f"MCP toolkit '{toolkit_name}' requires OAuth authorization")
425
+ raise
426
426
  except Exception as e:
427
427
  logger.error(f"Direct discovery failed for MCP toolkit '{toolkit_name}': {e}", exc_info=True)
428
428
  logger.error(f"Discovery error details - URL: {connection_config.url}, Timeout: {timeout}s")
429
429
 
430
- # Fallback to static mode if available and not already static
431
- if isinstance(e, McpAuthorizationRequired):
432
- # Authorization is required; surface upstream so the caller can prompt the user
430
+ # Check if the exception wraps McpAuthorizationRequired (can happen with asyncio)
431
+ if hasattr(e, '__cause__') and isinstance(e.__cause__, McpAuthorizationRequired):
432
+ logger.info(f"Found wrapped McpAuthorizationRequired, re-raising")
433
+ raise e.__cause__
434
+
435
+ # For new MCP toolkits (no client), don't silently return empty - surface the error
436
+ # This helps users understand why tool discovery failed
437
+ if not client:
438
+ logger.warning(f"No fallback available for toolkit '{toolkit_name}' - re-raising discovery error")
433
439
  raise
434
- if client and discovery_mode != "static":
435
- logger.info(f"Falling back to static discovery for toolkit '{toolkit_name}'")
436
- tools = cls._create_tools_static(toolkit_name, selected_tools, timeout, client)
437
- else:
438
- logger.warning(f"No fallback available for toolkit '{toolkit_name}' - returning empty tools list")
440
+
441
+ # Only fall back to static discovery for existing toolkits with a client
442
+ logger.info(f"Falling back to static discovery for toolkit '{toolkit_name}'")
443
+ tools = cls._create_tools_static(toolkit_name, selected_tools, timeout, client)
439
444
 
440
445
  # Don't add inspection tool to agent - it's only for internal use by toolkit
441
446
  # inspection_tool = cls._create_inspection_tool(
@@ -481,8 +486,15 @@ class McpToolkit(BaseToolkit):
481
486
  )
482
487
  )
483
488
  return all_tools, session_id
489
+ except McpAuthorizationRequired:
490
+ # Re-raise auth required exceptions directly
491
+ logger.info(f"[MCP SSE] Authorization required for '{toolkit_name}'")
492
+ raise
484
493
  except Exception as e:
485
494
  logger.error(f"[MCP SSE] Discovery failed for '{toolkit_name}': {e}")
495
+ # Check if the exception wraps McpAuthorizationRequired
496
+ if hasattr(e, '__cause__') and isinstance(e.__cause__, McpAuthorizationRequired):
497
+ raise e.__cause__
486
498
  raise
487
499
 
488
500
  @classmethod
@@ -858,8 +870,6 @@ def get_tools(tool_config: dict, alita_client, llm=None, memory_store=None) -> L
858
870
  url=url,
859
871
  headers=headers,
860
872
  timeout=safe_int(settings.get('timeout'), 60),
861
- discovery_mode=settings.get('discovery_mode', 'dynamic'),
862
- discovery_interval=safe_int(settings.get('discovery_interval'), 300),
863
873
  selected_tools=settings.get('selected_tools', []),
864
874
  enable_caching=settings.get('enable_caching', True),
865
875
  cache_ttl=safe_int(settings.get('cache_ttl'), 300),
@@ -0,0 +1,171 @@
1
+ """
2
+ PlanningToolkit - Runtime toolkit for agent plan management.
3
+
4
+ Provides tools for creating, tracking, and completing multi-step execution plans.
5
+ Supports two storage backends:
6
+ 1. PostgreSQL - when pgvector_configuration with connection_string is provided
7
+ 2. Filesystem - when no connection string (local CLI usage)
8
+ """
9
+
10
+ from typing import ClassVar, List, Any, Literal, Optional, Callable
11
+
12
+ from langchain_community.agent_toolkits.base import BaseToolkit
13
+ from langchain_core.tools import BaseTool
14
+ from pydantic import create_model, BaseModel, ConfigDict, Field
15
+ from pydantic.fields import FieldInfo
16
+
17
+ from ..tools.planning import PlanningWrapper
18
+ from ...tools.base.tool import BaseAction
19
+ from ...tools.utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
20
+
21
+
22
+ class PlanningToolkit(BaseToolkit):
23
+ """
24
+ Toolkit for agent plan management.
25
+
26
+ Provides tools for creating, updating, and tracking execution plans.
27
+ Supports PostgreSQL (production) and filesystem (local) storage backends.
28
+ Plans are scoped by conversation_id.
29
+ """
30
+ tools: List[BaseTool] = []
31
+ _toolkit_max_length: ClassVar[int] = 50 # Use ClassVar to avoid Pydantic treating it as field
32
+
33
+ @staticmethod
34
+ def toolkit_config_schema() -> BaseModel:
35
+ """
36
+ Returns the configuration schema for the Planning toolkit.
37
+
38
+ Used by the UI to generate the toolkit configuration form.
39
+ """
40
+ # Define available tools
41
+ selected_tools = {
42
+ 'update_plan': {
43
+ 'title': 'UpdatePlanInput',
44
+ 'type': 'object',
45
+ 'properties': {
46
+ 'title': {'type': 'string', 'description': "Title for the plan"},
47
+ 'steps': {'type': 'array', 'items': {'type': 'string'}, 'description': "List of step descriptions"},
48
+ 'conversation_id': {'type': 'string', 'description': "Conversation ID (auto-injected)"}
49
+ },
50
+ 'required': ['title', 'steps', 'conversation_id']
51
+ },
52
+ 'complete_step': {
53
+ 'title': 'CompleteStepInput',
54
+ 'type': 'object',
55
+ 'properties': {
56
+ 'step_number': {'type': 'integer', 'description': "Step number to complete (1-indexed)"},
57
+ 'conversation_id': {'type': 'string', 'description': "Conversation ID (auto-injected)"}
58
+ },
59
+ 'required': ['step_number', 'conversation_id']
60
+ },
61
+ 'get_plan_status': {
62
+ 'title': 'GetPlanStatusInput',
63
+ 'type': 'object',
64
+ 'properties': {
65
+ 'conversation_id': {'type': 'string', 'description': "Conversation ID (auto-injected)"}
66
+ },
67
+ 'required': ['conversation_id']
68
+ },
69
+ 'delete_plan': {
70
+ 'title': 'DeletePlanInput',
71
+ 'type': 'object',
72
+ 'properties': {
73
+ 'conversation_id': {'type': 'string', 'description': "Conversation ID (auto-injected)"}
74
+ },
75
+ 'required': ['conversation_id']
76
+ }
77
+ }
78
+
79
+ PlanningToolkit._toolkit_max_length = get_max_toolkit_length(selected_tools)
80
+
81
+ return create_model(
82
+ "planning",
83
+ # Tool selection
84
+ selected_tools=(
85
+ List[Literal[tuple(selected_tools)]],
86
+ Field(
87
+ default=list(selected_tools.keys()),
88
+ json_schema_extra={'args_schemas': selected_tools}
89
+ )
90
+ ),
91
+ __config__=ConfigDict(
92
+ json_schema_extra={
93
+ 'metadata': {
94
+ "label": "Planning",
95
+ "description": "Tools for managing multi-step execution plans with progress tracking. Uses PostgreSQL when configured, filesystem otherwise.",
96
+ "icon_url": None,
97
+ "max_length": PlanningToolkit._toolkit_max_length
98
+ }
99
+ }
100
+ )
101
+ )
102
+
103
+ @classmethod
104
+ def get_toolkit(
105
+ cls,
106
+ toolkit_name: Optional[str] = None,
107
+ selected_tools: Optional[List[str]] = None,
108
+ pgvector_configuration: Optional[dict] = None,
109
+ storage_dir: Optional[str] = None,
110
+ plan_callback: Optional[Any] = None,
111
+ conversation_id: Optional[str] = None,
112
+ **kwargs
113
+ ):
114
+ """
115
+ Create a PlanningToolkit instance with configured tools.
116
+
117
+ Args:
118
+ toolkit_name: Optional name prefix for tools
119
+ selected_tools: List of tool names to include (default: all)
120
+ pgvector_configuration: PostgreSQL configuration dict with connection_string.
121
+ If not provided, uses filesystem storage.
122
+ storage_dir: Directory for filesystem storage (when no pgvector_configuration)
123
+ plan_callback: Optional callback function called when plan changes (for CLI UI)
124
+ conversation_id: Conversation ID for scoping plans.
125
+ For server: from elitea_core payload. For CLI: session_id.
126
+ **kwargs: Additional configuration options
127
+
128
+ Returns:
129
+ PlanningToolkit instance with configured tools
130
+ """
131
+ if selected_tools is None:
132
+ selected_tools = ['update_plan', 'complete_step', 'get_plan_status', 'delete_plan']
133
+
134
+ tools = []
135
+
136
+ # Extract connection string from pgvector configuration (if provided)
137
+ connection_string = None
138
+ if pgvector_configuration:
139
+ connection_string = pgvector_configuration.get('connection_string', '')
140
+ if hasattr(connection_string, 'get_secret_value'):
141
+ connection_string = connection_string.get_secret_value()
142
+
143
+ # Create wrapper - it will auto-select storage backend
144
+ wrapper = PlanningWrapper(
145
+ connection_string=connection_string if connection_string else None,
146
+ conversation_id=conversation_id,
147
+ storage_dir=storage_dir,
148
+ plan_callback=plan_callback,
149
+ )
150
+
151
+ # Build tool name prefix
152
+ prefix = clean_string(toolkit_name, cls._toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
153
+
154
+ # Create tools from wrapper
155
+ available_tools = wrapper.get_available_tools()
156
+ for tool in available_tools:
157
+ if tool["name"] not in selected_tools:
158
+ continue
159
+
160
+ tools.append(BaseAction(
161
+ api_wrapper=wrapper,
162
+ name=prefix + tool["name"],
163
+ description=tool["description"],
164
+ args_schema=tool["args_schema"]
165
+ ))
166
+
167
+ return cls(tools=tools)
168
+
169
+ def get_tools(self) -> List[BaseTool]:
170
+ """Return the list of configured tools."""
171
+ return self.tools
@@ -9,6 +9,7 @@ from alita_sdk.tools import get_tools as alita_tools
9
9
  from .application import ApplicationToolkit
10
10
  from .artifact import ArtifactToolkit
11
11
  from .datasource import DatasourcesToolkit
12
+ from .planning import PlanningToolkit
12
13
  from .prompt import PromptToolkit
13
14
  from .subgraph import SubgraphToolkit
14
15
  from .vectorstore import VectorStoreToolkit
@@ -21,6 +22,7 @@ from ...community import get_toolkits as community_toolkits, get_tools as commun
21
22
  from ...tools.memory import MemoryToolkit
22
23
  from ..utils.mcp_oauth import canonical_resource, McpAuthorizationRequired
23
24
  from ...tools.utils import TOOLKIT_SPLITTER
25
+ from alita_sdk.tools import _inject_toolkit_id
24
26
 
25
27
  logger = logging.getLogger(__name__)
26
28
 
@@ -29,6 +31,7 @@ def get_toolkits():
29
31
  core_toolkits = [
30
32
  ArtifactToolkit.toolkit_config_schema(),
31
33
  MemoryToolkit.toolkit_config_schema(),
34
+ PlanningToolkit.toolkit_config_schema(),
32
35
  VectorStoreToolkit.toolkit_config_schema(),
33
36
  SandboxToolkit.toolkit_config_schema(),
34
37
  ImageGenerationToolkit.toolkit_config_schema(),
@@ -38,7 +41,7 @@ def get_toolkits():
38
41
  return core_toolkits + community_toolkits() + alita_toolkits()
39
42
 
40
43
 
41
- def get_tools(tools_list: list, alita_client, llm, memory_store: BaseStore = None, debug_mode: Optional[bool] = False, mcp_tokens: Optional[dict] = None) -> list:
44
+ def get_tools(tools_list: list, alita_client=None, llm=None, memory_store: BaseStore = None, debug_mode: Optional[bool] = False, mcp_tokens: Optional[dict] = None, conversation_id: Optional[str] = None) -> list:
42
45
  prompts = []
43
46
  tools = []
44
47
 
@@ -92,7 +95,7 @@ def get_tools(tools_list: list, alita_client, llm, memory_store: BaseStore = Non
92
95
  logger.warning("Image generation internal tool requested "
93
96
  "but no image generation model configured")
94
97
  elif tool['type'] == 'artifact':
95
- tools.extend(ArtifactToolkit.get_toolkit(
98
+ toolkit_tools = ArtifactToolkit.get_toolkit(
96
99
  client=alita_client,
97
100
  bucket=tool['settings']['bucket'],
98
101
  toolkit_name=tool.get('toolkit_name', ''),
@@ -102,13 +105,36 @@ def get_tools(tools_list: list, alita_client, llm, memory_store: BaseStore = Non
102
105
  pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
103
106
  embedding_model=tool['settings'].get('embedding_model'),
104
107
  collection_name=f"{tool.get('toolkit_name')}",
105
- collection_schema = str(tool['id'])
106
- ).get_tools())
108
+ collection_schema=str(tool['id']),
109
+ ).get_tools()
110
+ # Inject toolkit_id for artifact tools as well
111
+ _inject_toolkit_id(tool, toolkit_tools)
112
+ tools.extend(toolkit_tools)
113
+
107
114
  elif tool['type'] == 'vectorstore':
108
115
  tools.extend(VectorStoreToolkit.get_toolkit(
109
116
  llm=llm,
110
117
  toolkit_name=tool.get('toolkit_name', ''),
111
118
  **tool['settings']).get_tools())
119
+ elif tool['type'] == 'planning':
120
+ # Planning toolkit for multi-step task tracking
121
+ # Try to fetch pgvector_project_connstr from project secrets
122
+ pgvector_connstr = None
123
+ if alita_client:
124
+ try:
125
+ pgvector_connstr = alita_client.unsecret('pgvector_project_connstr')
126
+ if pgvector_connstr:
127
+ logger.info("Using pgvector_project_connstr for planning toolkit")
128
+ except Exception as e:
129
+ logger.debug(f"pgvector_project_connstr not available: {e}")
130
+
131
+ pgvector_config = {'connection_string': pgvector_connstr} if pgvector_connstr else {}
132
+ tools.extend(PlanningToolkit.get_toolkit(
133
+ toolkit_name=tool.get('toolkit_name', ''),
134
+ selected_tools=tool['settings'].get('selected_tools', []),
135
+ pgvector_configuration=pgvector_config,
136
+ conversation_id=conversation_id or tool['settings'].get('conversation_id'),
137
+ ).get_tools())
112
138
  elif tool['type'] == 'mcp':
113
139
  # remote mcp tool initialization with token injection
114
140
  settings = dict(tool['settings'])
@@ -153,8 +179,15 @@ def get_tools(tools_list: list, alita_client, llm, memory_store: BaseStore = Non
153
179
  toolkit_name=tool.get('toolkit_name', ''),
154
180
  client=alita_client,
155
181
  **settings).get_tools())
182
+ except McpAuthorizationRequired:
183
+ # Re-raise auth required exceptions directly
184
+ raise
156
185
  except Exception as e:
157
- if isinstance(e, McpAuthorizationRequired):
186
+ # Check for wrapped McpAuthorizationRequired
187
+ if hasattr(e, '__cause__') and isinstance(e.__cause__, McpAuthorizationRequired):
188
+ raise e.__cause__
189
+ # Check exception class name as fallback
190
+ if e.__class__.__name__ == 'McpAuthorizationRequired':
158
191
  raise
159
192
  logger.error(f"Error initializing toolkit for tool '{tool.get('name', 'unknown')}': {e}", exc_info=True)
160
193
  if debug_mode:
@@ -271,7 +304,7 @@ def _init_single_mcp_tool(server_toolkit_name, toolkit_name, available_tool, ali
271
304
  tool_name = f'{toolkit_name}{TOOLKIT_SPLITTER}{available_tool["name"]}'
272
305
  return McpServerTool(
273
306
  name=tool_name,
274
- description=f"MCP for a tool '{tool_name}': {available_tool.get("description", "")}",
307
+ description=f"MCP for a tool '{tool_name}': {available_tool.get('description', '')}",
275
308
  args_schema=McpServerTool.create_pydantic_model_from_schema(
276
309
  available_tool.get("inputSchema", {})
277
310
  ),