quantalogic 0.2.8__py3-none-any.whl → 0.2.12__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.
@@ -0,0 +1,127 @@
1
+ """LLM Vision Tool for analyzing images using a language model."""
2
+
3
+ import logging
4
+ from typing import Optional
5
+
6
+ from pydantic import ConfigDict, Field
7
+
8
+ from quantalogic.generative_model import GenerativeModel, Message
9
+ from quantalogic.tools.tool import Tool, ToolArgument
10
+
11
+ # DEFAULT_MODEL_NAME = "ollama/llama3.2-vision"
12
+ DEFAULT_MODEL_NAME = "openrouter/openai/gpt-4o-mini"
13
+
14
+
15
+ class LLMVisionTool(Tool):
16
+ """Tool to analyze images using a specified language model."""
17
+
18
+ model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")
19
+
20
+ name: str = Field(default="llm_vision_tool")
21
+ description: str = Field(
22
+ default=(
23
+ "Analyzes images and generates responses using a specified language model. "
24
+ "Supports multimodal input combining text and images."
25
+ )
26
+ )
27
+ arguments: list = Field(
28
+ default=[
29
+ ToolArgument(
30
+ name="system_prompt",
31
+ arg_type="string",
32
+ description="The system prompt to guide the model's behavior",
33
+ required=True,
34
+ example="You are an expert in image analysis and visual understanding.",
35
+ ),
36
+ ToolArgument(
37
+ name="prompt",
38
+ arg_type="string",
39
+ description="The question or instruction about the image",
40
+ required=True,
41
+ example="What is shown in this image?",
42
+ ),
43
+ ToolArgument(
44
+ name="image_url",
45
+ arg_type="string",
46
+ description="URL of the image to analyze",
47
+ required=True,
48
+ example="https://example.com/image.jpg",
49
+ ),
50
+ ToolArgument(
51
+ name="temperature",
52
+ arg_type="string",
53
+ description='Sampling temperature between "0.0" and "1.0"',
54
+ required=True,
55
+ default="0.7",
56
+ example="0.7",
57
+ ),
58
+ ]
59
+ )
60
+
61
+ model_name: str = Field(..., description="The name of the language model to use")
62
+ generative_model: Optional[GenerativeModel] = Field(default=None)
63
+
64
+ def model_post_init(self, __context):
65
+ """Initialize the generative model after model initialization."""
66
+ if self.generative_model is None:
67
+ self.generative_model = GenerativeModel(model=self.model_name)
68
+ logging.debug(f"Initialized LLMVisionTool with model: {self.model_name}")
69
+
70
+ def execute(self, system_prompt: str, prompt: str, image_url: str, temperature: str = "0.7") -> str:
71
+ """Execute the tool to analyze an image and generate a response.
72
+
73
+ Args:
74
+ system_prompt: The system prompt to guide the model
75
+ prompt: The question or instruction about the image
76
+ image_url: URL of the image to analyze
77
+ temperature: Sampling temperature
78
+
79
+ Returns:
80
+ The generated response
81
+
82
+ Raises:
83
+ ValueError: If temperature is invalid or image_url is malformed
84
+ Exception: If there's an error during response generation
85
+ """
86
+ try:
87
+ temp = float(temperature)
88
+ if not (0.0 <= temp <= 1.0):
89
+ raise ValueError("Temperature must be between 0 and 1.")
90
+ except ValueError as ve:
91
+ logging.error(f"Invalid temperature value: {temperature}")
92
+ raise ValueError(f"Invalid temperature value: {temperature}") from ve
93
+
94
+ if not image_url.startswith(("http://", "https://")):
95
+ raise ValueError("Image URL must start with http:// or https://")
96
+
97
+ # Prepare the messages history
98
+ messages_history = [
99
+ Message(role="system", content=system_prompt),
100
+ ]
101
+
102
+ if self.generative_model is None:
103
+ self.generative_model = GenerativeModel(model=self.model_name)
104
+
105
+ self.generative_model.temperature = temp
106
+
107
+ try:
108
+ response_stats = self.generative_model.generate_with_history(
109
+ messages_history=messages_history, prompt=prompt, image_url=image_url
110
+ )
111
+ response = response_stats.response.strip()
112
+ logging.info(f"Generated response: {response}")
113
+ return response
114
+ except Exception as e:
115
+ logging.error(f"Error generating response: {e}")
116
+ raise Exception(f"Error generating response: {e}") from e
117
+
118
+
119
+ if __name__ == "__main__":
120
+ # Example usage
121
+ tool = LLMVisionTool(model_name=DEFAULT_MODEL_NAME)
122
+ system_prompt = "You are a vision expert."
123
+ question = "What is shown in this image? Describe it with details."
124
+ image_url = "https://fastly.picsum.photos/id/767/200/300.jpg?hmac=j5YA1cRw-jS6fK3Mx2ooPwl2_TS3RSyLmFmiM9TqLC4"
125
+ temperature = "0.7"
126
+ answer = tool.execute(system_prompt=system_prompt, prompt=question, image_url=image_url, temperature=temperature)
127
+ print(answer)
@@ -342,14 +342,14 @@ class NodeJsTool(Tool):
342
342
  RuntimeError: If pulling the Docker image fails.
343
343
  """
344
344
  try:
345
- logger.info(f"Pulling Docker image: {docker_image}")
345
+ logger.debug(f"Pulling Docker image: {docker_image}")
346
346
  subprocess.run(
347
347
  ["docker", "pull", docker_image],
348
348
  check=True,
349
349
  capture_output=True,
350
350
  text=True,
351
351
  )
352
- logger.info(f"Successfully pulled Docker image '{docker_image}'.")
352
+ logger.debug(f"Successfully pulled Docker image '{docker_image}'.")
353
353
  except subprocess.CalledProcessError as e:
354
354
  error_msg = f"Failed to pull Docker image '{docker_image}': {e.stderr.strip()}"
355
355
  logger.error(error_msg)
@@ -266,7 +266,7 @@ class PythonTool(Tool):
266
266
  capture_output=True,
267
267
  text=True,
268
268
  )
269
- logger.info(f"Successfully pulled Docker image '{docker_image}'.")
269
+ logger.debug(f"Successfully pulled Docker image '{docker_image}'.")
270
270
  except subprocess.CalledProcessError as e:
271
271
  error_msg = f"Failed to pull Docker image '{docker_image}': {e.stderr.strip()}"
272
272
  logger.error(error_msg)
@@ -365,7 +365,7 @@ class PythonTool(Tool):
365
365
  docker_run_cmd += ["bash", "-c", venv_and_run]
366
366
  logger.debug("Added script execution command to Docker run command.")
367
367
 
368
- logger.info(f"Executing Docker command: {' '.join(docker_run_cmd)}")
368
+ logger.debug(f"Executing Docker command: {' '.join(docker_run_cmd)}")
369
369
  try:
370
370
  result = subprocess.run(
371
371
  docker_run_cmd,
@@ -204,7 +204,7 @@ class ReplaceInFileTool(Tool):
204
204
  if not block.search:
205
205
  if block.replace:
206
206
  content += f"\n{block.replace}"
207
- logger.info(f"Block {idx}: Appended content")
207
+ logger.debug(f"Block {idx}: Appended content")
208
208
  continue
209
209
 
210
210
  match_found = False
@@ -218,7 +218,7 @@ class ReplaceInFileTool(Tool):
218
218
  content = f"{content[:start]}{content[end:]}"
219
219
  changes.append((start, start + len(block.replace) if block.replace else start))
220
220
  match_found = True
221
- logger.info(f"Block {idx}: Exact match {'replaced' if block.replace else 'deleted'}")
221
+ logger.debug(f"Block {idx}: Exact match {'replaced' if block.replace else 'deleted'}")
222
222
 
223
223
  if not match_found:
224
224
  similarity, matched_str = self.find_similar_match(block.search, content)
@@ -232,7 +232,7 @@ class ReplaceInFileTool(Tool):
232
232
  else:
233
233
  content = f"{content[:start]}{content[end:]}"
234
234
  changes.append((start, start + len(block.replace) if block.replace else start))
235
- logger.info(
235
+ logger.debug(
236
236
  f"Block {idx}: Similar match (similarity={similarity:.1%}) "
237
237
  f"{'replaced' if block.replace else 'deleted'}"
238
238
  )
@@ -136,7 +136,7 @@ class RipgrepTool(Tool):
136
136
  return "No files matching the pattern (after .gitignore filtering)"
137
137
 
138
138
  try:
139
- logger.info(f"Executing ripgrep with args: {args}")
139
+ logger.debug(f"Executing ripgrep with args: {args}")
140
140
  # Add filtered files to ripgrep command
141
141
  args.extend(filtered_files)
142
142
  output = subprocess.check_output([rg_path] + args, text=True, cwd=cwd)
@@ -194,7 +194,7 @@ class RipgrepTool(Tool):
194
194
  for path in system_paths + node_paths:
195
195
  full_path = Path(__file__).parent.parent / path if str(path).startswith("node_modules") else path
196
196
  if full_path.exists():
197
- logger.info(f"Found ripgrep at: {full_path}")
197
+ logger.debug(f"Found ripgrep at: {full_path}")
198
198
  return str(full_path)
199
199
 
200
200
  # Check system PATH using which/where
@@ -202,7 +202,7 @@ class RipgrepTool(Tool):
202
202
  command = "where" if os.name == "nt" else "which"
203
203
  rg_path = subprocess.check_output([command, bin_name], text=True).strip()
204
204
  if rg_path:
205
- logger.info(f"Found ripgrep in PATH at: {rg_path}")
205
+ logger.debug(f"Found ripgrep in PATH at: {rg_path}")
206
206
  return rg_path
207
207
  except subprocess.CalledProcessError:
208
208
  logger.debug("Ripgrep not found in system PATH")
quantalogic/tools/tool.py CHANGED
@@ -25,10 +25,10 @@ class ToolArgument(BaseModel):
25
25
  arg_type: Literal["string", "int", "float", "boolean"] = Field(
26
26
  ..., description="The type of the argument. Must be one of: string, integer, float, boolean."
27
27
  )
28
- description: str | None = Field(None, description="A brief description of the argument.")
28
+ description: str | None = Field(default=None, description="A brief description of the argument.")
29
29
  required: bool = Field(default=False, description="Indicates if the argument is required.")
30
- default: str | None = Field(None, description="The default value for the argument.")
31
- example: str | None = Field(None, description="An example value to illustrate the argument's usage.")
30
+ default: str | None = Field(default=None, description="The default value for the argument. This parameter is required.")
31
+ example: str | None = Field(default=None, description="An example value to illustrate the argument's usage.")
32
32
  need_validation: bool = Field(default=False, description="Indicates if the argument needs validation.")
33
33
 
34
34
 
@@ -153,6 +153,7 @@ class PatchError(Exception):
153
153
  super().__init__(message)
154
154
 
155
155
  def __str__(self):
156
+ """Override the default exception string to include context."""
156
157
  msg = [super().__str__()]
157
158
  if self.context:
158
159
  for key, value in self.context.items():
@@ -43,6 +43,7 @@ class WriteFileTool(Tool):
43
43
  description="Overwrite mode. If true, existing files can be overwritten. Defaults to False.",
44
44
  required=False,
45
45
  example="False",
46
+ default="False",
46
47
  ),
47
48
  ]
48
49
 
@@ -0,0 +1,37 @@
1
+
2
+ import requests
3
+ from packaging import version
4
+
5
+ from quantalogic.version import get_version
6
+
7
+
8
+ def check_if_is_latest_version() -> (bool,str|None):
9
+ """Check if the current version is the latest version on PyPI.
10
+
11
+ Returns:
12
+ bool: True if the current version is the latest, False otherwise
13
+ """
14
+ try:
15
+ current_version = get_version()
16
+ response = requests.get("https://pypi.org/pypi/quantalogic/json", timeout=5)
17
+ response.raise_for_status()
18
+ latest_version = response.json()["info"]["version"]
19
+ return version.parse(current_version) <= version.parse(latest_version), latest_version
20
+ except (requests.RequestException, KeyError):
21
+ return False, None
22
+
23
+
24
+ def main():
25
+ """Test the version checking functionality."""
26
+ is_latest, latest_version = check_if_is_latest_version()
27
+ if is_latest:
28
+ print("✅ You're running the latest version")
29
+ elif latest_version:
30
+ print(f"⚠️ Update available: {latest_version}")
31
+ else:
32
+ print("❌ Could not check version")
33
+
34
+ if __name__ == "__main__":
35
+ main()
36
+
37
+
@@ -35,18 +35,18 @@ def download_http_file(
35
35
 
36
36
  for attempt in range(max_retries):
37
37
  try:
38
- logger.info(f"Attempt {attempt + 1} of {max_retries} to download {url}")
38
+ logger.debug(f"Attempt {attempt + 1} of {max_retries} to download {url}")
39
39
  response = requests.get(url, headers=headers, stream=True, timeout=timeout)
40
40
  response.raise_for_status()
41
41
 
42
42
  content_type = response.headers.get("Content-Type", "unknown")
43
- logger.info(f"Downloading content with Content-Type: {content_type}")
43
+ logger.debug(f"Downloading content with Content-Type: {content_type}")
44
44
 
45
45
  with open(local_path, "wb") as file:
46
46
  for chunk in response.iter_content(chunk_size=chunk_size):
47
47
  file.write(chunk)
48
48
 
49
- logger.info(f"File successfully downloaded and saved to {local_path}")
49
+ logger.debug(f"File successfully downloaded and saved to {local_path}")
50
50
  return local_path
51
51
 
52
52
  except HTTPError as http_err:
@@ -70,7 +70,7 @@ def download_http_file(
70
70
 
71
71
  if attempt < max_retries - 1:
72
72
  sleep_duration = delay * (2**attempt) # Exponential backoff
73
- logger.info(f"Retrying in {sleep_duration} seconds...")
73
+ logger.debug(f"Retrying in {sleep_duration} seconds...")
74
74
  sleep(sleep_duration)
75
75
 
76
76
  logger.error("Max retries reached. Download failed.")
@@ -45,7 +45,7 @@ def read_http_text_content(
45
45
 
46
46
  for attempt in range(retries):
47
47
  try:
48
- logger.info(f"Attempt {attempt + 1} of {retries} to fetch {url}")
48
+ logger.debug(f"Attempt {attempt + 1} of {retries} to fetch {url}")
49
49
  response = requests.get(url, headers=headers, timeout=timeout)
50
50
  response.raise_for_status() # Raise an HTTPError for bad responses (4xx and 5xx)
51
51
 
@@ -87,7 +87,7 @@ def read_http_text_content(
87
87
 
88
88
  if attempt < retries - 1:
89
89
  sleep_duration = delay * (2**attempt) # Exponential backoff
90
- logger.info(f"Retrying in {sleep_duration} seconds...")
90
+ logger.debug(f"Retrying in {sleep_duration} seconds...")
91
91
  sleep(sleep_duration)
92
92
 
93
93
  return None, error_msg
quantalogic/version.py CHANGED
@@ -1,4 +1,5 @@
1
+ import importlib.metadata
2
+
1
3
 
2
- VERSION = "0.2.8"
3
4
  def get_version() -> str:
4
- return VERSION
5
+ return importlib.metadata.version("quantalogic")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: quantalogic
3
- Version: 0.2.8
3
+ Version: 0.2.12
4
4
  Summary: QuantaLogic ReAct Agents
5
5
  Author: Raphaël MANSUY
6
6
  Author-email: raphael.mansuy@gmail.com
@@ -31,6 +31,7 @@ Requires-Dist: tree-sitter-python (>=0.23.6,<0.24.0)
31
31
  Requires-Dist: tree-sitter-rust (>=0.23.2,<0.24.0)
32
32
  Requires-Dist: tree-sitter-scala (>=0.23.4,<0.24.0)
33
33
  Requires-Dist: tree-sitter-typescript (>=0.23.2,<0.24.0)
34
+ Requires-Dist: types-requests (>=2.32.0.20241016,<3.0.0.0)
34
35
  Requires-Dist: uvicorn (>=0.34.0,<0.35.0)
35
36
  Requires-Dist: websocket (>=0.2.1,<0.3.0)
36
37
  Description-Content-Type: text/markdown
@@ -123,8 +124,10 @@ Usage: quantalogic [OPTIONS] COMMAND [ARGS]...
123
124
 
124
125
  Options:
125
126
  --version Show version information.
126
- --model-name TEXT Specify the model to use (litellm format,
127
+ --model-name TEXT Specify the text model to use (litellm format,
127
128
  e.g. "openrouter/deepseek-chat").
129
+ --vision-model-name TEXT Specify the vision model to use (litellm format,
130
+ e.g. "openrouter/A/gpt-4o-mini").
128
131
  --log [info|debug|warning] Set logging level (info/debug/warning).
129
132
  --verbose Enable verbose output.
130
133
  --mode [code|basic|interpreter|full|code-basic]
@@ -385,7 +388,7 @@ By integrating these tools into its architecture, QuantaLogic allows agents to p
385
388
  | Script Execution | Python Tool, Node.js Tool, Elixir Tool |
386
389
  | File Operations | Read File Tool, Write File Tool, Edit Whole Content Tool, Replace In File Tool |
387
390
  | Code Analysis | Search Definition Names Tool, Ripgrep Tool |
388
- | Content Generation | LLM Tool |
391
+ | Content Generation | LLM Tool, LLMVisionTool |
389
392
  | Utility and Management | Download HTTP File Tool, List Directory Tool, Markitdown Tool, Unified Diff Tool |
390
393
 
391
394
  ---
@@ -681,7 +684,30 @@ print("Ripgrep Results:", output)
681
684
 
682
685
  ---
683
686
 
684
- ### 14. LLM Tool
687
+ #### 14. LLMVisionTool
688
+
689
+ The **LLMVisionTool** enables processing of visual inputs using vision-language models.
690
+
691
+ ##### Parameters
692
+
693
+ | Parameter | Type | Description | Example |
694
+ |----------------|---------|------------------------------------------------------------------------|--------------------------------------------|
695
+ | `image_path` | string | Path to the image file to process | `./path/to/image.png` |
696
+ | `prompt` | string | The question or instruction for the vision model | `Describe the contents of this image` |
697
+ | `temperature` | float | Sampling temperature between 0.0 and 1.0 | `0.7` |
698
+
699
+ ##### Example Usage
700
+ ```python
701
+ vision_tool = LLMVisionTool()
702
+ response = vision_tool.execute(
703
+ image_path="./path/to/image.png",
704
+ prompt="Describe the contents of this image",
705
+ temperature=0.7
706
+ )
707
+ print("Vision Model Response:", response)
708
+ ```
709
+
710
+ #### 15. LLM Tool
685
711
 
686
712
  The **LLM Tool** generates answers using a specified language model.
687
713
 
@@ -706,7 +732,7 @@ print("LLM Response:", response)
706
732
 
707
733
  ---
708
734
 
709
- ### 15. Download HTTP File Tool
735
+ ### 16. Download HTTP File Tool
710
736
 
711
737
  The **Download HTTP File Tool** downloads a file from a specified HTTP URL.
712
738
 
@@ -726,7 +752,7 @@ print(result)
726
752
 
727
753
  ---
728
754
 
729
- ### 16. List Directory Tool
755
+ ### 17. List Directory Tool
730
756
 
731
757
  The **List Directory Tool** lists files in a specified directory.
732
758
 
@@ -745,7 +771,7 @@ print("Directory Files:", result)
745
771
 
746
772
  ---
747
773
 
748
- ### 17. Markitdown Tool
774
+ ### 18. Markitdown Tool
749
775
 
750
776
  The **Markitdown Tool** processes markdown files, possibly for conversion or rendering.
751
777
 
@@ -762,26 +788,6 @@ result = markitdown_tool.execute(markdown_path="./path/to/file.md")
762
788
  print("Processed Markdown Output:", result)
763
789
  ```
764
790
 
765
- ---
766
-
767
- ### 18. Unified Diff Tool
768
-
769
- The **Unified Diff Tool** generates a unified diff between two texts or files.
770
-
771
- #### Parameters
772
-
773
- | Parameter | Type | Description | Example |
774
- |--------------|--------|------------------------------------------------|------------------------|
775
- | `original` | string | The original content or file path. | `old_text.txt` |
776
- | `updated` | string | The updated content or file path. | `new_text.txt` |
777
-
778
- #### Example Usage
779
- ```python
780
- diff_tool = UnifiedDiffTool()
781
- result = diff_tool.execute(original="old_text.txt", updated="new_text.txt")
782
- print("Unified Diff Output:", result)
783
- ```
784
-
785
791
 
786
792
  #### Creating Custom Tools
787
793
 
@@ -1,29 +1,29 @@
1
1
  quantalogic/__init__.py,sha256=HFk7_19UzHzYwvPzb9QTQ4w_lPwTTPda61AYb8qggZY,686
2
- quantalogic/agent.py,sha256=QBQc-C_h_DsstV2ntHETh8XywPAcY31-ThO2SiBqvB0,25443
3
- quantalogic/agent_config.py,sha256=sNuZ0Y02h3ra2hcjAE3-8Tt-NE8QSarRsTB0auTLgn0,3595
4
- quantalogic/coding_agent.py,sha256=ivHBn3hIDEt9V1LDXI4l-COeGXYVp_v_rrx9ng8sP2A,3214
2
+ quantalogic/agent.py,sha256=ROE9hJe9b2eRhhuH64-rxWWHsXO4lnjV-PdjqqdxS_g,26653
3
+ quantalogic/agent_config.py,sha256=iPJjY8OZDOoV7lYuL5TAj5JXPcRL4VUOzu5CZVeB3Sg,4520
4
+ quantalogic/coding_agent.py,sha256=FrodyypgtOOV-AvJiQP8PLkUIDQkDrye26dbOxIEKjM,3486
5
5
  quantalogic/event_emitter.py,sha256=jqot2g4JRXc88K6PW837Oqxbf7shZfO-xdPaUWmzupk,7901
6
- quantalogic/generative_model.py,sha256=JkZz7YBd-v9n5EURidKUddkCLNvNZaqMzo5PgE_ugmc,8398
6
+ quantalogic/generative_model.py,sha256=LKuv_aRpEwMgeEUzHg4r3XkQdPHAr4Mu-ZfWIAqR4Ik,10651
7
7
  quantalogic/interactive_text_editor.py,sha256=kYeTA2qej5kxtPvAUHy_Dr2MhrGQAyenLFpW9mU9Rmw,6855
8
- quantalogic/main.py,sha256=_oLhXNTDSH7Zfc1__jPgOvqZGpYH5VSjamdLwZ4xqDM,8698
8
+ quantalogic/main.py,sha256=CdQVjs_5EMEpXUHoqfW5MyfOnQosERRJx1-M7jSsMXU,11061
9
9
  quantalogic/memory.py,sha256=zbtRuM05jaS2lJll-92dt5JfYVLERnF_m_9xqp2x-k0,6304
10
10
  quantalogic/model_names.py,sha256=UZlz25zG9B2dpfwdw_e1Gw5qFsKQ7iME9FJh9Ts4u6s,938
11
- quantalogic/print_event.py,sha256=-4qZmFI2BTkXuGE9DoKm6Vs-GzK1F9WJGt9GqpRQlQQ,2175
12
- quantalogic/prompts.py,sha256=GWVWnwFBxcVtOPvm1rUr1VnWY0OVqaBwVU_pMNunH2k,3609
11
+ quantalogic/print_event.py,sha256=nl1aRdYnsU72SRezafePF82zKtrqGfY8OoTx2QfbdE8,2206
12
+ quantalogic/prompts.py,sha256=BHIST57DYcTeTb7rvV1QkGLt0_B8Wk8a_9tsnsN6suk,3547
13
13
  quantalogic/server/__init__.py,sha256=8sz_PYAUCrkM6JM5EAUeIzNM4NPW6j6UT72JVkc21WQ,91
14
- quantalogic/server/agent_server.py,sha256=GmglYf-LeVQQOdikMFDvPq1R0wKt6wIBpufW8XzP-iE,22489
14
+ quantalogic/server/agent_server.py,sha256=38GEK_MpLp--CX_dCkopTFOU7KcGuOw4-GciwmRJyyg,22502
15
15
  quantalogic/server/models.py,sha256=nVUGWElOsUw8QnRCGJylk25wCew_5gohe6nldYighUA,1322
16
16
  quantalogic/server/routes.py,sha256=00nFe6s0T4Gv8vCp0wQFjWGo1tC8FViH8h0koAJdWs4,4216
17
- quantalogic/server/state.py,sha256=UuG4VZTzo3RgQzkgHvnV6Qb1oZWs3fpFXyjVfwFKx3s,7364
17
+ quantalogic/server/state.py,sha256=TwtL0BTp_LT-fynF1IR4k8WVXuxXWtSv3NgWG9fuUME,7369
18
18
  quantalogic/server/static/js/event_visualizer.js,sha256=eFkkWyNZw3zOZlF18kxbfsWql8a2C13qBFEOAPzrj88,19646
19
19
  quantalogic/server/static/js/quantalogic.js,sha256=x7TrlZGR1Y0WLK2DWl1xY847BhEWMPnL0Ua7KtOldUc,22311
20
20
  quantalogic/server/templates/index.html,sha256=nDnXJoQEm1vXbhXtgaYk0G5VXj0wwzE6KrqEDhHFpj4,7773
21
- quantalogic/tool_manager.py,sha256=FyghX2M_yGmdL7ovJR4ZGYIiBwkxA-bPjpI-y4IFx4Y,2421
22
- quantalogic/tools/__init__.py,sha256=VmvOHjCZmcVRnm5meMVBE8wMRmY1D7M2kxkrPeieWcI,1431
23
- quantalogic/tools/agent_tool.py,sha256=qeRp74EBqPSGu6JNZMATGyDoSCzPo7EnB2rmCP5wsBE,3050
21
+ quantalogic/tool_manager.py,sha256=JAC5E5kLfYzYJx0QRIWbG14q1hlkOcwJFBG7HE8twpU,2425
22
+ quantalogic/tools/__init__.py,sha256=OxZp1nWZC5EewMJJVEvP6Fd2RMFlpaIYLHqChXPG_6s,1495
23
+ quantalogic/tools/agent_tool.py,sha256=MXCXxWHRch7VK4UWhtRP1jeI8Np9Ne2CUGo8vm1oZiM,3064
24
24
  quantalogic/tools/download_http_file_tool.py,sha256=wTfanbXjIRi5-qrbluuLvNmDNhvmYAnlMVb3dO8C2ss,2210
25
25
  quantalogic/tools/edit_whole_content_tool.py,sha256=nXmpAvojvqvAcqNMy1kUKZ1ocboky_ZcnCR4SNCSPgw,2360
26
- quantalogic/tools/elixir_tool.py,sha256=rGWP6lsfSw0pyZi9I4Fcj4k7Q8Ie6BAFaPtC9YiPYfc,7637
26
+ quantalogic/tools/elixir_tool.py,sha256=fzPPtAW-Koy9KB0r5k2zV1f1U0WphL-LXPPOBkeNkug,7652
27
27
  quantalogic/tools/execute_bash_command_tool.py,sha256=fnx-zSPpxR2EofaleygAorrR21gRs43jBWh7IBAoNKw,4131
28
28
  quantalogic/tools/input_question_tool.py,sha256=UoTlNhdmdr-eyiVtVCG2qJe_R4bU_ag-DzstSdmYkvM,1848
29
29
  quantalogic/tools/language_handlers/__init__.py,sha256=5GD6TYsMqRni0nwePp2KOjNQ04GnT5wihT6YAuvx43c,699
@@ -37,33 +37,35 @@ quantalogic/tools/language_handlers/rust_handler.py,sha256=t_AqKVa3KVk6SVkq_UjUU
37
37
  quantalogic/tools/language_handlers/scala_handler.py,sha256=wr-cWOIFOc0UYwODmEtT6rV63Qf1NyNB_BLo23GLrvk,1281
38
38
  quantalogic/tools/language_handlers/typescript_handler.py,sha256=L4vuJMYxKO3_83dQhdwZ9fogauIV7rwoicRT0xLGfkQ,1738
39
39
  quantalogic/tools/list_directory_tool.py,sha256=8Hy38DelSh-mRqS_uDLpeBYoHLtEy5ji77xI-TJu3Ms,4176
40
- quantalogic/tools/llm_tool.py,sha256=_6cMM2gpX6Wc_rV5y8L6-w3PoRwZtoRl09ZlPAlOckw,5005
40
+ quantalogic/tools/llm_tool.py,sha256=9SNApqvNT2qF9GWxEVzMKq8XiVtc-UoyamhsIWvgZQI,5456
41
+ quantalogic/tools/llm_vision_tool.py,sha256=OP2B6bYjnKvO7TjSG0gEtwvV5L0m4uFDWAaU54cOG3w,4913
41
42
  quantalogic/tools/markitdown_tool.py,sha256=GHJMPdWmwF-CBu3vHWhy-kXJYRDluFkh18KN06yNHOc,4101
42
- quantalogic/tools/nodejs_tool.py,sha256=2VTkZgtyXmv2E18CVaml3CKZE28WL9Tbv2IVdziv8wA,19903
43
- quantalogic/tools/python_tool.py,sha256=t66ge3xXS55-wJkddnVU9210TuDVoRI0Y-rsZwWxYIk,18154
43
+ quantalogic/tools/nodejs_tool.py,sha256=zdnE0VFj_5786uR2L0o-SKR0Gk8L-U7rdj7xGHJYIq0,19905
44
+ quantalogic/tools/python_tool.py,sha256=70HLbfU2clOBgj4axDOtIKzXwEBMNGEAX1nGSf-KNNQ,18156
44
45
  quantalogic/tools/read_file_block_tool.py,sha256=FTcDAUOOPQOvWRjnRI6nMI1Upus90klR4PC0pbPP_S8,5266
45
46
  quantalogic/tools/read_file_tool.py,sha256=bOWJbA0GU-hYbFOJ-tQVlSVz0r6WrVAfzy4aXOnAcBw,2757
46
- quantalogic/tools/replace_in_file_tool.py,sha256=6nbW3v0yzo3YDh-w30oW_kulmYzn0xsIfUw1jcpJh_c,12950
47
- quantalogic/tools/ripgrep_tool.py,sha256=a0V5a-HozZqWPBxmIq8BoRvcFd7UXm1Z7TuE7l73H0Y,14288
47
+ quantalogic/tools/replace_in_file_tool.py,sha256=n63s09Y8RXOKGjxfWw0D6F6JpQ6ERSJxVJOzmceVXLk,12953
48
+ quantalogic/tools/ripgrep_tool.py,sha256=sRzHaWac9fa0cCGhECJN04jw_Ko0O3u45KDWzMIYcvY,14291
48
49
  quantalogic/tools/search_definition_names.py,sha256=qolDbRUssE5EyghWqgs69Kmu_dhzeO9GliqgP9pkUHM,16704
49
50
  quantalogic/tools/task_complete_tool.py,sha256=L8tuyVoN07Q2hOsxx17JTW0C5Jd_N-C0i_0PtCUQUKU,929
50
- quantalogic/tools/tool.py,sha256=pC9aLMv4R0pDbuQsWHOUQG1EVaDeAEABIoH0djznCH8,5598
51
- quantalogic/tools/unified_diff_tool.py,sha256=cDWZjtIVodvhWxV479u0RRs98GKn13b3I7z9anFyvK0,14075
52
- quantalogic/tools/write_file_tool.py,sha256=7zbXbjZDKDu6ZY1N1mH2w0oyVz5FMxROk1JmKtdfpTA,3735
51
+ quantalogic/tools/tool.py,sha256=ixouKOcmyYMP4YnzXANhIxixh4xgBVCRqvnBccqrAY0,5650
52
+ quantalogic/tools/unified_diff_tool.py,sha256=wTKXIoBEPcC_EcQmpJZVi95vq0Ncvsw1Kyc7XqPO6dU,14147
53
+ quantalogic/tools/write_file_tool.py,sha256=_mx9_Zjg2oMAAVzlcHEKjZVZUxQVgbRfcoMKgWnoZcg,3764
53
54
  quantalogic/utils/__init__.py,sha256=Ltq7tzLuHCl9BpCvfRVA9Sjrtp1RJesrn7G980lbl_c,563
54
55
  quantalogic/utils/ask_user_validation.py,sha256=F0jkbFJVXAImcSSP7op6dov5i80hRvZGRvBHbfcZrxg,340
55
- quantalogic/utils/download_http_file.py,sha256=cm0Jr2PWLoXxJL5-zMOYxJtYvugZSLWurEWt2HlPryw,3468
56
+ quantalogic/utils/check_version.py,sha256=LZDU78EwMSDw3cv-sXQK_3wfTGZeFAyPR4OsepM8aIU,1095
57
+ quantalogic/utils/download_http_file.py,sha256=FTN3brq9WvCFvuBX-lYAhjsdYTzQT4m9m2vqlcyjkNk,3472
56
58
  quantalogic/utils/get_coding_environment.py,sha256=ujZ2_nDryrLWe6ZUalSu9WDG6t53UJFn7FJ_ER7Jixc,389
57
59
  quantalogic/utils/get_environment.py,sha256=7wWruSHYTUlnQWW27qU3WFYZnncqqqdofsxAsUU7lhw,875
58
60
  quantalogic/utils/get_quantalogic_rules_content.py,sha256=fnEFTyClXzpI0MLaM-gB9R6l4CJlu2NnaYiR09ciJC8,673
59
61
  quantalogic/utils/git_ls.py,sha256=_aXg2TwqYv9CoOrhQ1gqHCqu1j8wOVigQNWbGncSDlM,4361
60
62
  quantalogic/utils/read_file.py,sha256=tSRVHk8dIP4nNLL89v5kRki4hOTjVyjbmuEb2zwvwCY,2077
61
- quantalogic/utils/read_http_text_content.py,sha256=1nRLQ9DHP_fKrm0rIEJBF0ROmB78e4lct2hUzD2PAUk,4408
62
- quantalogic/version.py,sha256=En2YsrG-VTf0ISc2bW9hm7HFnvQTMuxJpfpAaapjJDI,64
63
+ quantalogic/utils/read_http_text_content.py,sha256=n3IayT5KcqctIVVF2gOQQAMf3Ow6eenlVgfXTpLcQbw,4410
64
+ quantalogic/version.py,sha256=ea_cRutaQk5_lwlLbUUvPFuOT7Of7-gAsDl7wdveS-g,107
63
65
  quantalogic/xml_parser.py,sha256=cTRorr5sVfkIzH72M0C-GQ9ROGPiz2FTT66U9ndjzhE,9538
64
66
  quantalogic/xml_tool_parser.py,sha256=lsVzClZBrZan7wjCuCKnGHWzksXI3VMy_vWthxu2_bo,3738
65
- quantalogic-0.2.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
66
- quantalogic-0.2.8.dist-info/METADATA,sha256=XISo9oYxS-YXKmE7Prszx8Y_b4Oc36FYNXKAzhILsE8,39180
67
- quantalogic-0.2.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
68
- quantalogic-0.2.8.dist-info/entry_points.txt,sha256=wgSq5SRU98yvlRHGEZD1Xn7sS5CSjH2RfUtTa6Qy28Q,52
69
- quantalogic-0.2.8.dist-info/RECORD,,
67
+ quantalogic-0.2.12.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
68
+ quantalogic-0.2.12.dist-info/METADATA,sha256=gqelTtdz_LdjDImTJ4lAhTUFqTQ3VNf_2Wa0OjEAY84,39806
69
+ quantalogic-0.2.12.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
70
+ quantalogic-0.2.12.dist-info/entry_points.txt,sha256=wgSq5SRU98yvlRHGEZD1Xn7sS5CSjH2RfUtTa6Qy28Q,52
71
+ quantalogic-0.2.12.dist-info/RECORD,,