diff --git a/README.md b/README.md
index 956a697..a64582d 100644
--- a/README.md
+++ b/README.md
@@ -1,179 +1,137 @@
+
+

+
+
Build, orchestrate and scale agents impossibly fast
+
+ [](https://badge.fury.io/py/impossibly)
+ [](https://www.python.org/downloads/)
+ [](https://github.com/jacksongrove/impossibly)
+ [](https://opensource.org/licenses/MIT)
+ [](https://impossibly.dev)
+
+ [**Documentation**](https://impossibly.dev) | [**Examples**](examples/) | [**Discord**](https://discord.gg/impossibly) | [**GitHub**](https://github.com/jacksongrove/impossibly)
+
+
+---
+
# Impossibly
-Impossibly is an agentic orchestration framework for rapidly building agentic architectures in Python. It accelerates agentic development, empowering developers to craft architectures that enable LLMs to excel in higher-order tasks like idea generation and critical thinking.
-This library is designed to be used as a backend for AI apps and automations, providing support for all major LLM providers and locally-hosted model endpoints.
+Impossibly is a lean Python library for building and orchestrating production AI agents. Declare tools as plain Python functions, keep a tiny dependency footprint, and skip the boilerplate—the stable core ships with first-class multimodal support and built-in tracing so you can ship and debug impossibly fast.
-# Getting Started
-## Installation
+🎯 Why Impossibly?
+---
+1. Stable core without surprise breakages.
+2. Ultra-lean footprint. No dependency bloat.
+3. Declare tools as plain Python functions.
+4. Multi-modal out of the box.
+5. Powerful agents without the boilerplate. It's time to build impossibly fast.
-Install the base package:
-```bash
-pip install impossibly
-```
-
-Or install with specific integrations:
-```bash
-# Minimal installations with specific providers
-pip install "impossibly[openai]" # Only OpenAI support
-pip install "impossibly[anthropic]" # Only Anthropic support
-pip install "impossibly[all]" # All LLM integrations
-
-# For testing and development
-pip install "impossibly[test]" # All LLM integrations + testing tools
-pip install "impossibly[dev]" # All LLM integrations + testing + dev tools
-```
+## 🚀 Quick Start
-## Imports
-Import the components you need:
```python
from impossibly import Agent, Graph, START, END
-```
-
-## Setting Up Environment Variables
-1. Copy the `.env.template` file to a new file named `.env`:
- ```bash
- cp .env.template .env
- ```
-
-2. Fill in your API keys and configurations in the `.env` file:
- ```
- OPENAI_API_KEY=your_actual_api_key_here
- ANTHROPIC_API_KEY=your_anthropic_api_key_here
- ```
-3. The library will automatically load these variables when needed. At minimum, you'll need the API key for your preferred LLM provider.
-
-## Initalize Clients for LLM APIs
-Done in the format standard to your API.
-
-## Create Agents
-Initalize the agents you'd like to call with a simple schema:
-```
+# Create an Impossibly agent
agent = Agent(
- client=client,
- model="gpt-4o",
- name="Agent",
- system_prompt="You are a friendly assistant.",
- description="This agent is an example agent."
- )
-```
-
-## Define how agents are executed with a Graph
-Graphs connect agents together using nodes and edges, routing the execution flow and all needed information through the graph. Each node represents an agent and each edge represents a conditional under which that agent is called. This conditional can be defined in natural language for each agent, within its `system_prompt`.
-
-In the case of multiple edges branching from one node, agents can understand their routing options using the `description` field of connecting nodes.
+ client=openai_client,
+ model="gpt-4o",
+ system_prompt="You are a helpful assistant",
+ tools=[web_search, calculator, database]
+)
-Every graph accepts user input at the `START` and returns a response to the user at the `END`.
-
-With this basic understanding, a graph can be created in just a few lines.
-```
+# Build a reasoning workflow
graph = Graph()
-
-graph.add_node(agent)
-graph.add_node(summarizer_agent)
-
graph.add_edge(START, agent)
-graph.add_edge(agent, summarizer_agent)
-graph.add_edge(summarizer_agent, END)
-```
+graph.add_edge(agent, END)
-## Run your Graph
-You're done! Prompt your agentic architecture.
-```
-graph.invoke("Hello there!")
+# Execute with autonomous reasoning
+result = graph.invoke("Analyze current market trends and provide strategic recommendations")
```
-# Development
-## Running Tests
+## ✨ Core Features
-To run the tests, first install the package with test dependencies:
+### One-line Agent Instantiation
+Define agents and the tools available to them in a single object instantiation:
+- **Native Multi-modal Support**: Agents can work with both text and images straight out of the box
+- **Native Routing**: Under-the-hood prompt-injection to ensure intelligent decision making and routing
+- **Custom Functions:**
+Build functions simply with Python, then connect them as tools to your agents
-```bash
-# Install with test dependencies
-pip install -e ".[test]"
-```
-
-Then run the tests using the CLI command that gets installed with the package:
-
-```bash
-# Run all tests
-impossibly run
-
-# Run just feature tests
-impossibly run --path features/
+### Graph-Based Orchestration
+Agents connected with a visual and intuitive workflow design:
+- **Conditional Logic**: Route based on agent decisions
+- **Monitoring**: Track agent performance and decisions
-# Run tests in Docker
-impossibly run --docker
-
-# Get help
-impossibly run --help
-```
+### Tool Integration
+Seamless connection to external systems and data with native Python functions:
+- **User-Created Tools**: Connect to any API, service, database and more with self-defined Python functions
+- **Own Your Tools**: Core updates won't break your functions—full control and easy fixes
+- **Custom Tools**: Build domain-specific capabilities with Python
-See [tests/README.md](tests/README.md) for more details on the testing framework and available options.
+### Designed for Multi-Agent Architectures
+Specialized agents working together on complex tasks:
+- **Role-Based Design**: Each agent has a specific expertise
+- **Coordinated Workflows**: Agents pass work between each other
+- **Quality Assurance**: Multiple agents validate and improve results
+- **Scalable Architecture**: Add agents as complexity grows
-## Local Development and Running Examples
+## 📚 Examples
-If you want to develop locally and test the examples, follow these steps:
+Explore practical implementations in the `/examples` directory:
-### Building the Package Locally
+- **SQL Agent**: Autonomous database analysis with iterative reasoning
+- **Research Agent**: Multi-step research with source validation
+- **Conversational Agents**: Context-aware dialogue systems
+- **Tool Agents**: Specialized agents for specific tasks
+- **Mixture of Experts**: Dynamic agent selection based on task requirements
-1. Clone the repository:
- ```bash
- git clone https://github.com/jacksongrove/impossibly.git
- cd impossibly
- ```
+## 🛠 Installation
-2. Create and activate a virtual environment (optional but recommended):
- ```bash
- python -m venv .venv
- source .venv/bin/activate # On Windows: .venv\Scripts\activate
- ```
-
-3. Install development dependencies:
- ```bash
- pip install -e ".[dev]"
- ```
+```bash
+# Base installation
+pip install impossibly
-4. Build the package locally:
- ```bash
- python -m build
- ```
- This will create distributions in the `dist/` directory.
+# With specific LLM providers only
+pip install "impossibly[openai]"
+pip install "impossibly[anthropic]"
+pip install "impossibly[all]"
-### Installing the Local Build to Run Examples
+# For development & contributions
+pip install "impossibly[dev]"
+```
-There are two approaches to use your local build:
+## 🧪 Testing
-#### Option 1: Install in Development Mode (Recommended)
+```bash
+# Install with test dependencies
+pip install -e ".[test]"
-This allows changes to the source code to be immediately reflected without reinstalling:
+# Run test suite
+impossibly run
-```bash
-pip install -e .
+# Run in Docker
+impossibly run --docker
```
-#### Option 2: Install the Built Wheel
-
-If you want to test the exact distribution that would be uploaded to PyPI:
+## 📖 Documentation
-```bash
-pip install dist/impossibly-0.1.0-py3-none-any.whl
-```
+Visit **[impossibly.dev](https://impossibly.dev)** for:
+- Complete API documentation
+- Agentic AI tutorials and guides
+- Framework comparisons (LangGraph, CrewAI, AutoGen)
+- Real-world case studies
+- Best practices for building reliable agents
-### Running Examples
+## 🤝 Community
-Once you've installed the package using either method, you can run the examples:
+- **Discord**: [Join our community](https://discord.gg/impossibly)
+- **GitHub**: [Contribute to the project](https://github.com/jacksongrove/impossibly)
+- **Documentation**: [Learn more at impossibly.dev](https://impossibly.dev)
-```bash
-# Set up your environment variables first
-cp .env.template .env
-# Edit .env to add your API keys
+## 📄 License
-# Run an example
-python examples/image_agent/image_agent.py
+MIT License - see [LICENSE](LICENSE) for details.
-# Or try another example
-python examples/web_search_agent/web_search_agent.py
-```
+---
-Make sure the required dependencies for each example are installed and the necessary API keys are in your `.env` file.
+**Ready to build, orchestrate and scale AI agents impossibly fast?** Start with the [documentation](https://impossibly.dev) and join the community pushing the boundaries of autonomous AI.
diff --git a/pyproject.toml b/pyproject.toml
index bbd4d76..20ee49a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
[project]
name = "impossibly"
-version = "0.1.0"
-description = "An agentic architecture for idea generation & critical thinking"
+version = "0.1.1"
+description = "Build, orchestrate and scale agents impossibly fast"
readme = "README.md"
requires-python = ">=3.9"
license = "MIT"
diff --git a/src/impossibly/graph.py b/src/impossibly/graph.py
index 37d6586..10502d3 100644
--- a/src/impossibly/graph.py
+++ b/src/impossibly/graph.py
@@ -98,10 +98,9 @@ def add_edge(self, node1: Union[Agent, List[Agent]], node2: Union[Agent, List[Ag
if n1 not in self.edges:
raise ValueError(f"{n1} is not a valid node in the graph. Please add it first.")
for n2 in node2:
- if n1 is not n2:
- if n2 not in self.edges:
- raise ValueError(f"{n2} is not a valid node in the graph. Please add it first.")
- self.edges[n1].append(n2)
+ if n2 not in self.edges and n2 != END:
+ raise ValueError(f"{n2} is not a valid node in the graph. Please add it first.")
+ self.edges[n1].append(n2)
def invoke(self, user_prompt: str = "", files: list[str] = [], show_thinking: bool = False) -> str:
@@ -141,6 +140,7 @@ async def _invoke_async(self, user_prompt: str = "", files: list[str] = [], show
# Execute each node in the graph until END is reached
curr_node = self.edges[START][0]
prompt = user_prompt
+ original_prompt = user_prompt # Store original task for self-loops
author = 'user'
selected_files = files
while curr_node != END:
@@ -155,6 +155,7 @@ async def _invoke_async(self, user_prompt: str = "", files: list[str] = [], show
i = 0
if len(self.edges[curr_node]) > 1:
route_idx, output = self._get_route(curr_node, output)
+ i = route_idx
# Route files intended to be passed
selected_files, output = self._get_files(files, output)
@@ -167,9 +168,26 @@ async def _invoke_async(self, user_prompt: str = "", files: list[str] = [], show
await global_memory.add(curr_node, self.edges[curr_node][i], output)
# Continue executing through the graph until END is reached
- curr_node = self.edges[curr_node][i]
- prompt = output
- author = 'user'
+ next_node = self.edges[curr_node][i]
+
+ # Handle self-loops: reset conversation to maintain tool-calling behavior
+ if next_node == curr_node:
+ # Self-loop: Reset message history and use fresh context
+ if hasattr(curr_node, 'client') and hasattr(curr_node.client, 'messages') and curr_node.client.messages:
+ # Keep only the system message (first message)
+ system_msg = curr_node.client.messages[0]
+ curr_node.client.messages = [system_msg]
+
+ # Create fresh prompt with task context and progress
+ cleaned_output = output.replace(f'\\\\{curr_node.name}\\\\', '').strip()
+ prompt = f"{original_prompt}\n\nProgress so far: {cleaned_output}\n\nContinue with your task."
+ author = 'user'
+ else:
+ # Different agent: pass the full output
+ prompt = output
+ author = 'user'
+
+ curr_node = next_node
return None
@@ -191,21 +209,27 @@ def _get_route(self, node: Agent, output: str) -> tuple[int, str]:
- str: The output string with the routing command removed.
'''
options = self.edges[node]
- # Regex from back of list to find agent names in delimited text
+ # Regex to find agent names - handle both single and double backslashes
+ # Try double backslashes first, then single backslashes
match = re.search(r'(?<=\\\\)(.*?)(?=\\\\)', output, re.DOTALL)
+ if not match:
+ match = re.search(r'(?<=\\)(.*?)(?=\\)', output, re.DOTALL)
+
if match:
- # Remove the last instance of the command from the output
- output = re.sub(r'\\\\' + re.escape(match.group(1)) + r'\\\\', '', output, count=1)
+ # Remove the routing command from the output (handle both patterns)
+ command = match.group(1)
+ output = re.sub(r'\\\\?' + re.escape(command) + r'\\\\?', '', output, count=1)
# Get index of the desired agent in the node's edge list
# Check if the match is the END command
- if match.group(1) == 'END':
+ if command == 'END':
return options.index(END), output
else:
for i, option in enumerate(options):
- if option.name == match.group(1):
+ if option.name == command:
return i, output
- print("No route found. Choosing random route.")
+
+ # No route found, choose default route
return 0, output