feat: Add call_external_copilot tool and update StandaloneLLMTool

This commit is contained in:
cyclop-bot
2025-06-03 15:38:25 -05:00
parent 9a1147c569
commit 2396e82b1b
+102 -13
View File
@@ -3,6 +3,8 @@ import os
import json import json
import logging import logging
from openai import OpenAI from openai import OpenAI
import urllib.request
import urllib.error
class StandaloneLLMTool(BaseTool): class StandaloneLLMTool(BaseTool):
def __init__(self): def __init__(self):
@@ -15,7 +17,7 @@ class StandaloneLLMTool(BaseTool):
return [ return [
{ {
"type": "function", "type": "function",
"function": { "function": {
"name": "call_external_llm", "name": "call_external_llm",
"description": "Call an external language model", "description": "Call an external language model",
"parameters": { "parameters": {
@@ -29,34 +31,121 @@ class StandaloneLLMTool(BaseTool):
"type": "string", "type": "string",
"description": "The model to use for generating the detailed instructions. Use mini for most coding tasks, preview when needing sophisticated reasoning", "description": "The model to use for generating the detailed instructions. Use mini for most coding tasks, preview when needing sophisticated reasoning",
"enum": ["mini", "max"], "enum": ["mini", "max"],
"default": "o1-mini" "default": "mini" # Set default to 'mini' as per spec
}, },
"max_tokens": { "max_tokens": {
"type": "integer", "type": "integer",
"description": "The maximum number of tokens to use for generating the detailed instructions. Default is 16384.", "description": "The maximum number of tokens to use for generating the detailed instructions. Default is 16384.",
"default": 16384
} }
}, },
"required": ["prompt"] "required": ["prompt"]
} }
}, },
"_tags": ["llm", "external"] "_tags": ["llm", "external"]
},
{
"type": "function",
"function": {
"name": "call_external_copilot",
"description": "Calls a separate AI copilot instance over HTTP to get a response.",
"parameters": {
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "The plain text prompt to send to the external copilot."
},
"url": {
"type": "string",
"description": "The URL of the external copilot's API endpoint (e.g., 'http://localhost:8000/copilot')."
}
},
"required": ["prompt", "url"]
}
},
"_tags": ["copilot", "external", "http"]
} }
] ]
def _call_external_copilot(self, prompt: str, url: str):
logging.info(f"Calling external copilot at URL: {url} with prompt: {prompt[:50]}...")
if not url.startswith('http://') and not url.startswith('https://'):
error_message = f"Invalid URL scheme for external copilot: {url}. URL must start with http:// or https://"
logging.error(error_message)
return error_message
try:
req = urllib.request.Request(
url,
data=prompt.encode('utf-8'),
headers={'Content-Type': 'text/plain; charset=utf-8', 'User-Agent': 'DualAICopilot/0.1'},
method='POST'
)
with urllib.request.urlopen(req, timeout=60) as response:
if response.status == 200:
response_data = response.read().decode('utf-8')
logging.info(f"Received response from external copilot: {response_data[:100]}...")
return response_data
else:
error_message = f"External copilot at {url} returned an error: {response.status} {response.reason}"
logging.error(error_message)
return error_message # Return error as string
except urllib.error.HTTPError as e:
error_body = ""
try:
error_body = e.read().decode('utf-8', 'replace') # Added error decoding fallback
except Exception:
pass
error_message = f"HTTP Error {e.code} calling external copilot at {url}: {e.reason}. Response: {error_body}"
logging.error(error_message)
return error_message
except urllib.error.URLError as e:
error_message = f"URL Error calling external copilot at {url}: {e.reason}"
logging.error(error_message)
return error_message
except Exception as e:
error_message = f"An unexpected error occurred while calling external copilot at {url}: {str(e)}"
logging.error(error_message)
return error_message
def execute(self, function_name, **kwargs): def execute(self, function_name, **kwargs):
if function_name == "call_external_llm": if function_name == "call_external_llm":
return self.call_external_llm(kwargs.get("prompt"), kwargs.get("model"), kwargs.get("max_tokens")) model = kwargs.get("model", "mini") # Default from spec
max_tokens = kwargs.get("max_tokens", 16384) # Default from spec
return self.call_external_llm(kwargs.get("prompt"), model, max_tokens)
elif function_name == "call_external_copilot":
return self._call_external_copilot(kwargs.get("prompt"), kwargs.get("url"))
else: else:
error_message = f"Unknown function: {function_name}" error_message = f"Unknown function: {function_name}"
logging.error(error_message) logging.error(error_message)
return error_message
def call_external_llm(self, prompt, model="o1-mini", max_tokens=16384): def call_external_llm(self, prompt, model="mini", max_tokens=16384):
logging.info(f"Calling external model: {model}") logging.info(f"Calling external LLM model: {model} with max_tokens: {max_tokens}")
response = self.client.completions.create( try:
model=model, actual_model_name = model
prompt=prompt, if model == "mini":
max_tokens=max_tokens actual_model_name = "o1-mini"
) # Add mapping for "max" if its name for OpenAI API is different
token_amount = response.summary["total_tokens"] # elif model == "max":
logging.info("Response generated, {token_amount} tokens used.") # actual_model_name = "some-other-openai-model-name"
return response.choices[0].text
response = self.client.completions.create(
model=actual_model_name,
prompt=prompt,
max_tokens=max_tokens
)
tokens_used = "unknown" # Default if token info isn't where expected
if hasattr(response, 'summary') and isinstance(response.summary, dict) and "total_tokens" in response.summary:
tokens_used = response.summary["total_tokens"]
elif hasattr(response, 'usage') and hasattr(response.usage, 'total_tokens'):
tokens_used = response.usage.total_tokens
logging.info(f"LLM response generated, {tokens_used} tokens used.")
return response.choices[0].text
except Exception as e:
error_message = f"Error calling external LLM: {str(e)}"
logging.error(error_message)
return error_message # Return error as string