quantalogic 0.61.3__py3-none-any.whl → 0.92__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.
Files changed (35) hide show
  1. quantalogic/agent.py +0 -1
  2. quantalogic/flow/__init__.py +16 -34
  3. quantalogic/main.py +11 -6
  4. quantalogic/tools/action_gen.py +1 -1
  5. quantalogic/tools/tool.py +8 -500
  6. quantalogic-0.92.dist-info/METADATA +448 -0
  7. {quantalogic-0.61.3.dist-info → quantalogic-0.92.dist-info}/RECORD +10 -33
  8. {quantalogic-0.61.3.dist-info → quantalogic-0.92.dist-info}/WHEEL +1 -1
  9. quantalogic-0.92.dist-info/entry_points.txt +3 -0
  10. quantalogic/codeact/__init__.py +0 -0
  11. quantalogic/codeact/agent.py +0 -499
  12. quantalogic/codeact/cli.py +0 -232
  13. quantalogic/codeact/constants.py +0 -9
  14. quantalogic/codeact/events.py +0 -78
  15. quantalogic/codeact/llm_util.py +0 -76
  16. quantalogic/codeact/prompts/error_format.j2 +0 -11
  17. quantalogic/codeact/prompts/generate_action.j2 +0 -26
  18. quantalogic/codeact/prompts/generate_program.j2 +0 -39
  19. quantalogic/codeact/prompts/response_format.j2 +0 -11
  20. quantalogic/codeact/tools_manager.py +0 -135
  21. quantalogic/codeact/utils.py +0 -135
  22. quantalogic/flow/flow.py +0 -960
  23. quantalogic/flow/flow_extractor.py +0 -723
  24. quantalogic/flow/flow_generator.py +0 -294
  25. quantalogic/flow/flow_manager.py +0 -637
  26. quantalogic/flow/flow_manager_schema.py +0 -255
  27. quantalogic/flow/flow_mermaid.py +0 -365
  28. quantalogic/flow/flow_validator.py +0 -479
  29. quantalogic/flow/flow_yaml.linkedin.md +0 -31
  30. quantalogic/flow/flow_yaml.md +0 -767
  31. quantalogic/flow/templates/prompt_check_inventory.j2 +0 -1
  32. quantalogic/flow/templates/system_check_inventory.j2 +0 -1
  33. quantalogic-0.61.3.dist-info/METADATA +0 -900
  34. quantalogic-0.61.3.dist-info/entry_points.txt +0 -6
  35. {quantalogic-0.61.3.dist-info → quantalogic-0.92.dist-info}/LICENSE +0 -0
quantalogic/agent.py CHANGED
@@ -23,7 +23,6 @@ from quantalogic.utils import get_environment
23
23
  from quantalogic.utils.ask_user_validation import console_ask_for_user_validation
24
24
  from quantalogic.xml_parser import ToleranceXMLParser
25
25
  from quantalogic.xml_tool_parser import ToolParser
26
- import uuid
27
26
 
28
27
  # Maximum ratio occupancy of the occupied memory
29
28
  MAX_OCCUPANCY = 90.0
@@ -1,40 +1,22 @@
1
- """
2
- Flow Package Initialization
1
+ """Stub alias for backwards compatibility: re-export Flow API from the quantalogic_flow package."""
2
+ from quantalogic_flow import (
3
+ Nodes,
4
+ Workflow,
5
+ WorkflowEngine,
6
+ WorkflowManager,
7
+ extract_workflow_from_file,
8
+ generate_executable_script,
9
+ generate_mermaid_diagram,
10
+ validate_workflow_definition,
11
+ )
3
12
 
4
- This module initializes the flow package and provides package-level imports.
5
- Now supports nested workflows for hierarchical flow definitions.
6
-
7
- Key Visualization Utilities:
8
- - generate_mermaid_diagram(): Convert workflow definitions to visual Mermaid flowcharts
9
- - Supports pastel-colored node styling
10
- - Generates interactive, readable workflow diagrams
11
- - Handles complex workflows with multiple node types
12
-
13
- - Generates descriptive labels
14
- - Supports conditional node detection
15
- """
16
-
17
- from loguru import logger
18
-
19
- # Expose key components for easy importing
20
- from .flow import Nodes, Workflow, WorkflowEngine
21
- from .flow_extractor import extract_workflow_from_file
22
- from .flow_generator import generate_executable_script
23
- from .flow_manager import WorkflowManager
24
- from .flow_mermaid import generate_mermaid_diagram
25
- from .flow_validator import validate_workflow_definition
26
-
27
- # Define which symbols are exported when using `from flow import *`
28
13
  __all__ = [
29
- "WorkflowManager",
14
+ "extract_workflow_from_file",
15
+ "generate_executable_script",
16
+ "generate_mermaid_diagram",
30
17
  "Nodes",
18
+ "validate_workflow_definition",
31
19
  "Workflow",
32
20
  "WorkflowEngine",
33
- "generate_mermaid_diagram",
34
- "extract_workflow_from_file",
35
- "generate_executable_script",
36
- "validate_workflow_definition"
21
+ "WorkflowManager",
37
22
  ]
38
-
39
- # Package-level logger configuration
40
- logger.info("Initializing Quantalogic Flow Package")
quantalogic/main.py CHANGED
@@ -18,6 +18,11 @@ load_dotenv()
18
18
 
19
19
  # Configure logger
20
20
  logger.remove()
21
+ logger.add(
22
+ sys.stderr,
23
+ level="ERROR", # Changed from WARNING to ERROR
24
+ format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
25
+ )
21
26
 
22
27
  from rich.console import Console # noqa: E402
23
28
  from rich.panel import Panel # noqa: E402
@@ -98,9 +103,9 @@ def restore_terminal(old_settings):
98
103
  )
99
104
  @click.option(
100
105
  "--log",
101
- type=click.Choice(["info", "debug", "warning"]),
106
+ type=click.Choice(["info", "debug", "warning", "error"]),
102
107
  default="info",
103
- help="Set logging level (info/debug/warning).",
108
+ help="Set logging level (info/debug/warning/error).",
104
109
  )
105
110
  @click.option("--verbose", is_flag=True, help="Enable verbose output.")
106
111
  @click.option("--mode", type=click.Choice(AGENT_MODES), default="basic", help="Agent mode (code/search/full/chat).")
@@ -196,9 +201,9 @@ def cli(
196
201
  @click.option("--mode", type=click.Choice(AGENT_MODES), default="basic", help="Agent mode (code/search/full/chat).")
197
202
  @click.option(
198
203
  "--log",
199
- type=click.Choice(["info", "debug", "warning"]),
204
+ type=click.Choice(["info", "debug", "warning", "error"]),
200
205
  default="info",
201
- help="Set logging level (info/debug/warning).",
206
+ help="Set logging level (info/debug/warning/error).",
202
207
  )
203
208
  @click.option(
204
209
  "--vision-model-name",
@@ -318,9 +323,9 @@ def list_models(search: Optional[str] = None):
318
323
  )
319
324
  @click.option(
320
325
  "--log",
321
- type=click.Choice(["info", "debug", "warning"]),
326
+ type=click.Choice(["info", "debug", "warning", "error"]),
322
327
  default="info",
323
- help="Set logging level (info/debug/warning).",
328
+ help="Set logging level (info/debug/warning/error).",
324
329
  )
325
330
  @click.option("--verbose", is_flag=True, help="Enable verbose output.")
326
331
  @click.option(
@@ -8,8 +8,8 @@ from typing import Callable, Dict, List
8
8
  import litellm
9
9
  import typer
10
10
  from loguru import logger
11
+ from quantalogic_pythonbox.python_interpreter import execute_async
11
12
 
12
- from quantalogic.python_interpreter import execute_async
13
13
  from quantalogic.tools.tool import Tool, ToolArgument
14
14
 
15
15
  # Configure loguru to log to a file with rotation, matching original
quantalogic/tools/tool.py CHANGED
@@ -1,500 +1,8 @@
1
- """Module for defining tool arguments and base tool classes.
2
-
3
- This module provides base classes and data models for creating configurable tools
4
- with type-validated arguments and execution methods.
5
- """
6
-
7
- import ast
8
- import asyncio # Added for asynchronous support
9
- import inspect
10
- from typing import Any, Callable, Literal, TypeVar
11
-
12
- from docstring_parser import parse as parse_docstring
13
- from pydantic import BaseModel, ConfigDict, Field, field_validator
14
-
15
- # Type variable for create_tool to preserve function signature
16
- F = TypeVar('F', bound=Callable[..., Any])
17
-
18
- class ToolArgument(BaseModel):
19
- """Represents an argument for a tool with validation and description.
20
-
21
- Attributes:
22
- name: The name of the argument.
23
- arg_type: The type of the argument (integer, float, boolean).
24
- description: Optional description of the argument.
25
- required: Indicates if the argument is mandatory.
26
- default: Optional default value for the argument.
27
- example: Optional example value to illustrate the argument's usage.
28
- """
29
-
30
- name: str = Field(..., description="The name of the argument.")
31
- arg_type: Literal["string", "int", "float", "boolean"] = Field(
32
- ..., description="The type of the argument. Must be one of: string, integer, float, boolean."
33
- )
34
- description: str | None = Field(default=None, description="A brief description of the argument.")
35
- required: bool = Field(default=False, description="Indicates if the argument is required.")
36
- default: str | None = Field(
37
- default=None, description="The default value for the argument. This parameter is required."
38
- )
39
- example: str | None = Field(default=None, description="An example value to illustrate the argument's usage.")
40
-
41
- class ToolDefinition(BaseModel):
42
- """Base class for defining tool configurations without execution logic.
43
-
44
- Attributes:
45
- name: Unique name of the tool.
46
- description: Brief description of the tool's functionality.
47
- arguments: List of arguments the tool accepts.
48
- return_type: The return type of the tool's execution method. Defaults to "str".
49
- need_validation: Flag to indicate if tool requires validation.
50
- """
51
-
52
- model_config = ConfigDict(extra="allow", validate_assignment=True)
53
-
54
- name: str = Field(..., description="The unique name of the tool.")
55
- description: str = Field(..., description="A brief description of what the tool does.")
56
- arguments: list[ToolArgument] = Field(default_factory=list, description="A list of arguments the tool accepts.")
57
- return_type: str = Field(default="str", description="The return type of the tool's execution method.")
58
- need_validation: bool = Field(
59
- default=False,
60
- description="When True, requires user confirmation before execution. Useful for tools that perform potentially destructive operations.",
61
- )
62
- need_post_process: bool = Field(
63
- default=True,
64
- description="When True, requires user confirmation before execution. Useful for tools that perform potentially destructive operations.",
65
- )
66
- need_variables: bool = Field(
67
- default=False,
68
- description="When True, provides access to the agent's variable store. Required for tools that need to interpolate variables (e.g., Jinja templates).",
69
- )
70
- need_caller_context_memory: bool = Field(
71
- default=False,
72
- description="When True, provides access to the agent's conversation history. Useful for tools that need context from previous interactions.",
73
- )
74
-
75
- def get_properties(self, exclude: list[str] | None = None) -> dict[str, Any]:
76
- """Return a dictionary of all non-None properties, excluding Tool class fields and specified fields.
77
-
78
- Args:
79
- exclude: Optional list of field names to exclude from the result
80
-
81
- Returns:
82
- Dictionary of property names and values, excluding Tool class fields and specified fields.
83
- """
84
- exclude = exclude or []
85
- tool_fields = {
86
- "name",
87
- "description",
88
- "arguments",
89
- "return_type",
90
- "need_validation",
91
- "need_variables",
92
- "need_caller_context_memory",
93
- }
94
- properties = {}
95
-
96
- for name, value in self.__dict__.items():
97
- if name not in tool_fields and name not in exclude and value is not None and not name.startswith("_"):
98
- properties[name] = value
99
-
100
- return properties
101
-
102
- def to_json(self) -> str:
103
- """Convert the tool to a JSON string representation.
104
-
105
- Returns:
106
- A JSON string of the tool's configuration.
107
- """
108
- return self.model_dump_json()
109
-
110
- def to_markdown(self) -> str:
111
- """Create a comprehensive Markdown representation of the tool.
112
-
113
- Returns:
114
- A detailed Markdown string representing the tool's configuration and usage.
115
- """
116
- # Tool name and description
117
- markdown = f"`{self.name}`:\n"
118
- markdown += f"- **Description**: {self.description}\n\n"
119
-
120
- properties_injectable = self.get_injectable_properties_in_execution()
121
-
122
- # Parameters section
123
- if self.arguments:
124
- markdown += "- **Parameters**:\n"
125
- parameters = ""
126
- for arg in self.arguments:
127
- # Skip if parameter name matches an object property with non-None value
128
- if properties_injectable.get(arg.name) is not None:
129
- continue
130
-
131
- required_status = "required" if arg.required else "optional"
132
- # Prioritize example, then default, then create a generic description
133
- value_info = ""
134
- if arg.example is not None:
135
- value_info = f" (example: `{arg.example}`)"
136
- elif arg.default is not None:
137
- value_info = f" (default: `{arg.default}`)"
138
-
139
- parameters += (
140
- f" - `{arg.name}`: " f"({required_status}{value_info})\n" f" {arg.description or ''}\n"
141
- )
142
- if len(parameters) > 0:
143
- markdown += parameters + "\n\n"
144
- else:
145
- markdown += "None\n\n"
146
-
147
- # Usage section with XML-style example
148
- markdown += "**Usage**:\n"
149
- markdown += "```xml\n"
150
- markdown += f"<{self.name}>\n"
151
-
152
- # Generate example parameters
153
- for arg in self.arguments:
154
- if properties_injectable.get(arg.name) is not None:
155
- continue
156
- # Prioritize example, then default, then create a generic example
157
- example_value = arg.example or arg.default or f"Your {arg.name} here"
158
- markdown += f" <{arg.name}>{example_value}</{arg.name}>\n"
159
-
160
- markdown += f"</{self.name}>\n"
161
- markdown += "```\n"
162
-
163
- return markdown
164
-
165
- def get_non_injectable_arguments(self) -> list[ToolArgument]:
166
- """Get arguments that cannot be injected from properties.
167
-
168
- Returns:
169
- List of ToolArgument instances that cannot be injected by the agent.
170
- """
171
- properties_injectable = self.get_injectable_properties_in_execution()
172
-
173
- return [arg for arg in self.arguments if properties_injectable.get(arg.name) is None]
174
-
175
- def get_injectable_properties_in_execution(self) -> dict[str, Any]:
176
- """Get injectable properties excluding tool arguments.
177
-
178
- Returns:
179
- A dictionary of property names and values, excluding tool arguments and None values.
180
- """
181
- # This method is defined here in ToolDefinition and overridden in Tool
182
- # For ToolDefinition, it returns an empty dict since it has no execution context yet
183
- return {}
184
-
185
- def to_docstring(self) -> str:
186
- """Convert the tool definition into a Google-style docstring with function signature.
187
-
188
- Returns:
189
- A string formatted as a valid Python docstring representing the tool's configuration,
190
- including the function signature and return type.
191
- """
192
- # Construct the function signature
193
- signature_parts = []
194
- for arg in self.arguments:
195
- # Base argument: name and type
196
- arg_str = f"{arg.name}: {arg.arg_type}"
197
- # Add default value if present
198
- if arg.default is not None:
199
- arg_str += f" = {arg.default}"
200
- signature_parts.append(arg_str)
201
- signature = f"def {self.name}({', '.join(signature_parts)}) -> {self.return_type}:"
202
-
203
- # Start with the signature and description
204
- docstring = f'"""\n{signature}\n\n{self.description}\n\n'
205
-
206
- # Add Arguments section if there are any
207
- if self.arguments:
208
- docstring += "Args:\n"
209
- for arg in self.arguments:
210
- # Base argument line: name and type
211
- arg_line = f" {arg.name} ({arg.arg_type})"
212
-
213
- # Add optional/required status and default/example if present
214
- details = []
215
- if not arg.required:
216
- details.append("optional")
217
- if arg.default is not None:
218
- details.append(f"defaults to {arg.default}")
219
- if arg.example is not None:
220
- details.append(f"e.g., {arg.example}")
221
- if details:
222
- arg_line += f" [{', '.join(details)}]"
223
-
224
- # Add description if present
225
- if arg.description:
226
- arg_line += f": {arg.description}"
227
-
228
- docstring += f"{arg_line}\n"
229
-
230
- # Add Returns section
231
- docstring += f"Returns:\n {self.return_type}: The result of the tool execution.\n"
232
-
233
- # Close the docstring
234
- docstring += '"""'
235
-
236
- return docstring
237
-
238
- class Tool(ToolDefinition):
239
- """Extended class for tools with execution capabilities.
240
-
241
- Inherits from ToolDefinition and adds execution functionality.
242
- """
243
-
244
- @field_validator("arguments", mode="before")
245
- @classmethod
246
- def validate_arguments(cls, v: Any) -> list[ToolArgument]:
247
- """Validate and convert arguments to ToolArgument instances.
248
-
249
- Args:
250
- v: Input arguments to validate.
251
-
252
- Returns:
253
- A list of validated ToolArgument instances.
254
- """
255
- if isinstance(v, list):
256
- return [
257
- ToolArgument(**arg)
258
- if isinstance(arg, dict)
259
- else arg
260
- if isinstance(arg, ToolArgument)
261
- else ToolArgument(name=str(arg), type=type(arg).__name__)
262
- for arg in v
263
- ]
264
- return []
265
-
266
- def execute(self, **kwargs: Any) -> str:
267
- """Execute the tool with provided arguments.
268
-
269
- If not implemented by a subclass, falls back to the asynchronous execute_async method.
270
-
271
- Args:
272
- **kwargs: Keyword arguments for tool execution.
273
-
274
- Returns:
275
- A string representing the result of tool execution.
276
- """
277
- # Check if execute is implemented in the subclass
278
- if self.__class__.execute is Tool.execute:
279
- # If not implemented, run the async version synchronously
280
- return asyncio.run(self.async_execute(**kwargs))
281
- raise NotImplementedError("This method should be implemented by subclasses.")
282
-
283
- async def async_execute(self, **kwargs: Any) -> str:
284
- """Asynchronous version of execute.
285
-
286
- By default, runs the synchronous execute method in a separate thread using asyncio.to_thread.
287
- Subclasses can override this method to provide a native asynchronous implementation for
288
- operations that benefit from async I/O (e.g., network requests).
289
-
290
- Args:
291
- **kwargs: Keyword arguments for tool execution.
292
-
293
- Returns:
294
- A string representing the result of tool execution.
295
- """
296
- # Check if execute_async is implemented in the subclass
297
- if self.__class__.async_execute is Tool.async_execute:
298
- return await asyncio.to_thread(self.execute, **kwargs)
299
- raise NotImplementedError("This method should be implemented by subclasses.")
300
-
301
- def get_injectable_properties_in_execution(self) -> dict[str, Any]:
302
- """Get injectable properties excluding tool arguments.
303
-
304
- Returns:
305
- A dictionary of property names and values, excluding tool arguments and None values.
306
- """
307
- # Get argument names from tool definition
308
- argument_names = {arg.name for arg in self.arguments}
309
-
310
- # Get properties excluding arguments and filter out None values
311
- properties = self.get_properties(exclude=["arguments"])
312
- return {name: value for name, value in properties.items() if value is not None and name in argument_names}
313
-
314
- def create_tool(func: F) -> Tool:
315
- """Create a Tool instance from a Python function using AST analysis.
316
-
317
- Analyzes the function's source code to extract its name, docstring, and arguments,
318
- then constructs a Tool subclass with appropriate execution logic.
319
-
320
- Args:
321
- func: The Python function (sync or async) to convert into a Tool.
322
-
323
- Returns:
324
- A Tool subclass instance configured based on the function.
325
-
326
- Raises:
327
- ValueError: If the input is not a valid function or lacks a function definition.
328
- """
329
- if not callable(func):
330
- raise ValueError("Input must be a callable function")
331
-
332
- # Get source code and parse with AST
333
- try:
334
- source = inspect.getsource(func).strip()
335
- tree = ast.parse(source)
336
- except (OSError, TypeError, SyntaxError) as e:
337
- raise ValueError(f"Failed to parse function source: {e}")
338
-
339
- # Ensure root node is a function definition
340
- if not tree.body or not isinstance(tree.body[0], (ast.FunctionDef, ast.AsyncFunctionDef)):
341
- raise ValueError("Source must define a single function")
342
- func_def = tree.body[0]
343
-
344
- # Extract metadata
345
- name = func_def.name
346
- docstring = ast.get_docstring(func_def) or ""
347
- parsed_doc = parse_docstring(docstring)
348
- description = parsed_doc.short_description or f"Tool generated from {name}"
349
- param_docs = {p.arg_name: p.description for p in parsed_doc.params}
350
- is_async = isinstance(func_def, ast.AsyncFunctionDef)
351
-
352
- # Get type hints using typing module
353
- from typing import get_type_hints
354
- type_hints = get_type_hints(func)
355
- type_map = {int: "int", str: "string", float: "float", bool: "boolean"}
356
-
357
- # Process arguments
358
- args = func_def.args
359
- defaults = [None] * (len(args.args) - len(args.defaults)) + [
360
- ast.unparse(d) if isinstance(d, ast.AST) else str(d) for d in args.defaults
361
- ]
362
- arguments: list[ToolArgument] = []
363
-
364
- for i, arg in enumerate(args.args):
365
- arg_name = arg.arg
366
- default = defaults[i]
367
- required = default is None
368
-
369
- # Determine argument type
370
- hint = type_hints.get(arg_name, str) # Default to str if no hint
371
- arg_type = type_map.get(hint, "string") # Fallback to string for unmapped types
372
-
373
- # Use docstring or default description
374
- description = param_docs.get(arg_name, f"Argument {arg_name}")
375
-
376
- # Create ToolArgument
377
- arguments.append(ToolArgument(
378
- name=arg_name,
379
- arg_type=arg_type,
380
- description=description,
381
- required=required,
382
- default=default,
383
- example=default if default else None
384
- ))
385
-
386
- # Determine return type from type hints
387
- return_type = type_hints.get("return", str)
388
- return_type_str = type_map.get(return_type, "string")
389
-
390
- # Define Tool subclass
391
- class GeneratedTool(Tool):
392
- def __init__(self, *args: Any, **kwargs: Any):
393
- super().__init__(*args, name=name, description=description, arguments=arguments, return_type=return_type_str, **kwargs)
394
- self._func = func
395
-
396
- if is_async:
397
- async def async_execute(self, **kwargs: Any) -> str:
398
- result = await self._func(**kwargs)
399
- return str(result)
400
- else:
401
- def execute(self, **kwargs: Any) -> str:
402
- result = self._func(**kwargs)
403
- return str(result)
404
-
405
- return GeneratedTool()
406
-
407
- if __name__ == "__main__":
408
- # Basic tool with argument
409
- tool = Tool(
410
- name="my_tool",
411
- description="A simple tool",
412
- arguments=[ToolArgument(name="arg1", arg_type="string")]
413
- )
414
- print("Basic Tool Markdown:")
415
- print(tool.to_markdown())
416
- print("Basic Tool Docstring:")
417
- print(tool.to_docstring())
418
- print()
419
-
420
- # Tool with injectable field (undefined)
421
- class MyTool(Tool):
422
- field1: str | None = Field(default=None, description="Field 1 description")
423
-
424
- tool_with_fields = MyTool(
425
- name="my_tool1",
426
- description="A simple tool with a field",
427
- arguments=[ToolArgument(name="field1", arg_type="string")]
428
- )
429
- print("Tool with Undefined Field Markdown:")
430
- print(tool_with_fields.to_markdown())
431
- print("Injectable Properties (should be empty):", tool_with_fields.get_injectable_properties_in_execution())
432
- print("Tool with Undefined Field Docstring:")
433
- print(tool_with_fields.to_docstring())
434
- print()
435
-
436
- # Tool with defined injectable field
437
- tool_with_fields_defined = MyTool(
438
- name="my_tool2",
439
- description="A simple tool with a defined field",
440
- field1="field1_value",
441
- arguments=[ToolArgument(name="field1", arg_type="string")]
442
- )
443
- print("Tool with Defined Field Markdown:")
444
- print(tool_with_fields_defined.to_markdown())
445
- print("Injectable Properties (should include field1):", tool_with_fields_defined.get_injectable_properties_in_execution())
446
- print("Tool with Defined Field Docstring:")
447
- print(tool_with_fields_defined.to_docstring())
448
- print()
449
-
450
- # Test create_tool with synchronous function
451
- def add(a: int, b: int = 0) -> int:
452
- """Add two numbers.
453
-
454
- Args:
455
- a: First number.
456
- b: Second number (optional).
457
- """
458
- return a + b
459
-
460
- sync_tool = create_tool(add)
461
- print("Synchronous Tool Markdown:")
462
- print(sync_tool.to_markdown())
463
- print("Synchronous Tool Docstring:")
464
- print(sync_tool.to_docstring())
465
- print("Execution result:", sync_tool.execute(a=5, b=3))
466
- print()
467
-
468
- # Test create_tool with asynchronous function
469
- async def greet(name: str) -> str:
470
- """Greet a person.
471
-
472
- Args:
473
- name: Name of the person.
474
- """
475
- await asyncio.sleep(0.1) # Simulate async work
476
- return f"Hello, {name}"
477
-
478
- async_tool = create_tool(greet)
479
- print("Asynchronous Tool Markdown:")
480
- print(async_tool.to_markdown())
481
- print("Asynchronous Tool Docstring:")
482
- print(async_tool.to_docstring())
483
- print("Execution result:", asyncio.run(async_tool.async_execute(name="Alice")))
484
- print()
485
-
486
- # Comprehensive tool for to_docstring demonstration with custom return type
487
- docstring_tool = Tool(
488
- name="sample_tool",
489
- description="A sample tool for testing docstring generation.",
490
- arguments=[
491
- ToolArgument(name="x", arg_type="int", description="The first number", required=True),
492
- ToolArgument(name="y", arg_type="float", description="The second number", default="0.0", example="1.5"),
493
- ToolArgument(name="verbose", arg_type="boolean", description="Print extra info", default="False")
494
- ],
495
- return_type="int" # Custom return type
496
- )
497
- print("Comprehensive Tool Markdown:")
498
- print(docstring_tool.to_markdown())
499
- print("Comprehensive Tool Docstring with Custom Return Type:")
500
- print(docstring_tool.to_docstring())
1
+ from quantalogic_toolbox.tool import Tool, ToolArgument, create_tool
2
+
3
+ __all__ = [
4
+ "ToolArgument",
5
+ "Tool",
6
+ "create_tool",
7
+ ]
8
+