Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,14 @@ export LLM_API_KEY="your-api-key"
# Optional
export LLM_API_BASE="your-api-base-url" # if using a local model, e.g. Ollama, LMStudio
export PERPLEXITY_API_KEY="your-api-key" # for search capabilities
export STRIX_DISABLE_IMAGES="true" # disable image/vision features for non-vision LLMs
```

**Disabling Image Features**: If you're using an LLM that doesn't support images/vision (e.g., some local models), set `STRIX_DISABLE_IMAGES=true`. This will:
- Disable browser automation tools (which rely on screenshots)
- Skip adding screenshots to LLM messages
- Improve performance and reduce costs for non-vision models

[OpenAI's GPT-5](https://openai.com/api/) (`openai/gpt-5`) and [Anthropic's Claude Sonnet 4.5](https://claude.com/platform/api) (`anthropic/claude-sonnet-4-5`) are the recommended models for best results with Strix. We also support many [other options](https://docs.litellm.ai/docs/providers), including cloud and local models, though their performance and reliability may vary.

## 🤝 Contributing
Expand Down
8 changes: 7 additions & 1 deletion strix/llm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def __init__(
enable_prompt_caching: bool = True,
prompt_modules: list[str] | None = None,
timeout: int | None = None,
disable_images: bool | None = None,
):
self.model_name = model_name or os.getenv("STRIX_LLM", "openai/gpt-5")

Expand All @@ -17,4 +18,9 @@ def __init__(
self.enable_prompt_caching = enable_prompt_caching
self.prompt_modules = prompt_modules or []

self.timeout = timeout or int(os.getenv("LLM_TIMEOUT", "300"))
self.timeout = timeout or int(os.getenv("LLM_TIMEOUT", "600"))

if disable_images is None:
self.disable_images = os.getenv("STRIX_DISABLE_IMAGES", "false").lower() == "true"
else:
self.disable_images = disable_images
13 changes: 13 additions & 0 deletions strix/llm/memory_compressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import litellm

from strix.tools import is_images_disabled


logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -125,6 +127,17 @@ def _summarize_messages(


def _handle_images(messages: list[dict[str, Any]], max_images: int) -> None:
if is_images_disabled():
for msg in messages:
content = msg.get("content", [])
if isinstance(content, list):
msg["content"] = [
item
for item in content
if not (isinstance(item, dict) and item.get("type") == "image_url")
]
return

image_count = 0
for msg in reversed(messages):
content = msg.get("content", [])
Expand Down
13 changes: 11 additions & 2 deletions strix/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,16 @@

HAS_PERPLEXITY_API = bool(os.getenv("PERPLEXITY_API_KEY"))


def is_images_disabled() -> bool:
return os.getenv("STRIX_DISABLE_IMAGES", "false").lower() == "true"


if not SANDBOX_MODE:
from .agents_graph import * # noqa: F403
from .browser import * # noqa: F403

if not is_images_disabled():
from .browser import * # noqa: F403
from .file_edit import * # noqa: F403
from .finish import * # noqa: F403
from .notes import * # noqa: F403
Expand All @@ -39,7 +46,8 @@
if HAS_PERPLEXITY_API:
from .web_search import * # noqa: F403
else:
from .browser import * # noqa: F403
if not is_images_disabled():
from .browser import * # noqa: F403
from .file_edit import * # noqa: F403
from .notes import * # noqa: F403
from .proxy import * # noqa: F403
Expand All @@ -55,6 +63,7 @@
"get_tool_by_name",
"get_tool_names",
"get_tools_prompt",
"is_images_disabled",
"needs_agent_state",
"process_tool_invocations",
"register_tool",
Expand Down
25 changes: 15 additions & 10 deletions strix/tools/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,22 @@ def _update_tracer_with_result(
def _format_tool_result(tool_name: str, result: Any) -> tuple[str, list[dict[str, Any]]]:
images: list[dict[str, Any]] = []

screenshot_data = extract_screenshot_from_result(result)
if screenshot_data:
images.append(
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{screenshot_data}"},
}
)
result_str = remove_screenshot_from_result(result)
from strix.tools import is_images_disabled

if not is_images_disabled():
screenshot_data = extract_screenshot_from_result(result)
if screenshot_data:
images.append(
{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{screenshot_data}"},
}
)
result_str = remove_screenshot_from_result(result)
else:
result_str = result
else:
result_str = result
result_str = remove_screenshot_from_result(result) if isinstance(result, dict) else result

if result_str is None:
final_result_str = f"Tool {tool_name} executed successfully"
Expand Down
10 changes: 10 additions & 0 deletions strix/tools/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,18 @@ def should_execute_in_sandbox(tool_name: str) -> bool:


def get_tools_prompt() -> str:
try:
from strix.tools import is_images_disabled

images_disabled = is_images_disabled()
except ImportError:
images_disabled = False

tools_by_module: dict[str, list[dict[str, Any]]] = {}
for tool in tools:
if images_disabled and tool.get("module") == "browser":
continue

module = tool.get("module", "unknown")
if module not in tools_by_module:
tools_by_module[module] = []
Expand Down