quantalogic 0.2.16__py3-none-any.whl → 0.2.18__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.
- quantalogic/__init__.py +3 -2
- quantalogic/agent.py +94 -38
- quantalogic/agent_config.py +62 -14
- quantalogic/coding_agent.py +17 -2
- quantalogic/{print_event.py → console_print_events.py} +1 -3
- quantalogic/console_print_token.py +16 -0
- quantalogic/docs_cli.py +50 -0
- quantalogic/generative_model.py +86 -77
- quantalogic/main.py +128 -18
- quantalogic/prompts.py +2 -2
- quantalogic/search_agent.py +12 -1
- quantalogic/server/agent_server.py +2 -2
- quantalogic/tools/llm_tool.py +52 -11
- quantalogic/tools/llm_vision_tool.py +23 -7
- quantalogic/xml_parser.py +109 -49
- {quantalogic-0.2.16.dist-info → quantalogic-0.2.18.dist-info}/METADATA +62 -153
- {quantalogic-0.2.16.dist-info → quantalogic-0.2.18.dist-info}/RECORD +20 -18
- quantalogic-0.2.18.dist-info/entry_points.txt +6 -0
- quantalogic-0.2.16.dist-info/entry_points.txt +0 -3
- {quantalogic-0.2.16.dist-info → quantalogic-0.2.18.dist-info}/LICENSE +0 -0
- {quantalogic-0.2.16.dist-info → quantalogic-0.2.18.dist-info}/WHEEL +0 -0
quantalogic/__init__.py
CHANGED
@@ -11,10 +11,11 @@ warnings.filterwarnings(
|
|
11
11
|
|
12
12
|
|
13
13
|
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
|
14
16
|
from .event_emitter import EventEmitter # noqa: E402
|
15
17
|
from .memory import AgentMemory, VariableMemory # noqa: E402
|
16
|
-
from .print_event import console_print_events # noqa: E402
|
17
18
|
|
18
19
|
"""QuantaLogic package for AI-powered generative models."""
|
19
20
|
|
20
|
-
__all__ = ["Agent", "EventEmitter", "AgentMemory", "VariableMemory", "console_print_events"]
|
21
|
+
__all__ = ["Agent", "EventEmitter", "AgentMemory", "VariableMemory", "console_print_events","console_print_token"]
|
quantalogic/agent.py
CHANGED
@@ -8,7 +8,7 @@ from loguru import logger
|
|
8
8
|
from pydantic import BaseModel, ConfigDict
|
9
9
|
|
10
10
|
from quantalogic.event_emitter import EventEmitter
|
11
|
-
from quantalogic.generative_model import GenerativeModel
|
11
|
+
from quantalogic.generative_model import GenerativeModel, ResponseStats, TokenUsage
|
12
12
|
from quantalogic.memory import AgentMemory, Message, VariableMemory
|
13
13
|
from quantalogic.prompts import system_prompt
|
14
14
|
from quantalogic.tool_manager import ToolManager
|
@@ -71,6 +71,8 @@ class Agent(BaseModel):
|
|
71
71
|
max_output_tokens: int = DEFAULT_MAX_OUTPUT_TOKENS
|
72
72
|
max_iterations: int = 30
|
73
73
|
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
|
74
76
|
|
75
77
|
def __init__(
|
76
78
|
self,
|
@@ -81,10 +83,15 @@ class Agent(BaseModel):
|
|
81
83
|
task_to_solve: str = "",
|
82
84
|
specific_expertise: str = "General AI assistant with coding and problem-solving capabilities",
|
83
85
|
get_environment: Callable[[], str] = get_environment,
|
86
|
+
compact_every_n_iterations: int | None = None, # New parameter
|
87
|
+
max_tokens_working_memory: int | None = None, # New parameter to set max working memory tokens
|
84
88
|
):
|
85
89
|
"""Initialize the agent with model, memory, tools, and configurations."""
|
86
90
|
try:
|
87
91
|
logger.debug("Initializing agent...")
|
92
|
+
# Create event emitter first
|
93
|
+
event_emitter = EventEmitter()
|
94
|
+
|
88
95
|
# Add TaskCompleteTool to the tools list if not already present
|
89
96
|
if TaskCompleteTool() not in tools:
|
90
97
|
tools.append(TaskCompleteTool())
|
@@ -108,7 +115,7 @@ class Agent(BaseModel):
|
|
108
115
|
|
109
116
|
logger.debug("Base class init started ...")
|
110
117
|
super().__init__(
|
111
|
-
model=GenerativeModel(model=model_name),
|
118
|
+
model=GenerativeModel(model=model_name, event_emitter=event_emitter),
|
112
119
|
memory=memory,
|
113
120
|
variable_store=VariableMemory(),
|
114
121
|
tools=tool_manager,
|
@@ -116,19 +123,30 @@ class Agent(BaseModel):
|
|
116
123
|
ask_for_user_validation=ask_for_user_validation,
|
117
124
|
task_to_solve=task_to_solve,
|
118
125
|
specific_expertise=specific_expertise,
|
126
|
+
event_emitter=event_emitter,
|
119
127
|
)
|
128
|
+
|
129
|
+
# Set the new compact_every_n_iterations parameter
|
130
|
+
self.compact_every_n_iterations = compact_every_n_iterations or self.max_iterations
|
131
|
+
logger.debug(f"Memory will be compacted every {self.compact_every_n_iterations} iterations")
|
132
|
+
|
133
|
+
# Set the max_tokens_working_memory parameter
|
134
|
+
self.max_tokens_working_memory = max_tokens_working_memory
|
135
|
+
logger.debug(f"Max tokens for working memory set to: {self.max_tokens_working_memory}")
|
136
|
+
|
120
137
|
logger.debug("Agent initialized successfully.")
|
121
138
|
except Exception as e:
|
122
139
|
logger.error(f"Failed to initialize agent: {str(e)}")
|
123
140
|
raise
|
124
141
|
|
125
|
-
def solve_task(self, task: str, max_iterations: int = 30) -> str:
|
142
|
+
def solve_task(self, task: str, max_iterations: int = 30, streaming: bool = False) -> str:
|
126
143
|
"""Solve the given task using the ReAct framework.
|
127
144
|
|
128
145
|
Args:
|
129
146
|
task (str): The task description.
|
130
147
|
max_iterations (int, optional): Maximum number of iterations to attempt solving the task.
|
131
148
|
Defaults to 30 to prevent infinite loops and ensure timely task completion.
|
149
|
+
streaming (bool, optional): Whether to use streaming mode for generating responses.
|
132
150
|
|
133
151
|
Returns:
|
134
152
|
str: The final response after task completion.
|
@@ -172,11 +190,34 @@ class Agent(BaseModel):
|
|
172
190
|
|
173
191
|
self._compact_memory_if_needed(current_prompt)
|
174
192
|
|
175
|
-
|
193
|
+
if streaming:
|
194
|
+
# For streaming, collect the response chunks
|
195
|
+
content = ""
|
196
|
+
for chunk in self.model.generate_with_history(
|
197
|
+
messages_history=self.memory.memory, prompt=current_prompt, streaming=True
|
198
|
+
):
|
199
|
+
content += chunk
|
200
|
+
|
201
|
+
# Create a response object similar to non-streaming mode
|
202
|
+
result = ResponseStats(
|
203
|
+
response=content,
|
204
|
+
usage=TokenUsage(
|
205
|
+
prompt_tokens=0, # We don't have token counts in streaming mode
|
206
|
+
completion_tokens=0,
|
207
|
+
total_tokens=0,
|
208
|
+
),
|
209
|
+
model=self.model.model,
|
210
|
+
finish_reason="stop",
|
211
|
+
)
|
212
|
+
else:
|
213
|
+
result = self.model.generate_with_history(
|
214
|
+
messages_history=self.memory.memory, prompt=current_prompt, streaming=False
|
215
|
+
)
|
176
216
|
|
177
217
|
content = result.response
|
178
|
-
|
179
|
-
|
218
|
+
if not streaming: # Only update tokens for non-streaming mode
|
219
|
+
token_usage = result.usage
|
220
|
+
self.total_tokens = token_usage.total_tokens
|
180
221
|
|
181
222
|
# Emit event: Task Think End
|
182
223
|
self._emit_event(
|
@@ -187,7 +228,7 @@ class Agent(BaseModel):
|
|
187
228
|
)
|
188
229
|
|
189
230
|
# Process the assistant's response
|
190
|
-
result = self._observe_response(
|
231
|
+
result = self._observe_response(content, iteration=self.current_iteration)
|
191
232
|
|
192
233
|
current_prompt = result.next_prompt
|
193
234
|
|
@@ -237,9 +278,31 @@ class Agent(BaseModel):
|
|
237
278
|
self.total_tokens = self.model.token_counter_with_history(message_history, prompt)
|
238
279
|
|
239
280
|
def _compact_memory_if_needed(self, current_prompt: str = ""):
|
240
|
-
"""Compacts the memory if it exceeds the maximum occupancy."""
|
281
|
+
"""Compacts the memory if it exceeds the maximum occupancy or token limit."""
|
241
282
|
ratio_occupied = self._calculate_context_occupancy()
|
242
|
-
|
283
|
+
|
284
|
+
# Compact memory if any of these conditions are met:
|
285
|
+
# 1. Memory occupancy exceeds MAX_OCCUPANCY, or
|
286
|
+
# 2. Current iteration is a multiple of compact_every_n_iterations, or
|
287
|
+
# 3. Working memory exceeds max_tokens_working_memory (if set)
|
288
|
+
should_compact_by_occupancy = ratio_occupied >= MAX_OCCUPANCY
|
289
|
+
should_compact_by_iteration = (
|
290
|
+
self.compact_every_n_iterations is not None and
|
291
|
+
self.current_iteration > 0 and
|
292
|
+
self.current_iteration % self.compact_every_n_iterations == 0
|
293
|
+
)
|
294
|
+
should_compact_by_token_limit = (
|
295
|
+
self.max_tokens_working_memory is not None and
|
296
|
+
self.total_tokens > self.max_tokens_working_memory
|
297
|
+
)
|
298
|
+
|
299
|
+
if should_compact_by_occupancy or should_compact_by_iteration or should_compact_by_token_limit:
|
300
|
+
if should_compact_by_occupancy:
|
301
|
+
logger.debug(f"Memory compaction triggered: Occupancy {ratio_occupied}% exceeds {MAX_OCCUPANCY}%")
|
302
|
+
|
303
|
+
if should_compact_by_iteration:
|
304
|
+
logger.debug(f"Memory compaction triggered: Iteration {self.current_iteration} is a multiple of {self.compact_every_n_iterations}")
|
305
|
+
|
243
306
|
self._emit_event("memory_full")
|
244
307
|
self.memory.compact()
|
245
308
|
self.total_tokens = self.model.token_counter_with_history(self.memory.memory, current_prompt)
|
@@ -292,9 +355,10 @@ class Agent(BaseModel):
|
|
292
355
|
is_repeated_call = self._is_repeated_tool_call(tool_name, arguments_with_values)
|
293
356
|
|
294
357
|
if is_repeated_call:
|
295
|
-
|
358
|
+
executed_tool, response = self._handle_repeated_tool_call(tool_name, arguments_with_values)
|
359
|
+
else:
|
360
|
+
executed_tool, response = self._execute_tool(tool_name, tool, arguments_with_values)
|
296
361
|
|
297
|
-
executed_tool, response = self._execute_tool(tool_name, tool, arguments_with_values)
|
298
362
|
if not executed_tool:
|
299
363
|
return self._handle_tool_execution_failure(response)
|
300
364
|
|
@@ -427,34 +491,26 @@ class Agent(BaseModel):
|
|
427
491
|
|
428
492
|
# Format the response message
|
429
493
|
formatted_response = (
|
430
|
-
"\n"
|
431
|
-
f"---
|
432
|
-
"\n"
|
433
|
-
f"
|
434
|
-
"\n"
|
435
|
-
|
436
|
-
"\n"
|
437
|
-
f"--- Tools --- \n"
|
438
|
-
"\n"
|
439
|
-
f"{self._get_tools_names_prompt()}"
|
440
|
-
"\n"
|
441
|
-
f"--- Variables --- \n"
|
442
|
-
"\n"
|
443
|
-
f"{self._get_variable_prompt()}\n"
|
444
|
-
"\n"
|
445
|
-
"You must analyze this answer and evaluate what to do next to solve the task.\n"
|
446
|
-
"If the step failed, take a step back and rethink your approach.\n"
|
447
|
-
"\n"
|
448
|
-
"--- Task to solve summary ---\n"
|
449
|
-
"\n"
|
450
|
-
f"{self.task_to_solve_summary}"
|
451
|
-
"\n"
|
494
|
+
f"\n--- Observations for iteration {iteration} / max {self.max_iterations} ---\n"
|
495
|
+
f"\n--- Tool execution result in ${variable_name}$ ---\n"
|
496
|
+
f"<{variable_name}>\n{response_display}\n</{variable_name}>\n\n"
|
497
|
+
f"--- Tools ---\n{self._get_tools_names_prompt()}\n"
|
498
|
+
f"--- Variables ---\n{self._get_variable_prompt()}\n"
|
499
|
+
"Analyze this response to determine the next steps. If the step failed, reconsider your approach.\n"
|
500
|
+
f"--- Task to solve summary ---\n{self.task_to_solve_summary}\n"
|
452
501
|
"--- Format ---\n"
|
453
|
-
"
|
454
|
-
"
|
455
|
-
"\n"
|
456
|
-
"
|
457
|
-
"
|
502
|
+
"Respond only with two XML blocks in markdown as specified in system prompt.\n"
|
503
|
+
"No extra comments must be added.\n"
|
504
|
+
"```xml\n"
|
505
|
+
"<thinking>\n"
|
506
|
+
"...\n"
|
507
|
+
"</thinking>\n"
|
508
|
+
"```\n"
|
509
|
+
"```xml\n"
|
510
|
+
"< ...tool_name... >\n"
|
511
|
+
"...\n"
|
512
|
+
"</ ...tool_name... >\n"
|
513
|
+
"```"
|
458
514
|
)
|
459
515
|
|
460
516
|
return formatted_response
|
quantalogic/agent_config.py
CHANGED
@@ -5,9 +5,11 @@
|
|
5
5
|
# Local application imports
|
6
6
|
from quantalogic.agent import Agent
|
7
7
|
from quantalogic.coding_agent import create_coding_agent
|
8
|
+
from quantalogic.console_print_token import console_print_token
|
8
9
|
from quantalogic.tools import (
|
9
10
|
AgentTool,
|
10
11
|
DownloadHttpFileTool,
|
12
|
+
DuckDuckGoSearchTool,
|
11
13
|
EditWholeContentTool,
|
12
14
|
ExecuteBashCommandTool,
|
13
15
|
InputQuestionTool,
|
@@ -23,20 +25,28 @@ from quantalogic.tools import (
|
|
23
25
|
RipgrepTool,
|
24
26
|
SearchDefinitionNames,
|
25
27
|
TaskCompleteTool,
|
26
|
-
WriteFileTool,
|
27
|
-
DuckDuckGoSearchTool,
|
28
28
|
WikipediaSearchTool,
|
29
|
+
WriteFileTool,
|
29
30
|
)
|
30
31
|
|
31
32
|
MODEL_NAME = "deepseek/deepseek-chat"
|
32
33
|
|
33
34
|
|
34
|
-
def create_agent(
|
35
|
+
def create_agent(
|
36
|
+
model_name: str,
|
37
|
+
vision_model_name: str | None,
|
38
|
+
no_stream: bool = False,
|
39
|
+
compact_every_n_iteration: int | None = None,
|
40
|
+
max_tokens_working_memory: int | None = None
|
41
|
+
) -> Agent:
|
35
42
|
"""Create an agent with the specified model and tools.
|
36
43
|
|
37
44
|
Args:
|
38
45
|
model_name (str): Name of the model to use
|
39
46
|
vision_model_name (str | None): Name of the vision model to use
|
47
|
+
no_stream (bool, optional): If True, the agent will not stream results.
|
48
|
+
compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
|
49
|
+
max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
|
40
50
|
|
41
51
|
Returns:
|
42
52
|
Agent: An agent with the specified model and tools
|
@@ -54,25 +64,36 @@ def create_agent(model_name: str, vision_model_name: str | None) -> Agent:
|
|
54
64
|
RipgrepTool(),
|
55
65
|
SearchDefinitionNames(),
|
56
66
|
MarkitdownTool(),
|
57
|
-
LLMTool(model_name=model_name),
|
67
|
+
LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
|
58
68
|
DownloadHttpFileTool(),
|
59
69
|
]
|
60
70
|
|
61
71
|
if vision_model_name:
|
62
|
-
tools.append(LLMVisionTool(model_name=vision_model_name))
|
72
|
+
tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
|
63
73
|
|
64
74
|
return Agent(
|
65
75
|
model_name=model_name,
|
66
76
|
tools=tools,
|
77
|
+
compact_every_n_iterations=compact_every_n_iteration,
|
78
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
67
79
|
)
|
68
80
|
|
69
81
|
|
70
|
-
def create_interpreter_agent(
|
82
|
+
def create_interpreter_agent(
|
83
|
+
model_name: str,
|
84
|
+
vision_model_name: str | None,
|
85
|
+
no_stream: bool = False,
|
86
|
+
compact_every_n_iteration: int | None = None,
|
87
|
+
max_tokens_working_memory: int | None = None
|
88
|
+
) -> Agent:
|
71
89
|
"""Create an interpreter agent with the specified model and tools.
|
72
90
|
|
73
91
|
Args:
|
74
92
|
model_name (str): Name of the model to use
|
75
93
|
vision_model_name (str | None): Name of the vision model to use
|
94
|
+
no_stream (bool, optional): If True, the agent will not stream results.
|
95
|
+
compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
|
96
|
+
max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
|
76
97
|
|
77
98
|
Returns:
|
78
99
|
Agent: An interpreter agent with the specified model and tools
|
@@ -92,18 +113,32 @@ def create_interpreter_agent(model_name: str, vision_model_name: str | None) ->
|
|
92
113
|
NodeJsTool(),
|
93
114
|
SearchDefinitionNames(),
|
94
115
|
MarkitdownTool(),
|
95
|
-
LLMTool(model_name=model_name),
|
116
|
+
LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
|
96
117
|
DownloadHttpFileTool(),
|
97
118
|
]
|
98
|
-
return Agent(
|
119
|
+
return Agent(
|
120
|
+
model_name=model_name,
|
121
|
+
tools=tools,
|
122
|
+
compact_every_n_iterations=compact_every_n_iteration,
|
123
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
124
|
+
)
|
99
125
|
|
100
126
|
|
101
|
-
def create_full_agent(
|
127
|
+
def create_full_agent(
|
128
|
+
model_name: str,
|
129
|
+
vision_model_name: str | None,
|
130
|
+
no_stream: bool = False,
|
131
|
+
compact_every_n_iteration: int | None = None,
|
132
|
+
max_tokens_working_memory: int | None = None
|
133
|
+
) -> Agent:
|
102
134
|
"""Create an agent with the specified model and many tools.
|
103
135
|
|
104
136
|
Args:
|
105
137
|
model_name (str): Name of the model to use
|
106
138
|
vision_model_name (str | None): Name of the vision model to use
|
139
|
+
no_stream (bool, optional): If True, the agent will not stream results.
|
140
|
+
compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
|
141
|
+
max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
|
107
142
|
|
108
143
|
Returns:
|
109
144
|
Agent: An agent with the specified model and tools
|
@@ -124,27 +159,38 @@ def create_full_agent(model_name: str, vision_model_name: str | None) -> Agent:
|
|
124
159
|
NodeJsTool(),
|
125
160
|
SearchDefinitionNames(),
|
126
161
|
MarkitdownTool(),
|
127
|
-
LLMTool(model_name=model_name),
|
162
|
+
LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
|
128
163
|
DownloadHttpFileTool(),
|
129
164
|
WikipediaSearchTool(),
|
130
165
|
DuckDuckGoSearchTool(),
|
131
166
|
]
|
132
167
|
|
133
168
|
if vision_model_name:
|
134
|
-
tools.append(LLMVisionTool(model_name=vision_model_name))
|
169
|
+
tools.append(LLMVisionTool(model_name=vision_model_name,on_token=console_print_token if not no_stream else None))
|
135
170
|
|
136
171
|
return Agent(
|
137
172
|
model_name=model_name,
|
138
173
|
tools=tools,
|
174
|
+
compact_every_n_iterations=compact_every_n_iteration,
|
175
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
139
176
|
)
|
140
177
|
|
141
178
|
|
142
|
-
def create_orchestrator_agent(
|
179
|
+
def create_orchestrator_agent(
|
180
|
+
model_name: str,
|
181
|
+
vision_model_name: str | None = None,
|
182
|
+
no_stream: bool = False,
|
183
|
+
compact_every_n_iteration: int | None = None,
|
184
|
+
max_tokens_working_memory: int | None = None
|
185
|
+
) -> Agent:
|
143
186
|
"""Create an agent with the specified model and tools.
|
144
187
|
|
145
188
|
Args:
|
146
189
|
model_name (str): Name of the model to use
|
147
190
|
vision_model_name (str | None): Name of the vision model to use
|
191
|
+
no_stream (bool, optional): If True, the agent will not stream results.
|
192
|
+
compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
|
193
|
+
max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
|
148
194
|
|
149
195
|
Returns:
|
150
196
|
Agent: An agent with the specified model and tools
|
@@ -160,14 +206,16 @@ def create_orchestrator_agent(model_name: str, vision_model_name: str | None = N
|
|
160
206
|
ReadFileBlockTool(),
|
161
207
|
RipgrepTool(),
|
162
208
|
SearchDefinitionNames(),
|
163
|
-
LLMTool(model_name=
|
209
|
+
LLMTool(model_name=model_name, on_token=console_print_token if not no_stream else None),
|
164
210
|
AgentTool(agent=coding_agent_instance, agent_role="software expert", name="coder_agent_tool"),
|
165
211
|
]
|
166
212
|
|
167
213
|
if vision_model_name:
|
168
|
-
tools.append(LLMVisionTool(model_name=vision_model_name))
|
214
|
+
tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
|
169
215
|
|
170
216
|
return Agent(
|
171
217
|
model_name=model_name,
|
172
218
|
tools=tools,
|
219
|
+
compact_every_n_iterations=compact_every_n_iteration,
|
220
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
173
221
|
)
|
quantalogic/coding_agent.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
from quantalogic.agent import Agent
|
2
|
+
from quantalogic.console_print_token import console_print_token
|
2
3
|
from quantalogic.tools import (
|
3
4
|
DuckDuckGoSearchTool,
|
4
5
|
EditWholeContentTool,
|
@@ -19,13 +20,23 @@ from quantalogic.utils import get_coding_environment
|
|
19
20
|
from quantalogic.utils.get_quantalogic_rules_content import get_quantalogic_rules_file_content
|
20
21
|
|
21
22
|
|
22
|
-
def create_coding_agent(
|
23
|
+
def create_coding_agent(
|
24
|
+
model_name: str,
|
25
|
+
vision_model_name: str | None = None,
|
26
|
+
basic: bool = False,
|
27
|
+
no_stream: bool = False,
|
28
|
+
compact_every_n_iteration: int | None = None,
|
29
|
+
max_tokens_working_memory: int | None = None
|
30
|
+
) -> Agent:
|
23
31
|
"""Creates and configures a coding agent with a comprehensive set of tools.
|
24
32
|
|
25
33
|
Args:
|
26
34
|
model_name (str): Name of the language model to use for the agent's core capabilities
|
27
35
|
vision_model_name (str | None): Name of the vision model to use for the agent's core capabilities
|
28
36
|
basic (bool, optional): If True, the agent will be configured with a basic set of tools.
|
37
|
+
no_stream (bool, optional): If True, the agent will not stream results.
|
38
|
+
compact_every_n_iteration (int | None, optional): Frequency of memory compaction.
|
39
|
+
max_tokens_working_memory (int | None, optional): Maximum tokens for working memory.
|
29
40
|
|
30
41
|
Returns:
|
31
42
|
Agent: A fully configured coding agent instance with:
|
@@ -64,7 +75,7 @@ def create_coding_agent(model_name: str, vision_model_name: str | None = None, b
|
|
64
75
|
]
|
65
76
|
|
66
77
|
if vision_model_name:
|
67
|
-
tools.append(LLMVisionTool(model_name=vision_model_name))
|
78
|
+
tools.append(LLMVisionTool(model_name=vision_model_name, on_token=console_print_token if not no_stream else None))
|
68
79
|
|
69
80
|
if not basic:
|
70
81
|
tools.append(
|
@@ -72,6 +83,7 @@ def create_coding_agent(model_name: str, vision_model_name: str | None = None, b
|
|
72
83
|
model_name=model_name,
|
73
84
|
system_prompt="You are a software expert, your role is to answer coding questions.",
|
74
85
|
name="coding_consultant", # Handles implementation-level coding questions
|
86
|
+
on_token=console_print_token if not no_stream else None,
|
75
87
|
)
|
76
88
|
)
|
77
89
|
tools.append(
|
@@ -79,6 +91,7 @@ def create_coding_agent(model_name: str, vision_model_name: str | None = None, b
|
|
79
91
|
model_name=model_name,
|
80
92
|
system_prompt="You are a software architect, your role is to answer software architecture questions.",
|
81
93
|
name="software_architect", # Handles system design and architecture questions
|
94
|
+
on_token=console_print_token if not no_stream else None,
|
82
95
|
)
|
83
96
|
)
|
84
97
|
|
@@ -87,4 +100,6 @@ def create_coding_agent(model_name: str, vision_model_name: str | None = None, b
|
|
87
100
|
tools=tools,
|
88
101
|
specific_expertise=specific_expertise,
|
89
102
|
get_environment=get_coding_environment,
|
103
|
+
compact_every_n_iterations=compact_every_n_iteration,
|
104
|
+
max_tokens_working_memory=max_tokens_working_memory,
|
90
105
|
)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"""Print events with rich formatting."""
|
2
|
+
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from rich.console import Console
|
6
|
+
|
7
|
+
|
8
|
+
def console_print_token(event: str, data: Any | None = None):
|
9
|
+
"""Print a token with rich formatting.
|
10
|
+
|
11
|
+
Args:
|
12
|
+
event (str): The event name (e.g., 'stream_chunk')
|
13
|
+
data (Any | None): The token data to print
|
14
|
+
"""
|
15
|
+
console = Console()
|
16
|
+
console.print(data, end="")
|
quantalogic/docs_cli.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import subprocess
|
2
|
+
import os
|
3
|
+
import sys
|
4
|
+
|
5
|
+
def get_config_path():
|
6
|
+
"""Get the absolute path to the mkdocs configuration file."""
|
7
|
+
return os.path.join(os.path.dirname(os.path.dirname(__file__)), 'mkdocs', 'mkdocs.yml')
|
8
|
+
|
9
|
+
def serve_docs():
|
10
|
+
"""Serve MkDocs documentation locally."""
|
11
|
+
config_path = get_config_path()
|
12
|
+
try:
|
13
|
+
subprocess.run(['mkdocs', 'serve', '--config-file', config_path], check=True)
|
14
|
+
except subprocess.CalledProcessError as e:
|
15
|
+
print(f"Error serving documentation: {e}")
|
16
|
+
sys.exit(1)
|
17
|
+
|
18
|
+
def build_docs():
|
19
|
+
"""Build MkDocs documentation."""
|
20
|
+
config_path = get_config_path()
|
21
|
+
try:
|
22
|
+
subprocess.run(['mkdocs', 'build', '--config-file', config_path], check=True)
|
23
|
+
print("Documentation built successfully.")
|
24
|
+
except subprocess.CalledProcessError as e:
|
25
|
+
print(f"Error building documentation: {e}")
|
26
|
+
sys.exit(1)
|
27
|
+
|
28
|
+
def deploy_docs():
|
29
|
+
"""Deploy MkDocs documentation to GitHub Pages."""
|
30
|
+
config_path = get_config_path()
|
31
|
+
try:
|
32
|
+
subprocess.run(['mkdocs', 'gh-deploy', '--config-file', config_path], check=True)
|
33
|
+
print("Documentation deployed successfully.")
|
34
|
+
except subprocess.CalledProcessError as e:
|
35
|
+
print(f"Error deploying documentation: {e}")
|
36
|
+
sys.exit(1)
|
37
|
+
|
38
|
+
# Ensure the script can be run directly for testing
|
39
|
+
if __name__ == '__main__':
|
40
|
+
command = sys.argv[1] if len(sys.argv) > 1 else None
|
41
|
+
|
42
|
+
if command == 'serve':
|
43
|
+
serve_docs()
|
44
|
+
elif command == 'build':
|
45
|
+
build_docs()
|
46
|
+
elif command == 'deploy':
|
47
|
+
deploy_docs()
|
48
|
+
else:
|
49
|
+
print("Usage: python docs_cli.py [serve|build|deploy]")
|
50
|
+
sys.exit(1)
|