Solana Agent Documentation

Welcome to Solana Agent’s documentation. Solana Agent enables you to build an AI business in three lines of code!

Getting Started

Installation

pip install solana-agent

Flows

In both flows of single and multiple agents - it is one user query to one agent using one or many tools (if needed).

An agent can have multiple tools and will choose the best ones to fulfill the user’s query.

Routing is determined by optimal domain expertise of the agent for the user’s query.

When the agent uses tools it feeds the tools output back to itself to generate the final response.

This is important as tools generally output unstructured and unformatted data that the agent needs to prepare for the user.

Keep this in mind while designing your agentic systems using Solana Agent.

                     Single Agent

   ┌────────┐        ┌─────────┐        ┌────────-┐
   │        │        │         │        │         │
   │        │        │         │        │         │
   │  User  │◄──────►│  Agent  │◄──────►│  Tools  │
   │        │        │         │        │         │
   │        │        │         │        │         │
   └────────┘        └─────────┘        └────────-┘





                     Multiple Agents

     ┌────────┐        ┌──────────┐        ┌─────────┐        ┌────────-┐
     │        │        │          │        │         │        │         │
     │        │        │          │        │         │        │         │
┌───►│  User  ├───────►│  Router  ├───────►│  Agent  │◄──────►│  Tools  │
│    │        │        │          │        │         │        │         │
│    │        │        │          │        │         │        │         │
│    └────────┘        └──────────┘        └────┬────┘        └────────-┘
│                                               │
│                                               │
│                                               │
│                                               │
└───────────────────────────────────────────────┘

Usage

Text/Text Streaming

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

async for response in solana_agent.process("user123", "What are the latest AI developments?"):
   print(response, end="")

Audio/Audio Streaming

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

audio_content = audio_file.read()

async for response in solana_agent.process("user123", audio_content, output_format="audio", audio_voice="nova", audio_input_format="webm", audio_output_format="aac"):
   print(response, end="")

Text/Audio Streaming

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

async for response in solana_agent.process("user123", "What is the latest news on Elon Musk?", output_format="audio", audio_voice="nova", audio_output_format="aac"):
   print(response, end="")

Audio/Text Streaming

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

audio_content = audio_file.read()

async for response in solana_agent.process("user123", audio_content, audio_input_format="aac"):
   print(response, end="")

Image/Text Streaming

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
            "name": "vision_expert",
            "instructions": "You are an expert at analyzing images and answering questions about them.",
            "specialization": "Image analysis",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

# Example with an image URL
image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"

# Example reading image bytes from a file
image_bytes = await image_file.read()

# You can mix URLs and bytes in the list
images_to_process = [
   image_url,
   image_bytes,
]

async for response in solana_agent.process("user123", "What is in this image? Describe the scene.", images=images_to_process):
   print(response, end="")

Structured Outputs

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
            "name": "researcher",
            "instructions": "You are a research expert.",
            "specialization": "Researcher",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

class ResearchProposal(BaseModel):
   title: str
   abstract: str
   key_points: list[str]

full_response = None
async for response in solana_agent.process("user123", "Research the life of Ben Franklin - the founding Father.", output_model=ResearchProposal):
   full_response = response

print(full_response.model_dump())

Command Line Interface (CLI)

Solana Agent includes a command-line interface (CLI) for text-based chat using a configuration file.

Ensure you have a valid configuration file (e.g., config.json) containing at least your OpenAI API key and agent definitions.

// config.json
{
   "openai": {
      "api_key": "your-openai-api-key"
   },
   "agents": [
      {
            "name": "default_agent",
            "instructions": "You are a helpful AI assistant.",
            "specialization": "general"
      }
   ]
}

Also ensure that you have pip install uv to call uvx.

uvx solana-agent [OPTIONS]

Options:

--user-id TEXT: The user ID for the conversation (default: cli_user).
--config TEXT: Path to the configuration JSON file (default: config.json).
--prompt TEXT: Optional system prompt override for the agent.
--help: Show help message and exit.

# Using default config.json and user_id
uvx solana-agent

# Specifying user ID and config path
uvx solana-agent --user-id my_cli_session --config ./my_agent_config.json

Optional Configurations

Business Alignment - Optional

config = {
   "business": {
      "mission": "To provide users with a one-stop shop for their queries.",
      "values": {
            "Friendliness": "Users must be treated fairly, openly, and with friendliness.",
            "Ethical": "Agents must use a strong ethical framework in their interactions with users.",
      },
      "goals": [
            "Empower users with great answers to their queries.",
      ],
      "voice": "The voice of the brand is that of a research business."
   },
}

Conversational History - Optional

config = {
   "mongo": {
      "connection_string": "your-mongo-connection-string",
      "database": "your-database-name",
   },
}

Conversational Memory - Optional

config = {
   "zep": {
      "api_key": "your-zep-api-key",
   },
}

Observability and Tracing - Optional

config = {
   "logfire": {
      "api_key": "your-logfire-write-token",
   },
}

Knowledge Base - Optional

The Knowledge Base (KB) is meant to store text values and/or small PDFs.

config = {
   "knowledge_base": {
      "pinecone": {
            "api_key": "your-pinecone-api-key",
            "index_name": "your-pinecone-index-name",
      }
   },
   "mongo": {
      "connection_string": "your-mongo-connection-string",
      "database": "your-database-name"
   },
}

Example for KB (text) - Optional

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "knowledge_base": {
      "pinecone": {
            "api_key": "your-pinecone-api-key",
            "index_name": "your-pinecone-index-name",
      }
   },
   "mongo": {
      "connection_string": "your-mongo-connection-string",
      "database": "your-database-name"
   },
   "agents": [
      {
            "name": "kb_expert",
            "instructions": "You answer questions based on the provided knowledge base documents.",
            "specialization": "Company Knowledge",
      }
   ]
}

solana_agent = SolanaAgent(config=config)

doc_text = "Solana Agent is a Python framework for building multi-agent AI systems."
doc_metadata = {
   "source": "internal_docs",
   "version": "1.0",
   "tags": ["framework", "python", "ai"]
}
await solana_agent.kb_add_document(text=doc_text, metadata=doc_metadata)

async for response in solana_agent.process("user123", "What is Solana Agent?"):
   print(response, end="")

Example for KB (pdf) - Optional

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "knowledge_base": {
      "pinecone": {
            "api_key": "your-pinecone-api-key",
            "index_name": "your-pinecone-index-name",
      }
   },
   "mongo": {
      "connection_string": "your-mongo-connection-string",
      "database": "your-database-name"
   },
   "agents": [
      {
            "name": "kb_expert",
            "instructions": "You answer questions based on the provided knowledge base documents.",
            "specialization": "Company Knowledge",
      }
   ]
}

solana_agent = SolanaAgent(config=config)

pdf_bytes = await pdf_file.read()

pdf_metadata = {
   "source": "annual_report_2024.pdf",
   "year": 2024,
   "tags": ["finance", "report"]
}

await solana_agent.kb_add_pdf_document(
   pdf_data=pdf_bytes,
   metadata=pdf_metadata,
)

async for response in solana_agent.process("user123", "Summarize the annual report for 2024."):
   print(response, end="")

Guardrails - Optional

Guardrails allow you to process and potentially modify user input before it reaches the agent (Input Guardrails) and agent output before it’s sent back to the user (Output Guardrails). This is useful for implementing safety checks, content moderation, data sanitization, or custom transformations.

Guardrails don’t apply to structured outputs.

Solana Agent provides a built-in PII scrubber based on scrubadub.

from solana_agent import SolanaAgent

config = {
   "guardrails": {
      "input": [
            # Example using a custom input guardrail
            {
               "class": "MyInputGuardrail",
               "config": {"setting1": "value1"}
            },
            # Example using the built-in PII guardrail for input
            {
               "class": "solana_agent.guardrails.pii.PII",
               "config": {
                  "locale": "en_GB", # Optional: Specify locale (default: en_US)
                  "replacement": "[REDACTED]" # Optional: Custom replacement format
               }
            }
      ],
      "output": [
            # Example using a custom output guardrail
            {
               "class": "MyOutputGuardrail",
               "config": {"filter_level": "high"}
            },
            # Example using the built-in PII guardrail for output (with defaults)
            {
               "class": "solana_agent.guardrails.pii.PII"
               # No config needed to use defaults
            }
      ]
   },
}

Example Custom Guardrails - Optional

Guardrails don’t apply to structured outputs.

from solana_agent import InputGuardrail, OutputGuardrail
import logging

logger = logging.getLogger(__name__)

class MyInputGuardrail(InputGuardrail):
   def __init__(self, config=None):
      super().__init__(config)
      self.setting1 = self.config.get("setting1", "default_value")
      logger.info(f"MyInputGuardrail initialized with setting1: {self.setting1}")

   async def process(self, text: str) -> str:
      # Example: Convert input to lowercase
      processed_text = text.lower()
      logger.debug(f"Input Guardrail processed: {text} -> {processed_text}")
      return processed_text

class MyOutputGuardrail(OutputGuardrail):
   def __init__(self, config=None):
      super().__init__(config)
      self.filter_level = self.config.get("filter_level", "low")
      logger.info(f"MyOutputGuardrail initialized with filter_level: {self.filter_level}")

   async def process(self, text: str) -> str:
      # Example: Basic profanity filtering (replace with a real library)
      if self.filter_level == "high" and "badword" in text:
            processed_text = text.replace("badword", "*******")
            logger.warning(f"Output Guardrail filtered content.")
            return processed_text
      logger.debug("Output Guardrail passed text through.")
      return text

Tools

Solana Agent Kit

pip install sakit

Inline Tool Example

from solana_agent import SolanaAgent, Tool

class TestTool(Tool):
   def __init__(self):
      # your tool initialization - delete the following pass
      pass

   @property
   def name(self) -> str:
      return "test_function"

   @property
   def description(self) -> str:
      return "Test function for Solana Agent"

   def configure(self, config: Dict[str, Any]) -> None:
      """Configure with all possible API key locations."""
      super().configure(config)

      # read your config values - delete the following pass
      pass

   def get_schema(self) -> Dict[str, Any]:
      # this is an example schema
      return {
         "type": "object",
         "properties": {
            "query": {"type": "string", "description": "Search query text"},
            "user_id": {"type": "string", "description": "User ID for the search session"}
         },
         "required": ["query", "user_id"],
         "additionalProperties": False,
      }

   async def execute(self, **params) -> Dict[str, Any]:
      try:
         # your tool logic
         result = "Your tool results"

         return {
            "status": "success",
            "result": result,
         }
      except Exception as e:
         return {
            "status": "error",
            "message": f"Error: {str(e)}",
         }

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

test_tool = TestTool()

solana_agent.register_tool(test_tool)

async for response in solana_agent.process("user123", "What are the latest AI developments?"):
   print(response, end="")

Advanced Configuration

Prompt Injection at Runtime Example

Useful for Knowledge Base answers and FAQs.

from solana_agent import SolanaAgent

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

solana_agent = SolanaAgent(config=config)

async for response in solana_agent.process("user123", "What are the latest AI developments?", "Always end your sentences with eh?"):
   print(response, end="")

Custom Routing Example

from solana_agent import SolanaAgent
from solana_agent.interfaces.services.routing import RoutingService as RoutingServiceInterface

config = {
   "openai": {
      "api_key": "your-openai-api-key",
   },
   "agents": [
      {
         "name": "research_specialist",
         "instructions": "You are an expert researcher who synthesizes complex information clearly.",
         "specialization": "Research and knowledge synthesis",
      },
      {
         "name": "customer_support",
         "instructions": "You provide friendly, helpful customer support responses.",
         "specialization": "Customer inquiries",
      }
   ],
}

class Router(RoutingServiceInterface)
   def __init__(self):
      # your router initialization - delete the following pass
      pass

   async def route_query(self, query: str) -> str:
      # a simple example to route always to customer_support agent
      return "customer_support"

router = Router()

solana_agent = SolanaAgent(config=config)

async for response in solana_agent.process("user123", "What are the latest AI developments?", router=router):
   print(response, end="")

API Reference

Check out the API Reference for detailed documentation of all modules and classes.