alita-sdk 0.3.457b0__py3-none-any.whl → 0.3.459__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.
- alita_sdk/cli/__init__.py +10 -0
- alita_sdk/cli/__main__.py +17 -0
- alita_sdk/cli/agents.py +1055 -0
- alita_sdk/cli/cli.py +156 -0
- alita_sdk/cli/config.py +134 -0
- alita_sdk/cli/formatting.py +182 -0
- alita_sdk/cli/toolkit.py +330 -0
- alita_sdk/runtime/toolkits/artifact.py +5 -6
- alita_sdk/runtime/tools/function.py +3 -4
- alita_sdk/tools/qtest/api_wrapper.py +790 -14
- alita_sdk/tools/sharepoint/api_wrapper.py +22 -2
- alita_sdk/tools/sharepoint/authorization_helper.py +17 -1
- {alita_sdk-0.3.457b0.dist-info → alita_sdk-0.3.459.dist-info}/METADATA +6 -1
- {alita_sdk-0.3.457b0.dist-info → alita_sdk-0.3.459.dist-info}/RECORD +18 -10
- alita_sdk-0.3.459.dist-info/entry_points.txt +2 -0
- {alita_sdk-0.3.457b0.dist-info → alita_sdk-0.3.459.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.457b0.dist-info → alita_sdk-0.3.459.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.457b0.dist-info → alita_sdk-0.3.459.dist-info}/top_level.txt +0 -0
alita_sdk/cli/toolkit.py
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Toolkit testing commands for Alita CLI.
|
|
3
|
+
|
|
4
|
+
Provides commands to list, inspect, and test toolkits directly from the command line.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Optional, Dict, Any
|
|
11
|
+
|
|
12
|
+
from .cli import get_client
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group()
|
|
18
|
+
def toolkit():
|
|
19
|
+
"""Toolkit testing commands."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@toolkit.command('list')
|
|
24
|
+
@click.option('--failed', is_flag=True, help='Show failed imports')
|
|
25
|
+
@click.pass_context
|
|
26
|
+
def toolkit_list(ctx, failed: bool):
|
|
27
|
+
"""List all available toolkits."""
|
|
28
|
+
formatter = ctx.obj['formatter']
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
# Import toolkit registry
|
|
32
|
+
from alita_sdk.tools import AVAILABLE_TOOLS, AVAILABLE_TOOLKITS, FAILED_IMPORTS
|
|
33
|
+
|
|
34
|
+
if failed:
|
|
35
|
+
# Show failed imports
|
|
36
|
+
if FAILED_IMPORTS:
|
|
37
|
+
click.echo("\nFailed toolkit imports:\n")
|
|
38
|
+
for name, error in FAILED_IMPORTS.items():
|
|
39
|
+
click.echo(f" - {name}: {error}")
|
|
40
|
+
click.echo(f"\nTotal failed: {len(FAILED_IMPORTS)}")
|
|
41
|
+
else:
|
|
42
|
+
click.echo("\nNo failed imports")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
# Build toolkit list
|
|
46
|
+
toolkits = []
|
|
47
|
+
for name, toolkit_dict in AVAILABLE_TOOLS.items():
|
|
48
|
+
toolkit_class_name = None
|
|
49
|
+
if 'toolkit_class' in toolkit_dict:
|
|
50
|
+
toolkit_class_name = toolkit_dict['toolkit_class'].__name__
|
|
51
|
+
|
|
52
|
+
toolkits.append({
|
|
53
|
+
'name': name,
|
|
54
|
+
'class_name': toolkit_class_name,
|
|
55
|
+
'has_get_tools': 'get_tools' in toolkit_dict
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
# Format and display
|
|
59
|
+
output = formatter.format_toolkit_list(toolkits)
|
|
60
|
+
click.echo(output)
|
|
61
|
+
|
|
62
|
+
except Exception as e:
|
|
63
|
+
logger.exception("Failed to list toolkits")
|
|
64
|
+
click.echo(formatter.format_error(str(e)), err=True)
|
|
65
|
+
raise click.Abort()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@toolkit.command('schema')
|
|
69
|
+
@click.argument('toolkit_name')
|
|
70
|
+
@click.pass_context
|
|
71
|
+
def toolkit_schema(ctx, toolkit_name: str):
|
|
72
|
+
"""
|
|
73
|
+
Show configuration schema for a toolkit.
|
|
74
|
+
|
|
75
|
+
TOOLKIT_NAME: Name of the toolkit (e.g., 'jira', 'github', 'confluence')
|
|
76
|
+
"""
|
|
77
|
+
formatter = ctx.obj['formatter']
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
# Import toolkit registry
|
|
81
|
+
from alita_sdk.tools import AVAILABLE_TOOLKITS
|
|
82
|
+
|
|
83
|
+
# Find toolkit class
|
|
84
|
+
toolkit_class = None
|
|
85
|
+
for name, cls in AVAILABLE_TOOLKITS.items():
|
|
86
|
+
if name.lower().replace('toolkit', '').replace('alita', '').strip() == toolkit_name.lower():
|
|
87
|
+
toolkit_class = cls
|
|
88
|
+
break
|
|
89
|
+
|
|
90
|
+
if not toolkit_class:
|
|
91
|
+
# Try direct match
|
|
92
|
+
for name, cls in AVAILABLE_TOOLKITS.items():
|
|
93
|
+
if toolkit_name.lower() in name.lower():
|
|
94
|
+
toolkit_class = cls
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
if not toolkit_class:
|
|
98
|
+
available = [name.lower().replace('toolkit', '').replace('alita', '').strip()
|
|
99
|
+
for name in AVAILABLE_TOOLKITS.keys()]
|
|
100
|
+
raise click.ClickException(
|
|
101
|
+
f"Toolkit '{toolkit_name}' not found.\n"
|
|
102
|
+
f"Available toolkits: {', '.join(sorted(set(available)))}"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Get schema
|
|
106
|
+
schema_model = toolkit_class.toolkit_config_schema()
|
|
107
|
+
schema = schema_model.model_json_schema()
|
|
108
|
+
|
|
109
|
+
# Format and display
|
|
110
|
+
if formatter.__class__.__name__ == 'JSONFormatter':
|
|
111
|
+
output = formatter.format_toolkit_schema(toolkit_name, schema)
|
|
112
|
+
else:
|
|
113
|
+
output = formatter.format_toolkit_schema(toolkit_name, schema)
|
|
114
|
+
|
|
115
|
+
click.echo(output)
|
|
116
|
+
|
|
117
|
+
except click.ClickException:
|
|
118
|
+
raise
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.exception(f"Failed to get schema for toolkit '{toolkit_name}'")
|
|
121
|
+
click.echo(formatter.format_error(str(e)), err=True)
|
|
122
|
+
raise click.Abort()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@toolkit.command('test')
|
|
126
|
+
@click.argument('toolkit_type')
|
|
127
|
+
@click.option('--tool', required=True, help='Tool name to execute')
|
|
128
|
+
@click.option('--config', 'config_file', type=click.File('r'),
|
|
129
|
+
help='Toolkit configuration JSON file')
|
|
130
|
+
@click.option('--params', type=click.File('r'),
|
|
131
|
+
help='Tool parameters JSON file')
|
|
132
|
+
@click.option('--param', multiple=True,
|
|
133
|
+
help='Tool parameter as key=value (can be used multiple times)')
|
|
134
|
+
@click.option('--llm-model', default='gpt-4o-mini',
|
|
135
|
+
help='LLM model to use (default: gpt-4o-mini)')
|
|
136
|
+
@click.option('--temperature', default=0.1, type=float,
|
|
137
|
+
help='LLM temperature (default: 0.1)')
|
|
138
|
+
@click.option('--max-tokens', default=1000, type=int,
|
|
139
|
+
help='LLM max tokens (default: 1000)')
|
|
140
|
+
@click.pass_context
|
|
141
|
+
def toolkit_test(ctx, toolkit_type: str, tool: str, config_file, params,
|
|
142
|
+
param, llm_model: str, temperature: float, max_tokens: int):
|
|
143
|
+
"""
|
|
144
|
+
Test a specific tool from a toolkit.
|
|
145
|
+
|
|
146
|
+
TOOLKIT_TYPE: Type of toolkit (e.g., 'jira', 'github', 'confluence')
|
|
147
|
+
|
|
148
|
+
Examples:
|
|
149
|
+
|
|
150
|
+
# Test with config and params from files
|
|
151
|
+
alita-cli toolkit test jira --tool get_issue \\
|
|
152
|
+
--config jira-config.json --params params.json
|
|
153
|
+
|
|
154
|
+
# Test with inline parameters
|
|
155
|
+
alita-cli toolkit test jira --tool get_issue \\
|
|
156
|
+
--config jira-config.json --param issue_key=PROJ-123
|
|
157
|
+
|
|
158
|
+
# Test with JSON output for scripting
|
|
159
|
+
alita-cli --output json toolkit test github --tool get_issue \\
|
|
160
|
+
--config github-config.json --param owner=user --param repo=myrepo
|
|
161
|
+
"""
|
|
162
|
+
formatter = ctx.obj['formatter']
|
|
163
|
+
client = get_client(ctx)
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
# Load toolkit configuration
|
|
167
|
+
toolkit_config = {}
|
|
168
|
+
if config_file:
|
|
169
|
+
toolkit_config = json.load(config_file)
|
|
170
|
+
logger.debug(f"Loaded toolkit config from {config_file.name}")
|
|
171
|
+
|
|
172
|
+
# Load tool parameters
|
|
173
|
+
tool_params = {}
|
|
174
|
+
if params:
|
|
175
|
+
tool_params = json.load(params)
|
|
176
|
+
logger.debug(f"Loaded tool params from {params.name}")
|
|
177
|
+
|
|
178
|
+
# Parse inline parameters
|
|
179
|
+
if param:
|
|
180
|
+
for param_pair in param:
|
|
181
|
+
if '=' not in param_pair:
|
|
182
|
+
raise click.ClickException(
|
|
183
|
+
f"Invalid parameter format: '{param_pair}'. "
|
|
184
|
+
"Use --param key=value"
|
|
185
|
+
)
|
|
186
|
+
key, value = param_pair.split('=', 1)
|
|
187
|
+
|
|
188
|
+
# Try to parse as JSON for complex values
|
|
189
|
+
try:
|
|
190
|
+
tool_params[key] = json.loads(value)
|
|
191
|
+
except json.JSONDecodeError:
|
|
192
|
+
tool_params[key] = value
|
|
193
|
+
|
|
194
|
+
logger.debug(f"Parsed {len(param)} inline parameters")
|
|
195
|
+
|
|
196
|
+
# Prepare full toolkit configuration
|
|
197
|
+
full_config = {
|
|
198
|
+
'toolkit_name': toolkit_type,
|
|
199
|
+
'type': toolkit_type,
|
|
200
|
+
'settings': toolkit_config
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# LLM configuration
|
|
204
|
+
llm_config = {
|
|
205
|
+
'temperature': temperature,
|
|
206
|
+
'max_tokens': max_tokens,
|
|
207
|
+
'top_p': 1.0
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# Execute test
|
|
211
|
+
logger.info(f"Testing tool '{tool}' from toolkit '{toolkit_type}'")
|
|
212
|
+
result = client.test_toolkit_tool(
|
|
213
|
+
toolkit_config=full_config,
|
|
214
|
+
tool_name=tool,
|
|
215
|
+
tool_params=tool_params,
|
|
216
|
+
llm_model=llm_model,
|
|
217
|
+
llm_config=llm_config
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Format and display result
|
|
221
|
+
output = formatter.format_toolkit_result(result)
|
|
222
|
+
click.echo(output)
|
|
223
|
+
|
|
224
|
+
# Exit with error code if test failed
|
|
225
|
+
if not result.get('success', False):
|
|
226
|
+
raise click.Abort()
|
|
227
|
+
|
|
228
|
+
except click.ClickException:
|
|
229
|
+
raise
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logger.exception("Failed to execute toolkit test")
|
|
232
|
+
click.echo(formatter.format_error(str(e)), err=True)
|
|
233
|
+
raise click.Abort()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@toolkit.command('tools')
|
|
237
|
+
@click.argument('toolkit_type')
|
|
238
|
+
@click.option('--config', 'config_file', type=click.File('r'),
|
|
239
|
+
help='Toolkit configuration JSON file (required for some toolkits)')
|
|
240
|
+
@click.pass_context
|
|
241
|
+
def toolkit_tools(ctx, toolkit_type: str, config_file):
|
|
242
|
+
"""
|
|
243
|
+
List available tools for a specific toolkit.
|
|
244
|
+
|
|
245
|
+
TOOLKIT_TYPE: Type of toolkit (e.g., 'jira', 'github', 'confluence')
|
|
246
|
+
|
|
247
|
+
Some toolkits require configuration to determine available tools.
|
|
248
|
+
Use --config to provide configuration if needed.
|
|
249
|
+
"""
|
|
250
|
+
formatter = ctx.obj['formatter']
|
|
251
|
+
client = get_client(ctx)
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
# Load toolkit configuration if provided
|
|
255
|
+
toolkit_config = {}
|
|
256
|
+
if config_file:
|
|
257
|
+
toolkit_config = json.load(config_file)
|
|
258
|
+
|
|
259
|
+
# Import and instantiate toolkit
|
|
260
|
+
from alita_sdk.tools import AVAILABLE_TOOLS
|
|
261
|
+
|
|
262
|
+
if toolkit_type not in AVAILABLE_TOOLS:
|
|
263
|
+
raise click.ClickException(
|
|
264
|
+
f"Toolkit '{toolkit_type}' not found. "
|
|
265
|
+
f"Use 'alita-cli toolkit list' to see available toolkits."
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
toolkit_entry = AVAILABLE_TOOLS[toolkit_type]
|
|
269
|
+
|
|
270
|
+
if 'toolkit_class' not in toolkit_entry:
|
|
271
|
+
raise click.ClickException(
|
|
272
|
+
f"Toolkit '{toolkit_type}' does not support tool listing"
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
# Get toolkit class and instantiate
|
|
276
|
+
toolkit_class = toolkit_entry['toolkit_class']
|
|
277
|
+
|
|
278
|
+
# Create minimal configuration
|
|
279
|
+
full_config = {
|
|
280
|
+
'toolkit_name': toolkit_type,
|
|
281
|
+
'type': toolkit_type,
|
|
282
|
+
'settings': toolkit_config
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
# Try to get available tools via API wrapper
|
|
286
|
+
try:
|
|
287
|
+
# Instantiate API wrapper if possible
|
|
288
|
+
api_wrapper_class = None
|
|
289
|
+
|
|
290
|
+
# Find API wrapper class by inspecting toolkit
|
|
291
|
+
import inspect
|
|
292
|
+
for name, obj in inspect.getmembers(toolkit_class):
|
|
293
|
+
if inspect.isclass(obj) and 'ApiWrapper' in obj.__name__:
|
|
294
|
+
api_wrapper_class = obj
|
|
295
|
+
break
|
|
296
|
+
|
|
297
|
+
if api_wrapper_class:
|
|
298
|
+
try:
|
|
299
|
+
api_wrapper = api_wrapper_class(**toolkit_config)
|
|
300
|
+
available_tools = api_wrapper.get_available_tools()
|
|
301
|
+
|
|
302
|
+
# Format tools list
|
|
303
|
+
click.echo(f"\nAvailable tools for {toolkit_type}:\n")
|
|
304
|
+
for tool_info in available_tools:
|
|
305
|
+
tool_name = tool_info.get('name', 'unknown')
|
|
306
|
+
description = tool_info.get('description', '')
|
|
307
|
+
click.echo(f" - {tool_name}")
|
|
308
|
+
if description:
|
|
309
|
+
click.echo(f" {description}")
|
|
310
|
+
|
|
311
|
+
click.echo(f"\nTotal: {len(available_tools)} tools")
|
|
312
|
+
return
|
|
313
|
+
|
|
314
|
+
except Exception as e:
|
|
315
|
+
logger.debug(f"Could not instantiate API wrapper: {e}")
|
|
316
|
+
|
|
317
|
+
# Fallback: show general info
|
|
318
|
+
click.echo(f"\n{toolkit_type} toolkit is available")
|
|
319
|
+
click.echo("Use 'alita-cli toolkit schema {toolkit_type}' to see configuration options")
|
|
320
|
+
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logger.exception("Failed to list tools")
|
|
323
|
+
raise click.ClickException(str(e))
|
|
324
|
+
|
|
325
|
+
except click.ClickException:
|
|
326
|
+
raise
|
|
327
|
+
except Exception as e:
|
|
328
|
+
logger.exception("Failed to list toolkit tools")
|
|
329
|
+
click.echo(formatter.format_error(str(e)), err=True)
|
|
330
|
+
raise click.Abort()
|
|
@@ -23,11 +23,7 @@ class ArtifactToolkit(BaseToolkit):
|
|
|
23
23
|
# client = (Any, FieldInfo(description="Client object", required=True, autopopulate=True)),
|
|
24
24
|
bucket=(str, FieldInfo(
|
|
25
25
|
description="Bucket name",
|
|
26
|
-
pattern=r'^[a-z][a-z0-9-]*$'
|
|
27
|
-
json_schema_extra={
|
|
28
|
-
'toolkit_name': True,
|
|
29
|
-
'max_toolkit_length': ArtifactToolkit.toolkit_max_length
|
|
30
|
-
}
|
|
26
|
+
pattern=r'^[a-z][a-z0-9-]*$'
|
|
31
27
|
)),
|
|
32
28
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
33
29
|
# indexer settings
|
|
@@ -37,7 +33,10 @@ class ArtifactToolkit(BaseToolkit):
|
|
|
37
33
|
embedding_model=(Optional[str], Field(default=None, description="Embedding configuration.",
|
|
38
34
|
json_schema_extra={'configuration_model': 'embedding'})),
|
|
39
35
|
|
|
40
|
-
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Artifact",
|
|
36
|
+
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Artifact",
|
|
37
|
+
"icon_url": None,
|
|
38
|
+
"max_length": ArtifactToolkit.toolkit_max_length
|
|
39
|
+
}})
|
|
41
40
|
)
|
|
42
41
|
|
|
43
42
|
@classmethod
|
|
@@ -34,7 +34,8 @@ class FunctionTool(BaseTool):
|
|
|
34
34
|
|
|
35
35
|
del state_copy['messages'] # remove messages to avoid issues with pickling without langchain-core
|
|
36
36
|
# inject state into the code block as alita_state variable
|
|
37
|
-
|
|
37
|
+
state_json = json.dumps(state_copy, ensure_ascii=False)
|
|
38
|
+
pyodide_predata = f'#state dict\nimport json\nalita_state = {repr(state_json)}\n'
|
|
38
39
|
return pyodide_predata
|
|
39
40
|
|
|
40
41
|
def _handle_pyodide_output(self, tool_result: Any) -> dict:
|
|
@@ -94,9 +95,7 @@ class FunctionTool(BaseTool):
|
|
|
94
95
|
# special handler for PyodideSandboxTool
|
|
95
96
|
if self._is_pyodide_tool():
|
|
96
97
|
code = func_args['code']
|
|
97
|
-
func_args['code'] =
|
|
98
|
-
# handle new lines in the code properly
|
|
99
|
-
.replace('\\n','\\\\n'))
|
|
98
|
+
func_args['code'] = f"{self._prepare_pyodide_input(state)}\n{code}"
|
|
100
99
|
try:
|
|
101
100
|
tool_result = self.tool.invoke(func_args, config, **kwargs)
|
|
102
101
|
dispatch_custom_event(
|