feat: add ephemeral prefill messages and system prompt loading
- Implemented functionality to load ephemeral prefill messages from a JSON file, enhancing few-shot priming capabilities for the agent. - Introduced a mechanism to load an ephemeral system prompt from environment variables or configuration files, ensuring dynamic prompt adjustments at API-call time. - Updated the CLI and agent initialization to utilize the new prefill messages and system prompt, improving the overall interaction experience. - Enhanced configuration options with new environment variables for prefill messages and system prompts, allowing for greater customization without persistence.
This commit is contained in:
@@ -412,9 +412,17 @@ class ShellFileOperations(FileOperations):
|
||||
# Still try to read, but warn
|
||||
pass
|
||||
|
||||
# Check if it's an image - return base64
|
||||
# Images are never inlined — redirect to the vision tool
|
||||
if self._is_image(path):
|
||||
return self._read_image(path)
|
||||
return ReadResult(
|
||||
is_image=True,
|
||||
is_binary=True,
|
||||
file_size=file_size,
|
||||
hint=(
|
||||
"Image file detected. Automatically redirected to vision_analyze tool. "
|
||||
"Use vision_analyze with this file path to inspect the image contents."
|
||||
),
|
||||
)
|
||||
|
||||
# Read a sample to check for binary content
|
||||
sample_cmd = f"head -c 1000 {self._escape_shell_arg(path)} 2>/dev/null"
|
||||
@@ -457,6 +465,10 @@ class ShellFileOperations(FileOperations):
|
||||
hint=hint
|
||||
)
|
||||
|
||||
# Images larger than this are too expensive to inline as base64 in the
|
||||
# conversation context. Return metadata only and suggest vision_analyze.
|
||||
MAX_IMAGE_BYTES = 512 * 1024 # 512 KB
|
||||
|
||||
def _read_image(self, path: str) -> ReadResult:
|
||||
"""Read an image file, returning base64 content."""
|
||||
# Get file size
|
||||
@@ -467,6 +479,17 @@ class ShellFileOperations(FileOperations):
|
||||
except ValueError:
|
||||
file_size = 0
|
||||
|
||||
if file_size > self.MAX_IMAGE_BYTES:
|
||||
return ReadResult(
|
||||
is_image=True,
|
||||
is_binary=True,
|
||||
file_size=file_size,
|
||||
hint=(
|
||||
f"Image is too large to inline ({file_size:,} bytes). "
|
||||
"Use vision_analyze to inspect the image, or reference it by path."
|
||||
),
|
||||
)
|
||||
|
||||
# Get base64 content
|
||||
b64_cmd = f"base64 -w 0 {self._escape_shell_arg(path)} 2>/dev/null"
|
||||
b64_result = self._exec(b64_cmd, timeout=30)
|
||||
|
||||
@@ -199,7 +199,7 @@ def _check_file_reqs():
|
||||
|
||||
READ_FILE_SCHEMA = {
|
||||
"name": "read_file",
|
||||
"description": "Read a file with line numbers and pagination. Use this instead of cat/head/tail in terminal. Output format: 'LINE_NUM|CONTENT'. Suggests similar filenames if not found. Images (png/jpg/gif/webp) returned as base64. Use offset and limit for large files.",
|
||||
"description": "Read a text file with line numbers and pagination. Use this instead of cat/head/tail in terminal. Output format: 'LINE_NUM|CONTENT'. Suggests similar filenames if not found. Use offset and limit for large files. NOTE: Cannot read images or binary files — use vision_analyze for images.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -159,7 +159,7 @@ async def process_content_with_llm(
|
||||
return processed_content
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Error processing content with LLM: %s", e)
|
||||
logger.debug("Error processing content with LLM: %s", e)
|
||||
return f"[Failed to process content: {str(e)[:100]}. Content size: {len(content):,} chars]"
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ async def _process_large_content_chunked(
|
||||
summaries.append(f"## Section {chunk_idx + 1}\n{summary}")
|
||||
|
||||
if not summaries:
|
||||
logger.error("All chunk summarizations failed")
|
||||
logger.debug("All chunk summarizations failed")
|
||||
return "[Failed to process large content: all chunk summarizations failed]"
|
||||
|
||||
logger.info("Got %d/%d chunk summaries", len(summaries), len(chunks))
|
||||
@@ -532,7 +532,7 @@ def web_search_tool(query: str, limit: int = 5) -> str:
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error searching web: {str(e)}"
|
||||
logger.error("%s", error_msg)
|
||||
logger.debug("%s", error_msg)
|
||||
|
||||
debug_call_data["error"] = error_msg
|
||||
_debug.log_call("web_search_tool", debug_call_data)
|
||||
@@ -673,7 +673,7 @@ async def web_extract_tool(
|
||||
})
|
||||
|
||||
except Exception as scrape_err:
|
||||
logger.error("Error scraping %s: %s", url, scrape_err)
|
||||
logger.debug("Scrape failed for %s: %s", url, scrape_err)
|
||||
results.append({
|
||||
"url": url,
|
||||
"title": "",
|
||||
@@ -799,7 +799,7 @@ async def web_extract_tool(
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error extracting content: {str(e)}"
|
||||
logger.error("%s", error_msg)
|
||||
logger.debug("%s", error_msg)
|
||||
|
||||
debug_call_data["error"] = error_msg
|
||||
_debug.log_call("web_extract_tool", debug_call_data)
|
||||
@@ -892,7 +892,7 @@ async def web_crawl_tool(
|
||||
**crawl_params
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Crawl API call failed: %s", e)
|
||||
logger.debug("Crawl API call failed: %s", e)
|
||||
raise
|
||||
|
||||
pages: List[Dict[str, Any]] = []
|
||||
@@ -1092,7 +1092,7 @@ async def web_crawl_tool(
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Error crawling website: {str(e)}"
|
||||
logger.error("%s", error_msg)
|
||||
logger.debug("%s", error_msg)
|
||||
|
||||
debug_call_data["error"] = error_msg
|
||||
_debug.log_call("web_crawl_tool", debug_call_data)
|
||||
@@ -1227,7 +1227,7 @@ WEB_SEARCH_SCHEMA = {
|
||||
|
||||
WEB_EXTRACT_SCHEMA = {
|
||||
"name": "web_extract",
|
||||
"description": "Extract content from web page URLs. Pages under 5000 chars return raw content; larger pages are LLM-summarized and capped at ~5000 chars per page. Pages over 2M chars are refused. Use browser tools only when pages require interaction or dynamic content.",
|
||||
"description": "Extract content from web page URLs. Returns page content in markdown format. Pages under 5000 chars return full markdown; larger pages are LLM-summarized and capped at ~5000 chars per page. Pages over 2M chars are refused. If a URL fails or times out, use the browser tool to access it instead.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
Reference in New Issue
Block a user