quantalogic 0.30.8__tar.gz → 0.31.0__tar.gz

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 (97) hide show
  1. {quantalogic-0.30.8 → quantalogic-0.31.0}/PKG-INFO +6 -1
  2. {quantalogic-0.30.8 → quantalogic-0.31.0}/README.md +3 -0
  3. {quantalogic-0.30.8 → quantalogic-0.31.0}/pyproject.toml +3 -1
  4. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/__init__.py +17 -7
  5. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/agent.py +75 -29
  6. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/agent_config.py +10 -0
  7. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/agent_factory.py +66 -11
  8. quantalogic-0.31.0/quantalogic/config.py +15 -0
  9. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/generative_model.py +17 -98
  10. quantalogic-0.31.0/quantalogic/get_model_info.py +42 -0
  11. quantalogic-0.31.0/quantalogic/interactive_text_editor.py +368 -0
  12. quantalogic-0.31.0/quantalogic/llm.py +135 -0
  13. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/main.py +60 -11
  14. quantalogic-0.31.0/quantalogic/prompts.py +119 -0
  15. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/task_runner.py +26 -39
  16. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tool_manager.py +66 -0
  17. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/replace_in_file_tool.py +1 -1
  18. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/search_definition_names.py +2 -0
  19. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/sql_query_tool.py +4 -2
  20. quantalogic-0.31.0/quantalogic/utils/get_all_models.py +20 -0
  21. quantalogic-0.30.8/quantalogic/get_model_info.py +0 -16
  22. quantalogic-0.30.8/quantalogic/interactive_text_editor.py +0 -194
  23. quantalogic-0.30.8/quantalogic/prompts.py +0 -94
  24. {quantalogic-0.30.8 → quantalogic-0.31.0}/LICENSE +0 -0
  25. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/coding_agent.py +0 -0
  26. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/console_print_events.py +0 -0
  27. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/console_print_token.py +0 -0
  28. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/docs_cli.py +0 -0
  29. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/event_emitter.py +0 -0
  30. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/memory.py +0 -0
  31. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/model_names.py +0 -0
  32. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/search_agent.py +0 -0
  33. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/__init__.py +0 -0
  34. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/agent_server.py +0 -0
  35. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/models.py +0 -0
  36. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/routes.py +0 -0
  37. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/state.py +0 -0
  38. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/static/js/event_visualizer.js +0 -0
  39. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/static/js/quantalogic.js +0 -0
  40. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/server/templates/index.html +0 -0
  41. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/task_file_reader.py +0 -0
  42. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/__init__.py +0 -0
  43. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/agent_tool.py +0 -0
  44. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/dalle_e.py +0 -0
  45. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/download_http_file_tool.py +0 -0
  46. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/duckduckgo_search_tool.py +0 -0
  47. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/edit_whole_content_tool.py +0 -0
  48. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/elixir_tool.py +0 -0
  49. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/execute_bash_command_tool.py +0 -0
  50. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/generate_database_report_tool.py +0 -0
  51. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/grep_app_tool.py +0 -0
  52. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/input_question_tool.py +0 -0
  53. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/jinja_tool.py +0 -0
  54. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/__init__.py +0 -0
  55. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/c_handler.py +0 -0
  56. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/cpp_handler.py +0 -0
  57. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/go_handler.py +0 -0
  58. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/java_handler.py +0 -0
  59. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/javascript_handler.py +0 -0
  60. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/python_handler.py +0 -0
  61. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/rust_handler.py +0 -0
  62. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/scala_handler.py +0 -0
  63. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/language_handlers/typescript_handler.py +0 -0
  64. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/list_directory_tool.py +0 -0
  65. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/llm_tool.py +0 -0
  66. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/llm_vision_tool.py +0 -0
  67. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/markitdown_tool.py +0 -0
  68. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/nodejs_tool.py +0 -0
  69. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/python_tool.py +0 -0
  70. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/read_file_block_tool.py +0 -0
  71. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/read_file_tool.py +0 -0
  72. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/read_html_tool.py +0 -0
  73. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/ripgrep_tool.py +0 -0
  74. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/serpapi_search_tool.py +0 -0
  75. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/task_complete_tool.py +0 -0
  76. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/tool.py +0 -0
  77. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/unified_diff_tool.py +0 -0
  78. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/utils/__init__.py +0 -0
  79. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/utils/create_sample_database.py +0 -0
  80. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/utils/generate_database_report.py +0 -0
  81. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/wikipedia_search_tool.py +0 -0
  82. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/tools/write_file_tool.py +0 -0
  83. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/__init__.py +0 -0
  84. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/ask_user_validation.py +0 -0
  85. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/check_version.py +0 -0
  86. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/download_http_file.py +0 -0
  87. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/get_coding_environment.py +0 -0
  88. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/get_environment.py +0 -0
  89. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/get_quantalogic_rules_content.py +0 -0
  90. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/git_ls.py +0 -0
  91. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/read_file.py +0 -0
  92. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/utils/read_http_text_content.py +0 -0
  93. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/version.py +0 -0
  94. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/version_check.py +0 -0
  95. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/welcome_message.py +0 -0
  96. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/xml_parser.py +0 -0
  97. {quantalogic-0.30.8 → quantalogic-0.31.0}/quantalogic/xml_tool_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantalogic
3
- Version: 0.30.8
3
+ Version: 0.31.0
4
4
  Summary: QuantaLogic ReAct Agents
5
5
  Author: Raphaël MANSUY
6
6
  Author-email: raphael.mansuy@gmail.com
@@ -14,6 +14,7 @@ Requires-Dist: click (>=8.1.8,<9.0.0)
14
14
  Requires-Dist: duckduckgo-search (>=7.2.1,<8.0.0)
15
15
  Requires-Dist: faker (>=33.3.1,<34.0.0)
16
16
  Requires-Dist: fastapi (>=0.115.6,<0.116.0)
17
+ Requires-Dist: fuzzywuzzy (>=0.18.0,<0.19.0)
17
18
  Requires-Dist: google-auth (>=2.20.0,<3.0.0)
18
19
  Requires-Dist: google-search-results (>=2.4.2,<3.0.0)
19
20
  Requires-Dist: jinja2 (>=3.1.5,<4.0.0)
@@ -35,6 +36,7 @@ Requires-Dist: prompt-toolkit (>=3.0.48,<4.0.0)
35
36
  Requires-Dist: pydantic (>=2.10.4,<3.0.0)
36
37
  Requires-Dist: pymdown-extensions (>=10.3.1,<11.0.0)
37
38
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
39
+ Requires-Dist: python-levenshtein (>=0.26.1,<0.27.0)
38
40
  Requires-Dist: requests (>=2.32.3,<3.0.0)
39
41
  Requires-Dist: rich (>=13.9.4,<14.0.0)
40
42
  Requires-Dist: serpapi (>=0.1.5,<0.2.0)
@@ -162,6 +164,9 @@ See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and chang
162
164
  | openrouter/openai/gpt-4o | OPENROUTER_API_KEY | OpenAI's GPT-4o model accessible through OpenRouter platform. |
163
165
  | openrouter/mistralai/mistral-large-2411 | OPENROUTER_API_KEY | Mistral's large model optimized for complex reasoning tasks, available through OpenRouter with enhanced multilingual capabilities. |
164
166
  | mistral/mistral-large-2407 | MISTRAL_API_KEY | Mistral's high-performance model designed for enterprise-grade applications, offering advanced reasoning and multilingual support. |
167
+ | dashscope/qwen-max | DASHSCOPE_API_KEY | Alibaba's Qwen-Max model optimized for maximum performance and extensive reasoning capabilities. |
168
+ | dashscope/qwen-plus | DASHSCOPE_API_KEY | Alibaba's Qwen-Plus model offering balanced performance and cost-efficiency for a variety of tasks. |
169
+ | dashscope/qwen-turbo | DASHSCOPE_API_KEY | Alibaba's Qwen-Turbo model designed for fast and efficient responses, ideal for high-throughput scenarios. |
165
170
 
166
171
  To configure the environment API key for Quantalogic using LiteLLM, set the required environment variable for your chosen provider and any optional variables like `OPENAI_API_BASE` or `OPENROUTER_REFERRER`. Use a `.env` file or a secrets manager to securely store these keys, and load them in your code using `python-dotenv`. For advanced configurations, refer to the [LiteLLM documentation](https://docs.litellm.ai/docs/).
167
172
 
@@ -104,6 +104,9 @@ See our [Release Notes](RELEASE_NOTES.MD) for detailed version history and chang
104
104
  | openrouter/openai/gpt-4o | OPENROUTER_API_KEY | OpenAI's GPT-4o model accessible through OpenRouter platform. |
105
105
  | openrouter/mistralai/mistral-large-2411 | OPENROUTER_API_KEY | Mistral's large model optimized for complex reasoning tasks, available through OpenRouter with enhanced multilingual capabilities. |
106
106
  | mistral/mistral-large-2407 | MISTRAL_API_KEY | Mistral's high-performance model designed for enterprise-grade applications, offering advanced reasoning and multilingual support. |
107
+ | dashscope/qwen-max | DASHSCOPE_API_KEY | Alibaba's Qwen-Max model optimized for maximum performance and extensive reasoning capabilities. |
108
+ | dashscope/qwen-plus | DASHSCOPE_API_KEY | Alibaba's Qwen-Plus model offering balanced performance and cost-efficiency for a variety of tasks. |
109
+ | dashscope/qwen-turbo | DASHSCOPE_API_KEY | Alibaba's Qwen-Turbo model designed for fast and efficient responses, ideal for high-throughput scenarios. |
107
110
 
108
111
  To configure the environment API key for Quantalogic using LiteLLM, set the required environment variable for your chosen provider and any optional variables like `OPENAI_API_BASE` or `OPENROUTER_REFERRER`. Use a `.env` file or a secrets manager to securely store these keys, and load them in your code using `python-dotenv`. For advanced configurations, refer to the [LiteLLM documentation](https://docs.litellm.ai/docs/).
109
112
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "quantalogic"
3
- version = "0.30.8"
3
+ version = "0.31.0"
4
4
  description = "QuantaLogic ReAct Agents"
5
5
  authors = ["Raphaël MANSUY <raphael.mansuy@gmail.com>"]
6
6
  readme = "README.md"
@@ -54,6 +54,8 @@ sqlalchemy = "^2.0.37"
54
54
  python-dotenv = "^1.0.1"
55
55
  networkx = "^3.4.2"
56
56
  faker = "^33.3.1"
57
+ fuzzywuzzy = "^0.18.0"
58
+ python-levenshtein = "^0.26.1"
57
59
 
58
60
  [tool.poetry.scripts]
59
61
  quantalogic = "quantalogic.main:cli"
@@ -1,4 +1,5 @@
1
- # QuantaLogic package initialization
1
+ """QuantaLogic package initialization."""
2
+
2
3
  import warnings
3
4
 
4
5
  # Suppress specific warnings related to Pydantic's V2 configuration changes
@@ -9,13 +10,22 @@ warnings.filterwarnings(
9
10
  message=".*config keys have changed in V2:.*|.*'fields' config key is removed in V2.*",
10
11
  )
11
12
 
12
-
13
+ # Import public API
14
+ from .llm import generate_completion, generate_image, count_tokens # noqa: E402
13
15
  from .agent import Agent # noqa: E402
14
- from .console_print_events import console_print_events # noqa: E402
15
- from .console_print_token import console_print_token # noqa: E402
16
16
  from .event_emitter import EventEmitter # noqa: E402
17
17
  from .memory import AgentMemory, VariableMemory # noqa: E402
18
+ from .console_print_events import console_print_events # noqa: E402
19
+ from .console_print_token import console_print_token # noqa: E402
18
20
 
19
- """QuantaLogic package for AI-powered generative models."""
20
-
21
- __all__ = ["Agent", "EventEmitter", "AgentMemory", "VariableMemory", "console_print_events","console_print_token"]
21
+ __all__ = [
22
+ "Agent",
23
+ "EventEmitter",
24
+ "AgentMemory",
25
+ "VariableMemory",
26
+ "console_print_events",
27
+ "console_print_token",
28
+ "generate_completion",
29
+ "generate_image",
30
+ "count_tokens"
31
+ ]
@@ -5,7 +5,7 @@ from datetime import datetime
5
5
  from typing import Any
6
6
 
7
7
  from loguru import logger
8
- from pydantic import BaseModel, ConfigDict
8
+ from pydantic import BaseModel, ConfigDict, PrivateAttr
9
9
 
10
10
  from quantalogic.event_emitter import EventEmitter
11
11
  from quantalogic.generative_model import GenerativeModel, ResponseStats, TokenUsage
@@ -52,12 +52,16 @@ class ObserveResponseResult(BaseModel):
52
52
  class Agent(BaseModel):
53
53
  """Enhanced QuantaLogic agent implementing ReAct framework."""
54
54
 
55
- model_config = ConfigDict(arbitrary_types_allowed=True, validate_assignment=True, extra="forbid")
55
+ model_config = ConfigDict(
56
+ arbitrary_types_allowed=True,
57
+ validate_assignment=True,
58
+ extra="forbid"
59
+ )
56
60
 
57
61
  specific_expertise: str
58
62
  model: GenerativeModel
59
- memory: AgentMemory = AgentMemory() # A list User / Assistant Messages
60
- variable_store: VariableMemory = VariableMemory() # A dictionary of variables (var1: value1, var2: value2)
63
+ memory: AgentMemory = AgentMemory() # A list User / Assistant Messages
64
+ variable_store: VariableMemory = VariableMemory() # A dictionary of variables
61
65
  tools: ToolManager = ToolManager()
62
66
  event_emitter: EventEmitter = EventEmitter()
63
67
  config: AgentConfig
@@ -71,8 +75,9 @@ class Agent(BaseModel):
71
75
  max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS
72
76
  max_iterations: int = 30
73
77
  system_prompt: str = ""
74
- compact_every_n_iterations: int | None = None # Add this to the class attributes
75
- max_tokens_working_memory: int | None = None # Add max_tokens_working_memory attribute
78
+ compact_every_n_iterations: int | None = None
79
+ max_tokens_working_memory: int | None = None
80
+ _model_name: str = PrivateAttr(default="")
76
81
 
77
82
  def __init__(
78
83
  self,
@@ -84,17 +89,18 @@ class Agent(BaseModel):
84
89
  task_to_solve: str = "",
85
90
  specific_expertise: str = "General AI assistant with coding and problem-solving capabilities",
86
91
  get_environment: Callable[[], str] = get_environment,
87
- compact_every_n_iterations: int | None = None, # if set the memory will be compacted every n iterations
88
- max_tokens_working_memory: int | None = None, # if set the memory will be compacted each time the max_tokens_working_memory is reached
92
+ compact_every_n_iterations: int | None = None,
93
+ max_tokens_working_memory: int | None = None,
89
94
  ):
90
95
  """Initialize the agent with model, memory, tools, and configurations."""
91
96
  try:
92
97
  logger.debug("Initializing agent...")
93
- # Create event emitter first
98
+
99
+ # Create event emitter
94
100
  event_emitter = EventEmitter()
95
101
 
96
102
  # Add TaskCompleteTool to the tools list if not already present
97
- if TaskCompleteTool() not in tools:
103
+ if not any(isinstance(t, TaskCompleteTool) for t in tools):
98
104
  tools.append(TaskCompleteTool())
99
105
 
100
106
  tool_manager = ToolManager(tools={tool.name: tool for tool in tools})
@@ -114,32 +120,50 @@ class Agent(BaseModel):
114
120
  system_prompt=system_prompt_text,
115
121
  )
116
122
 
117
- logger.debug("Base class init started ...")
123
+ # Initialize using Pydantic's model_validate
118
124
  super().__init__(
125
+ specific_expertise=specific_expertise,
119
126
  model=GenerativeModel(model=model_name, event_emitter=event_emitter),
120
127
  memory=memory,
121
128
  variable_store=variable_store,
122
129
  tools=tool_manager,
130
+ event_emitter=event_emitter,
123
131
  config=config,
124
- ask_for_user_validation=ask_for_user_validation,
125
132
  task_to_solve=task_to_solve,
126
- specific_expertise=specific_expertise,
127
- event_emitter=event_emitter,
133
+ task_to_solve_summary="",
134
+ ask_for_user_validation=ask_for_user_validation,
135
+ last_tool_call={},
136
+ total_tokens=0,
137
+ current_iteration=0,
138
+ max_input_tokens=DEFAULT_MAX_INPUT_TOKENS,
139
+ max_output_tokens=DEFAULT_MAX_OUTPUT_TOKENS,
140
+ max_iterations=30,
141
+ system_prompt="",
142
+ compact_every_n_iterations=compact_every_n_iterations or 30,
143
+ max_tokens_working_memory=max_tokens_working_memory,
128
144
  )
129
145
 
130
- # Set the new compact_every_n_iterations parameter
131
- self.compact_every_n_iterations = compact_every_n_iterations or self.max_iterations
132
- logger.debug(f"Memory will be compacted every {self.compact_every_n_iterations} iterations")
146
+ self._model_name = model_name
133
147
 
134
- # Set the max_tokens_working_memory parameter
135
- self.max_tokens_working_memory = max_tokens_working_memory
148
+ logger.debug(f"Memory will be compacted every {self.compact_every_n_iterations} iterations")
136
149
  logger.debug(f"Max tokens for working memory set to: {self.max_tokens_working_memory}")
137
-
138
150
  logger.debug("Agent initialized successfully.")
139
151
  except Exception as e:
140
152
  logger.error(f"Failed to initialize agent: {str(e)}")
141
153
  raise
142
154
 
155
+ @property
156
+ def model_name(self) -> str:
157
+ """Get the current model name."""
158
+ return self._model_name
159
+
160
+ @model_name.setter
161
+ def model_name(self, value: str) -> None:
162
+ """Set the model name."""
163
+ self._model_name = value
164
+ # Update the model instance with the new name
165
+ self.model = GenerativeModel(model=value, event_emitter=self.event_emitter)
166
+
143
167
  def clear_memory(self):
144
168
  """Clear the memory and reset the session."""
145
169
  self._reset_session(clear_memory=True)
@@ -533,7 +557,10 @@ class Agent(BaseModel):
533
557
  question_validation: str = (
534
558
  "Do you permit the execution of this tool?\n"
535
559
  f"Tool: {tool_name}\n"
536
- f"Arguments: {arguments_with_values}\n"
560
+ "Arguments:\n"
561
+ "<arguments>\n"
562
+ + "\n".join([f" <{key}>{value}</{key}>" for key, value in arguments_with_values.items()])
563
+ + "\n</arguments>\n"
537
564
  "Yes or No"
538
565
  )
539
566
  permission_granted = self.ask_for_user_validation(question_validation)
@@ -603,10 +630,14 @@ class Agent(BaseModel):
603
630
  return executed_tool, response
604
631
 
605
632
  def _interpolate_variables(self, text: str) -> str:
606
- """Interpolate variables using $var1$ syntax in the given text."""
633
+ """Interpolate variables using $var$ syntax in the given text."""
607
634
  try:
635
+ import re
608
636
  for var in self.variable_store.keys():
609
- text = text.replace(f"${var}$", self.variable_store[var])
637
+ # Escape the variable name for regex, but use raw value for replacement
638
+ pattern = rf'\${re.escape(var)}\$'
639
+ replacement = self.variable_store[var]
640
+ text = re.sub(pattern, replacement, text)
610
641
  return text
611
642
  except Exception as e:
612
643
  logger.error(f"Error in _interpolate_variables: {str(e)}")
@@ -645,6 +676,7 @@ class Agent(BaseModel):
645
676
  "1. Select ONE tool per message\n"
646
677
  "2. You will receive the tool's output in the next user response\n"
647
678
  "3. Choose the most appropriate tool for each step\n"
679
+ "4. Use task_complete tool to confirm task completion\n"
648
680
  )
649
681
  return prompt_use_tools
650
682
 
@@ -706,23 +738,32 @@ class Agent(BaseModel):
706
738
  return summary.response
707
739
 
708
740
  def _generate_task_summary(self, content: str) -> str:
709
- """Generate a concise summary of the given content using the generative model.
741
+ """Generate a concise task-focused summary using the generative model.
710
742
 
711
743
  Args:
712
744
  content (str): The content to summarize
713
745
 
714
746
  Returns:
715
- str: Generated summary
747
+ str: Generated task summary
716
748
  """
717
749
  try:
718
750
  prompt = (
719
- "Rewrite this task in a precise, dense, and concise manner:\n"
720
- f"{content}\n"
721
- "Summary should be 2-3 sentences maximum. No extra comments should be added.\n"
751
+ "Create an ultra-concise task summary that captures ONLY: \n"
752
+ "1. Primary objective/purpose\n"
753
+ "2. Core actions/requirements\n"
754
+ "3. Desired end-state/outcome\n\n"
755
+ "Guidelines:\n"
756
+ "- Use imperative voice\n"
757
+ "- Exclude background, explanations, and examples\n"
758
+ "- Compress information using semantic density\n"
759
+ "- Strict 2-3 sentence maximum (under 50 words)\n"
760
+ "- Format: 'Concise Task Summary: [Your summary]'\n\n"
761
+ f"Input Task Description:\n{content}\n\n"
762
+ "Concise Task Summary:"
722
763
  )
723
764
  result = self.model.generate(prompt=prompt)
724
765
  logger.debug(f"Generated summary: {result.response}")
725
- return result.response
766
+ return result.response.strip() + "\n🚨 The FULL task is in <task> tag in the previous messages.\n"
726
767
  except Exception as e:
727
768
  logger.error(f"Error generating summary: {str(e)}")
728
769
  return f"Summary generation failed: {str(e)}"
@@ -747,3 +788,8 @@ class Agent(BaseModel):
747
788
  "session_add_message",
748
789
  {"role": "assistant", "content": assistant_content},
749
790
  )
791
+
792
+ def update_model(self, new_model_name: str) -> None:
793
+ """Update the model name and recreate the model instance."""
794
+ self.model_name = new_model_name
795
+ self.model = GenerativeModel(model=new_model_name, event_emitter=self.event_emitter)
@@ -37,6 +37,14 @@ load_dotenv()
37
37
  MODEL_NAME = "deepseek/deepseek-chat"
38
38
 
39
39
 
40
+ _current_model_name: str = ""
41
+
42
+ def get_current_model() -> str:
43
+ """Retrieve the currently active model name."""
44
+ if not _current_model_name:
45
+ raise ValueError("No model initialized")
46
+ return _current_model_name
47
+
40
48
  def create_agent(
41
49
  model_name: str,
42
50
  vision_model_name: str | None,
@@ -44,6 +52,8 @@ def create_agent(
44
52
  compact_every_n_iteration: int | None = None,
45
53
  max_tokens_working_memory: int | None = None
46
54
  ) -> Agent:
55
+ global _current_model_name
56
+ _current_model_name = model_name
47
57
  """Create an agent with the specified model and tools.
48
58
 
49
59
  Args:
@@ -1,6 +1,4 @@
1
- """Agent factory module for creating different types of agents."""
2
-
3
- from typing import Optional
1
+ from typing import Dict, Optional
4
2
 
5
3
  from loguru import logger
6
4
 
@@ -11,7 +9,57 @@ from quantalogic.agent_config import (
11
9
  create_interpreter_agent,
12
10
  )
13
11
  from quantalogic.coding_agent import create_coding_agent
14
- from quantalogic.search_agent import create_search_agent
12
+ from quantalogic.search_agent import create_search_agent # noqa: E402
13
+
14
+
15
+ class AgentRegistry:
16
+ """Registry for managing agent instances by name."""
17
+
18
+ _instance = None
19
+ _agents: Dict[str, Agent] = {}
20
+
21
+ def __new__(cls):
22
+ if cls._instance is None:
23
+ cls._instance = super().__new__(cls)
24
+ return cls._instance
25
+
26
+ @classmethod
27
+ def register_agent(cls, name: str, agent: Agent) -> None:
28
+ """Register an agent instance with a name.
29
+
30
+ Args:
31
+ name: Unique name for the agent
32
+ agent: Agent instance to register
33
+ """
34
+ if name in cls._agents:
35
+ raise ValueError(f"Agent with name {name} already exists")
36
+ cls._agents[name] = agent
37
+
38
+ @classmethod
39
+ def get_agent(cls, name: str) -> Agent:
40
+ """Retrieve a registered agent by name.
41
+
42
+ Args:
43
+ name: Name of the agent to retrieve
44
+
45
+ Returns:
46
+ Registered Agent instance
47
+
48
+ Raises:
49
+ KeyError: If no agent with that name exists
50
+ """
51
+ return cls._agents[name]
52
+
53
+ @classmethod
54
+ def list_agents(cls) -> Dict[str, str]:
55
+ """List all registered agents.
56
+
57
+ Returns:
58
+ Dictionary mapping agent names to their types
59
+ """
60
+ return {name: type(agent).__name__ for name, agent in cls._agents.items()}
61
+
62
+ """Agent factory module for creating different types of agents."""
15
63
 
16
64
 
17
65
  def create_agent_for_mode(
@@ -46,7 +94,7 @@ def create_agent_for_mode(
46
94
 
47
95
  if mode == "code":
48
96
  logger.debug("Creating code agent without basic mode")
49
- return create_coding_agent(
97
+ agent = create_coding_agent(
50
98
  model_name,
51
99
  vision_model_name,
52
100
  basic=False,
@@ -54,8 +102,9 @@ def create_agent_for_mode(
54
102
  compact_every_n_iteration=compact_every_n_iteration,
55
103
  max_tokens_working_memory=max_tokens_working_memory
56
104
  )
105
+ return agent
57
106
  if mode == "code-basic":
58
- return create_coding_agent(
107
+ agent = create_coding_agent(
59
108
  model_name,
60
109
  vision_model_name,
61
110
  basic=True,
@@ -63,44 +112,50 @@ def create_agent_for_mode(
63
112
  compact_every_n_iteration=compact_every_n_iteration,
64
113
  max_tokens_working_memory=max_tokens_working_memory
65
114
  )
115
+ return agent
66
116
  elif mode == "basic":
67
- return create_basic_agent(
117
+ agent = create_basic_agent(
68
118
  model_name,
69
119
  vision_model_name,
70
120
  no_stream=no_stream,
71
121
  compact_every_n_iteration=compact_every_n_iteration,
72
122
  max_tokens_working_memory=max_tokens_working_memory
73
123
  )
124
+ return agent
74
125
  elif mode == "full":
75
- return create_full_agent(
126
+ agent = create_full_agent(
76
127
  model_name,
77
128
  vision_model_name,
78
129
  no_stream=no_stream,
79
130
  compact_every_n_iteration=compact_every_n_iteration,
80
131
  max_tokens_working_memory=max_tokens_working_memory
81
132
  )
133
+ return agent
82
134
  elif mode == "interpreter":
83
- return create_interpreter_agent(
135
+ agent = create_interpreter_agent(
84
136
  model_name,
85
137
  vision_model_name,
86
138
  no_stream=no_stream,
87
139
  compact_every_n_iteration=compact_every_n_iteration,
88
140
  max_tokens_working_memory=max_tokens_working_memory
89
141
  )
142
+ return agent
90
143
  elif mode == "search":
91
- return create_search_agent(
144
+ agent = create_search_agent(
92
145
  model_name,
93
146
  no_stream=no_stream,
94
147
  compact_every_n_iteration=compact_every_n_iteration,
95
148
  max_tokens_working_memory=max_tokens_working_memory
96
149
  )
150
+ return agent
97
151
  if mode == "search-full":
98
- return create_search_agent(
152
+ agent = create_search_agent(
99
153
  model_name,
100
154
  mode_full=True,
101
155
  no_stream=no_stream,
102
156
  compact_every_n_iteration=compact_every_n_iteration,
103
157
  max_tokens_working_memory=max_tokens_working_memory
104
158
  )
159
+ return agent
105
160
  else:
106
161
  raise ValueError(f"Unknown agent mode: {mode}")
@@ -0,0 +1,15 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class QLConfig:
6
+ """Central configuration for QuantaLogic agent parameters."""
7
+ model_name: str
8
+ verbose: bool
9
+ mode: str
10
+ log: str
11
+ vision_model_name: str | None
12
+ max_iterations: int
13
+ compact_every_n_iteration: int | None
14
+ max_tokens_working_memory: int | None
15
+ no_stream: bool