Future enhancements section
This commit is contained in:
parent
ee5d70c4c8
commit
a8f6b10bc9
@ -2,5 +2,5 @@
|
|||||||
showErrorDetails = "none"
|
showErrorDetails = "none"
|
||||||
|
|
||||||
[theme]
|
[theme]
|
||||||
primaryColor = "#FF69B4"
|
primaryColor = "#EB2D8C"
|
||||||
base="dark"
|
base="dark"
|
||||||
13
README.md
13
README.md
@ -134,16 +134,21 @@ There are a good amount of steps for the setup but it goes quick!
|
|||||||
- [Learn more about V4](iterations/v4-streamlit-ui-overhaul/README.md)
|
- [Learn more about V4](iterations/v4-streamlit-ui-overhaul/README.md)
|
||||||
|
|
||||||
### Future Iterations
|
### Future Iterations
|
||||||
- V5: Self-Feedback Loop - Automated validation and error correction
|
- V5: Multi-Agent Coding Workflow - Specialized agents for different parts of the agent creation process
|
||||||
- V6: Tool Library Integration - Pre-built external tool incorporation
|
- V6: Tool Library and Example Integration - Pre-built external tool and agent examples incorporation
|
||||||
- V7: Multi-Framework Support - Framework-agnostic agent generation
|
- V7: LangGraph Documentation - Allow Archon to build Pydantic AI AND LangGraph agents
|
||||||
- V8: Autonomous Framework Learning - Self-updating framework adapters
|
- V8: Self-Feedback Loop - Automated validation and error correction
|
||||||
|
- V9: Multi-Framework Support - Framework-agnostic agent generation
|
||||||
|
- V10: Autonomous Framework Learning - Self-updating framework adapters
|
||||||
|
- V11: Advanced RAG Techniques - Enhanced retrieval and incorporation of framework documentation
|
||||||
|
- V12: MCP Agent Marketplace - Integrating Archon agents as MCP servers and publishing to marketplaces
|
||||||
|
|
||||||
### Future Integrations
|
### Future Integrations
|
||||||
- LangSmith
|
- LangSmith
|
||||||
- MCP marketplace
|
- MCP marketplace
|
||||||
- Other frameworks besides Pydantic AI
|
- Other frameworks besides Pydantic AI
|
||||||
- Other vector databases besides Supabase
|
- Other vector databases besides Supabase
|
||||||
|
- [Local AI package](https://github.com/coleam00/local-ai-packaged) for the agent environment
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
|||||||
802
future_enhancements.py
Normal file
802
future_enhancements.py
Normal file
@ -0,0 +1,802 @@
|
|||||||
|
import streamlit as st
|
||||||
|
|
||||||
|
def future_enhancements_tab():
|
||||||
|
# Display the future enhancements and integrations interface
|
||||||
|
st.write("## Future Enhancements")
|
||||||
|
|
||||||
|
st.write("Explore what's coming next for Archon - from specialized multi-agent workflows to autonomous framework learning.")
|
||||||
|
|
||||||
|
# Future Iterations section
|
||||||
|
st.write("### Future Iterations")
|
||||||
|
|
||||||
|
# V5: Multi-Agent Coding Workflow
|
||||||
|
with st.expander("V5: Multi-Agent Coding Workflow"):
|
||||||
|
st.write("Specialized agents for different parts of the agent creation process")
|
||||||
|
|
||||||
|
# Create a visual representation of multi-agent workflow
|
||||||
|
st.write("#### Multi-Agent Coding Architecture")
|
||||||
|
|
||||||
|
# Describe the parallel architecture
|
||||||
|
st.markdown("""
|
||||||
|
The V5 architecture introduces specialized parallel agents that work simultaneously on different aspects of agent creation:
|
||||||
|
|
||||||
|
1. **Reasoner Agent**: Analyzes requirements and plans the overall agent architecture
|
||||||
|
2. **Parallel Coding Agents**:
|
||||||
|
- **Prompt Engineering Agent**: Designs optimal prompts for the agent
|
||||||
|
- **Tool Definition Agent**: Creates tool specifications and interfaces
|
||||||
|
- **Dependencies Agent**: Identifies required libraries and dependencies
|
||||||
|
- **Model Selection Agent**: Determines the best model configuration
|
||||||
|
3. **Final Coding Agent**: Integrates all components into a cohesive agent
|
||||||
|
4. **Human-in-the-Loop**: Iterative refinement with the final coding agent
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Display parallel agents
|
||||||
|
st.write("#### Parallel Coding Agents")
|
||||||
|
|
||||||
|
col1, col2, col3, col4 = st.columns(4)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
st.info("**Prompt Engineering Agent**\n\nDesigns optimal prompts for different agent scenarios")
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
st.success("**Tool Definition Agent**\n\nCreates tool specifications and interfaces")
|
||||||
|
|
||||||
|
with col3:
|
||||||
|
st.warning("**Dependencies Agent**\n\nIdentifies required libraries and dependencies")
|
||||||
|
|
||||||
|
with col4:
|
||||||
|
st.error("**Model Selection Agent**\n\nDetermines the best model configuration")
|
||||||
|
|
||||||
|
# Updated flow chart visualization with better colors for ovals
|
||||||
|
st.graphviz_chart('''
|
||||||
|
digraph {
|
||||||
|
rankdir=LR;
|
||||||
|
node [shape=box, style=filled, color=lightblue];
|
||||||
|
|
||||||
|
User [label="User Request", shape=ellipse, style=filled, color=purple, fontcolor=black];
|
||||||
|
Reasoner [label="Reasoner\nAgent"];
|
||||||
|
|
||||||
|
subgraph cluster_parallel {
|
||||||
|
label = "Parallel Coding Agents";
|
||||||
|
color = lightgrey;
|
||||||
|
style = filled;
|
||||||
|
|
||||||
|
Prompt [label="Prompt\nEngineering\nAgent", color=lightskyblue];
|
||||||
|
Tools [label="Tool\nDefinition\nAgent", color=green];
|
||||||
|
Dependencies [label="Dependencies\nAgent", color=yellow];
|
||||||
|
Model [label="Model\nSelection\nAgent", color=pink];
|
||||||
|
}
|
||||||
|
|
||||||
|
Final [label="Final\nCoding\nAgent"];
|
||||||
|
Human [label="Human-in-the-Loop\nIteration", shape=ellipse, style=filled, color=orange, fontcolor=black];
|
||||||
|
|
||||||
|
User -> Reasoner;
|
||||||
|
Reasoner -> Prompt;
|
||||||
|
Reasoner -> Tools;
|
||||||
|
Reasoner -> Dependencies;
|
||||||
|
Reasoner -> Model;
|
||||||
|
|
||||||
|
Prompt -> Final;
|
||||||
|
Tools -> Final;
|
||||||
|
Dependencies -> Final;
|
||||||
|
Model -> Final;
|
||||||
|
|
||||||
|
Final -> Human;
|
||||||
|
Human -> Final [label="Feedback Loop", color=red, constraint=false];
|
||||||
|
}
|
||||||
|
''')
|
||||||
|
|
||||||
|
st.write("#### Benefits of Parallel Agent Architecture")
|
||||||
|
st.markdown("""
|
||||||
|
- **Specialization**: Each agent focuses on its area of expertise
|
||||||
|
- **Efficiency**: Parallel processing reduces overall development time
|
||||||
|
- **Quality**: Specialized agents produce higher quality components
|
||||||
|
- **Flexibility**: Easy to add new specialized agents as needed
|
||||||
|
- **Scalability**: Architecture can handle complex agent requirements
|
||||||
|
""")
|
||||||
|
|
||||||
|
# V6: Tool Library and Example Integration
|
||||||
|
with st.expander("V6: Tool Library and Example Integration"):
|
||||||
|
st.write("Pre-built external tool and agent examples incorporation")
|
||||||
|
st.write("""
|
||||||
|
With pre-built tools, the agent can pull full functions from the tool library so it doesn't have to
|
||||||
|
create them from scratch. On top of that, pre-built agents will give Archon a starting point
|
||||||
|
so it doesn't have to build the agent structure from scratch either.
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.write("#### Example Integration Configuration")
|
||||||
|
|
||||||
|
# Add tabs for different aspects of V6
|
||||||
|
tool_tab, example_tab = st.tabs(["Tool Library", "Example Agents"])
|
||||||
|
|
||||||
|
with tool_tab:
|
||||||
|
st.write("##### Example Tool Library Config (could be a RAG implementation too, still deciding)")
|
||||||
|
|
||||||
|
sample_config = """
|
||||||
|
{
|
||||||
|
"tool_library": {
|
||||||
|
"web_tools": {
|
||||||
|
"web_search": {
|
||||||
|
"type": "search_engine",
|
||||||
|
"api_key_env": "SEARCH_API_KEY",
|
||||||
|
"description": "Search the web for information"
|
||||||
|
},
|
||||||
|
"web_browser": {
|
||||||
|
"type": "browser",
|
||||||
|
"description": "Navigate web pages and extract content"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data_tools": {
|
||||||
|
"database_query": {
|
||||||
|
"type": "sql_executor",
|
||||||
|
"description": "Execute SQL queries against databases"
|
||||||
|
},
|
||||||
|
"data_analysis": {
|
||||||
|
"type": "pandas_processor",
|
||||||
|
"description": "Analyze data using pandas"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ai_service_tools": {
|
||||||
|
"image_generation": {
|
||||||
|
"type": "text_to_image",
|
||||||
|
"api_key_env": "IMAGE_GEN_API_KEY",
|
||||||
|
"description": "Generate images from text descriptions"
|
||||||
|
},
|
||||||
|
"text_to_speech": {
|
||||||
|
"type": "tts_converter",
|
||||||
|
"api_key_env": "TTS_API_KEY",
|
||||||
|
"description": "Convert text to spoken audio"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
st.code(sample_config, language="json")
|
||||||
|
|
||||||
|
st.write("##### Pydantic AI Tool Definition Example")
|
||||||
|
|
||||||
|
pydantic_tool_example = """
|
||||||
|
from pydantic_ai import Agent, RunContext, Tool
|
||||||
|
from typing import Union, List, Dict, Any
|
||||||
|
import requests
|
||||||
|
|
||||||
|
@agent.tool
|
||||||
|
async def weather_tool(ctx: RunContext[Dict[str, Any]], location: str) -> str:
|
||||||
|
\"\"\"Get current weather information for a location.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
location: The city and state/country (e.g., 'San Francisco, CA')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A string with current weather conditions and temperature
|
||||||
|
\"\"\"
|
||||||
|
api_key = ctx.deps.get("WEATHER_API_KEY")
|
||||||
|
if not api_key:
|
||||||
|
return "Error: Weather API key not configured"
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = f"https://api.weatherapi.com/v1/current.json?key={api_key}&q={location}"
|
||||||
|
response = requests.get(url)
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
if "error" in data:
|
||||||
|
return f"Error: {data['error']['message']}"
|
||||||
|
|
||||||
|
current = data["current"]
|
||||||
|
location_name = f"{data['location']['name']}, {data['location']['country']}"
|
||||||
|
condition = current["condition"]["text"]
|
||||||
|
temp_c = current["temp_c"]
|
||||||
|
temp_f = current["temp_f"]
|
||||||
|
humidity = current["humidity"]
|
||||||
|
|
||||||
|
return f"Weather in {location_name}: {condition}, {temp_c}°C ({temp_f}°F), {humidity}% humidity"
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error retrieving weather data: {str(e)}"
|
||||||
|
"""
|
||||||
|
st.code(pydantic_tool_example, language="python")
|
||||||
|
|
||||||
|
st.write("##### Tool Usage in Agent")
|
||||||
|
tool_usage_example = """
|
||||||
|
async def use_weather_tool(location: str) -> str:
|
||||||
|
\"\"\"Search for weather information\"\"\"
|
||||||
|
tool = agent.get_tool("get_weather")
|
||||||
|
result = await tool.execute({"location": location})
|
||||||
|
return result.content
|
||||||
|
"""
|
||||||
|
st.code(tool_usage_example, language="python")
|
||||||
|
|
||||||
|
with example_tab:
|
||||||
|
st.write("##### Example Agents")
|
||||||
|
st.markdown("""
|
||||||
|
V6 will include pre-built example agents that serve as templates and learning resources. These examples will be baked directly into agent prompts to improve results and consistency.
|
||||||
|
|
||||||
|
**Benefits of Example Agents:**
|
||||||
|
- Provide concrete implementation patterns for common agent types
|
||||||
|
- Demonstrate best practices for tool usage and error handling
|
||||||
|
- Serve as starting points that can be customized for specific needs
|
||||||
|
- Improve consistency in agent behavior and output format
|
||||||
|
- Reduce the learning curve for new users
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.write("##### Example Agent Types")
|
||||||
|
|
||||||
|
example_agents = {
|
||||||
|
"Research Assistant": {
|
||||||
|
"description": "Performs comprehensive research on topics using web search and content analysis",
|
||||||
|
"tools": ["web_search", "web_browser", "summarization"],
|
||||||
|
"example_prompt": "Research the latest advancements in quantum computing and provide a summary"
|
||||||
|
},
|
||||||
|
"Data Analyst": {
|
||||||
|
"description": "Analyzes datasets, generates visualizations, and provides insights",
|
||||||
|
"tools": ["database_query", "data_analysis", "chart_generation"],
|
||||||
|
"example_prompt": "Analyze this sales dataset and identify key trends over the past quarter"
|
||||||
|
},
|
||||||
|
"Content Creator": {
|
||||||
|
"description": "Generates various types of content including text, images, and code",
|
||||||
|
"tools": ["text_generation", "image_generation", "code_generation"],
|
||||||
|
"example_prompt": "Create a blog post about sustainable living with accompanying images"
|
||||||
|
},
|
||||||
|
"Conversational Assistant": {
|
||||||
|
"description": "Engages in helpful, informative conversations with natural dialogue",
|
||||||
|
"tools": ["knowledge_base", "memory_management", "personalization"],
|
||||||
|
"example_prompt": "I'd like to learn more about machine learning. Where should I start?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a table of example agents
|
||||||
|
example_data = {
|
||||||
|
"Agent Type": list(example_agents.keys()),
|
||||||
|
"Description": [example_agents[a]["description"] for a in example_agents],
|
||||||
|
"Core Tools": [", ".join(example_agents[a]["tools"]) for a in example_agents]
|
||||||
|
}
|
||||||
|
|
||||||
|
st.dataframe(example_data, use_container_width=True)
|
||||||
|
|
||||||
|
st.write("##### Example Agent Implementation")
|
||||||
|
|
||||||
|
st.code("""
|
||||||
|
# Example Weather Agent based on Pydantic AI documentation
|
||||||
|
from pydantic_ai import Agent, RunContext
|
||||||
|
from typing import Dict, Any
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from httpx import AsyncClient
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WeatherDeps:
|
||||||
|
client: AsyncClient
|
||||||
|
weather_api_key: str | None
|
||||||
|
geo_api_key: str | None
|
||||||
|
|
||||||
|
# Create the agent with appropriate system prompt
|
||||||
|
weather_agent = Agent(
|
||||||
|
'openai:gpt-4o',
|
||||||
|
system_prompt=(
|
||||||
|
'Be concise, reply with one sentence. '
|
||||||
|
'Use the `get_lat_lng` tool to get the latitude and longitude of locations, '
|
||||||
|
'then use the `get_weather` tool to get the weather.'
|
||||||
|
),
|
||||||
|
deps_type=WeatherDeps,
|
||||||
|
)
|
||||||
|
|
||||||
|
@weather_agent.tool
|
||||||
|
async def get_lat_lng(ctx: RunContext[WeatherDeps], location_description: str) -> Dict[str, float]:
|
||||||
|
\"\"\"Get the latitude and longitude of a location.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
location_description: A description of a location (e.g., 'London, UK')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with lat and lng keys
|
||||||
|
\"\"\"
|
||||||
|
if ctx.deps.geo_api_key is None:
|
||||||
|
# Return dummy data if no API key
|
||||||
|
return {'lat': 51.1, 'lng': -0.1}
|
||||||
|
|
||||||
|
# Call geocoding API
|
||||||
|
params = {'q': location_description, 'api_key': ctx.deps.geo_api_key}
|
||||||
|
r = await ctx.deps.client.get('https://geocode.maps.co/search', params=params)
|
||||||
|
r.raise_for_status()
|
||||||
|
data = r.json()
|
||||||
|
|
||||||
|
if data:
|
||||||
|
return {'lat': float(data[0]['lat']), 'lng': float(data[0]['lon'])}
|
||||||
|
else:
|
||||||
|
return {'error': 'Location not found'}
|
||||||
|
|
||||||
|
@weather_agent.tool
|
||||||
|
async def get_weather(ctx: RunContext[WeatherDeps], lat: float, lng: float) -> Dict[str, Any]:
|
||||||
|
\"\"\"Get the weather at a location.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lat: Latitude of the location
|
||||||
|
lng: Longitude of the location
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with temperature and description
|
||||||
|
\"\"\"
|
||||||
|
if ctx.deps.weather_api_key is None:
|
||||||
|
# Return dummy data if no API key
|
||||||
|
return {'temperature': '21°C', 'description': 'Sunny'}
|
||||||
|
|
||||||
|
# Call weather API
|
||||||
|
params = {
|
||||||
|
'apikey': ctx.deps.weather_api_key,
|
||||||
|
'location': f'{lat},{lng}',
|
||||||
|
'units': 'metric',
|
||||||
|
}
|
||||||
|
r = await ctx.deps.client.get(
|
||||||
|
'https://api.tomorrow.io/v4/weather/realtime',
|
||||||
|
params=params
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
data = r.json()
|
||||||
|
|
||||||
|
values = data['data']['values']
|
||||||
|
weather_codes = {
|
||||||
|
1000: 'Clear, Sunny',
|
||||||
|
1100: 'Mostly Clear',
|
||||||
|
1101: 'Partly Cloudy',
|
||||||
|
4001: 'Rain',
|
||||||
|
5000: 'Snow',
|
||||||
|
8000: 'Thunderstorm',
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'temperature': f'{values["temperatureApparent"]:0.0f}°C',
|
||||||
|
'description': weather_codes.get(values['weatherCode'], 'Unknown'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Example usage
|
||||||
|
async def get_weather_report(location: str) -> str:
|
||||||
|
\"\"\"Get weather report for a location.\"\"\"
|
||||||
|
async with AsyncClient() as client:
|
||||||
|
deps = WeatherDeps(
|
||||||
|
client=client,
|
||||||
|
weather_api_key="YOUR_API_KEY", # Replace with actual key
|
||||||
|
geo_api_key="YOUR_API_KEY", # Replace with actual key
|
||||||
|
)
|
||||||
|
result = await weather_agent.run(
|
||||||
|
f"What is the weather like in {location}?",
|
||||||
|
deps=deps
|
||||||
|
)
|
||||||
|
return result.data
|
||||||
|
""", language="python")
|
||||||
|
|
||||||
|
st.info("""
|
||||||
|
**In-Context Learning with Examples**
|
||||||
|
|
||||||
|
These example agents will be used in the system prompt for Archon, providing concrete examples that help the LLM understand the expected structure and quality of agent code. This approach leverages in-context learning to significantly improve code generation quality and consistency.
|
||||||
|
""")
|
||||||
|
|
||||||
|
# V7: LangGraph Documentation
|
||||||
|
with st.expander("V7: LangGraph Documentation"):
|
||||||
|
st.write("Integrating LangGraph for complex agent workflows")
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
### Pydantic AI vs LangGraph with Pydantic AI
|
||||||
|
|
||||||
|
V7 will integrate LangGraph to enable complex agent workflows while maintaining compatibility with Pydantic AI agents.
|
||||||
|
This allows for creating sophisticated multi-agent systems with well-defined state management and workflow control.
|
||||||
|
""")
|
||||||
|
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
st.markdown("#### Pydantic AI Agent")
|
||||||
|
st.markdown("Simple, standalone agent with tools")
|
||||||
|
|
||||||
|
pydantic_agent_code = """
|
||||||
|
# Simple Pydantic AI Weather Agent
|
||||||
|
from pydantic_ai import Agent, RunContext
|
||||||
|
from typing import Dict, Any
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from httpx import AsyncClient
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WeatherDeps:
|
||||||
|
client: AsyncClient
|
||||||
|
weather_api_key: str | None
|
||||||
|
|
||||||
|
# Create the agent
|
||||||
|
weather_agent = Agent(
|
||||||
|
'openai:gpt-4o',
|
||||||
|
system_prompt="You provide weather information.",
|
||||||
|
deps_type=WeatherDeps,
|
||||||
|
)
|
||||||
|
|
||||||
|
@weather_agent.tool
|
||||||
|
async def get_weather(
|
||||||
|
ctx: RunContext[WeatherDeps],
|
||||||
|
location: str
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
\"\"\"Get weather for a location.\"\"\"
|
||||||
|
# Implementation details...
|
||||||
|
return {"temperature": "21°C", "description": "Sunny"}
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
async def main():
|
||||||
|
async with AsyncClient() as client:
|
||||||
|
deps = WeatherDeps(
|
||||||
|
client=client,
|
||||||
|
weather_api_key="API_KEY"
|
||||||
|
)
|
||||||
|
result = await weather_agent.run(
|
||||||
|
"What's the weather in London?",
|
||||||
|
deps=deps
|
||||||
|
)
|
||||||
|
print(result.data)
|
||||||
|
"""
|
||||||
|
st.code(pydantic_agent_code, language="python")
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
st.markdown("#### LangGraph with Pydantic AI Agent")
|
||||||
|
st.markdown("Complex workflow using Pydantic AI agents in a graph")
|
||||||
|
|
||||||
|
langgraph_code = """
|
||||||
|
# LangGraph with Pydantic AI Agents
|
||||||
|
from pydantic_ai import Agent, RunContext
|
||||||
|
from typing import TypedDict, Literal
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from httpx import AsyncClient
|
||||||
|
from langgraph.graph import StateGraph, START, END
|
||||||
|
|
||||||
|
# Define state for LangGraph
|
||||||
|
class GraphState(TypedDict):
|
||||||
|
query: str
|
||||||
|
weather_result: str
|
||||||
|
verified: bool
|
||||||
|
response: str
|
||||||
|
|
||||||
|
# Create a verifier agent
|
||||||
|
verifier_agent = Agent(
|
||||||
|
'openai:gpt-4o',
|
||||||
|
system_prompt=(
|
||||||
|
"You verify weather information for accuracy and completeness. "
|
||||||
|
"Check if the weather report includes temperature, conditions, "
|
||||||
|
"and is properly formatted."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define nodes for the graph
|
||||||
|
async def get_weather_info(state: GraphState) -> GraphState:
|
||||||
|
\"\"\"Use the weather agent to get weather information.\"\"\"
|
||||||
|
# Simply use the weather agent directly
|
||||||
|
async with AsyncClient() as client:
|
||||||
|
deps = WeatherDeps(
|
||||||
|
client=client,
|
||||||
|
weather_api_key="API_KEY"
|
||||||
|
)
|
||||||
|
result = await weather_agent.run(
|
||||||
|
state["query"],
|
||||||
|
deps=deps
|
||||||
|
)
|
||||||
|
return {"weather_result": result.data}
|
||||||
|
|
||||||
|
async def verify_information(state: GraphState) -> GraphState:
|
||||||
|
\"\"\"Use the verifier agent to check the weather information.\"\"\"
|
||||||
|
result = await verifier_agent.run(
|
||||||
|
f"Verify this weather information: {state['weather_result']}"
|
||||||
|
)
|
||||||
|
# Simple verification logic
|
||||||
|
verified = "accurate" in result.data.lower()
|
||||||
|
return {"verified": verified}
|
||||||
|
|
||||||
|
async def route(state: GraphState) -> Literal["regenerate", "finalize"]:
|
||||||
|
"\"\"Decide whether to regenerate or finalize based on verification.\"\"\"
|
||||||
|
if state["verified"]:
|
||||||
|
return "finalize"
|
||||||
|
else:
|
||||||
|
return "regenerate"
|
||||||
|
|
||||||
|
async def regenerate_response(state: GraphState) -> GraphState:
|
||||||
|
\"\"\"Regenerate a better response if verification failed.\"\"\"
|
||||||
|
result = await verifier_agent.run(
|
||||||
|
result = await weather_agent.run(
|
||||||
|
f"Please provide more detailed weather information for: {state['query']}"
|
||||||
|
)
|
||||||
|
return {"weather_result": result.data, "verified": True}
|
||||||
|
|
||||||
|
async def finalize_response(state: GraphState) -> GraphState:
|
||||||
|
\"\"\"Format the final response.\"\"\"
|
||||||
|
return {"response": f"Verified Weather Report: {state['weather_result']}"}
|
||||||
|
|
||||||
|
# Build the graph
|
||||||
|
workflow = StateGraph(GraphState)
|
||||||
|
|
||||||
|
# Add nodes
|
||||||
|
workflow.add_node("get_weather", get_weather_info)
|
||||||
|
workflow.add_node("verify", verify_information)
|
||||||
|
workflow.add_node("regenerate", regenerate_response)
|
||||||
|
workflow.add_node("finalize", finalize_response)
|
||||||
|
|
||||||
|
# Add edges
|
||||||
|
workflow.add_edge(START, "get_weather")
|
||||||
|
workflow.add_edge("get_weather", "verify")
|
||||||
|
|
||||||
|
# Add conditional edges based on verification
|
||||||
|
workflow.add_conditional_edges(
|
||||||
|
"verify",
|
||||||
|
route,
|
||||||
|
{
|
||||||
|
"regenerate": "regenerate",
|
||||||
|
"finalize": "finalize"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
workflow.add_edge("regenerate", "finalize")
|
||||||
|
workflow.add_edge("finalize", END)
|
||||||
|
|
||||||
|
# Compile the graph
|
||||||
|
app = workflow.compile()
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
async def main():
|
||||||
|
result = await app.ainvoke({
|
||||||
|
"query": "What's the weather in London?",
|
||||||
|
"verified": False
|
||||||
|
})
|
||||||
|
print(result["response"])
|
||||||
|
"""
|
||||||
|
st.code(langgraph_code, language="python")
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
### Key Benefits of Integration
|
||||||
|
|
||||||
|
1. **Workflow Management**: LangGraph provides a structured way to define complex agent workflows with clear state transitions.
|
||||||
|
|
||||||
|
2. **Reusability**: Pydantic AI agents can be reused within LangGraph nodes, maintaining their tool capabilities.
|
||||||
|
|
||||||
|
3. **Visualization**: LangGraph offers built-in visualization of agent workflows, making it easier to understand and debug complex systems.
|
||||||
|
|
||||||
|
4. **State Management**: The typed state in LangGraph ensures type safety and clear data flow between nodes.
|
||||||
|
|
||||||
|
5. **Parallel Execution**: LangGraph supports parallel execution of nodes, enabling more efficient processing.
|
||||||
|
|
||||||
|
6. **Human-in-the-Loop**: Both frameworks support human intervention points, which can be combined for powerful interactive systems.
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.image("https://blog.langchain.dev/content/images/2024/01/simple_multi_agent_diagram--1-.png",
|
||||||
|
caption="Example LangGraph Multi-Agent Workflow", width=600)
|
||||||
|
|
||||||
|
# V8: Self-Feedback Loop
|
||||||
|
with st.expander("V8: Self-Feedback Loop"):
|
||||||
|
st.write("Automated validation and error correction")
|
||||||
|
|
||||||
|
# Create a visual feedback loop
|
||||||
|
st.graphviz_chart('''
|
||||||
|
digraph {
|
||||||
|
rankdir=TB;
|
||||||
|
node [shape=box, style=filled, color=lightblue];
|
||||||
|
|
||||||
|
Agent [label="Agent Generation"];
|
||||||
|
Test [label="Automated Testing"];
|
||||||
|
Validate [label="Validation"];
|
||||||
|
Error [label="Error Detection"];
|
||||||
|
Fix [label="Self-Correction"];
|
||||||
|
|
||||||
|
Agent -> Test;
|
||||||
|
Test -> Validate;
|
||||||
|
Validate -> Error [label="Issues Found"];
|
||||||
|
Error -> Fix;
|
||||||
|
Fix -> Agent [label="Regenerate"];
|
||||||
|
Validate -> Agent [label="Success", color=green];
|
||||||
|
}
|
||||||
|
''')
|
||||||
|
|
||||||
|
st.write("#### Validation Process")
|
||||||
|
st.info("""
|
||||||
|
1. Generate agent code
|
||||||
|
2. Run automated tests
|
||||||
|
3. Analyze test results
|
||||||
|
4. Identify errors or improvement areas
|
||||||
|
5. Apply self-correction algorithms
|
||||||
|
6. Regenerate improved code
|
||||||
|
7. Repeat until validation passes
|
||||||
|
""")
|
||||||
|
|
||||||
|
# V9: Multi-Framework Support
|
||||||
|
with st.expander("V9: Multi-Framework Support"):
|
||||||
|
st.write("Framework-agnostic agent generation")
|
||||||
|
|
||||||
|
frameworks = {
|
||||||
|
"Pydantic AI": {"status": "Supported", "description": "Native support for function-based agents"},
|
||||||
|
"LangGraph": {"status": "Coming in V7", "description": "Declarative multi-agent orchestration"},
|
||||||
|
"LangChain": {"status": "Planned", "description": "Popular agent framework with extensive tools"},
|
||||||
|
"Agno (Phidata)": {"status": "Planned", "description": "Multi-agent workflow framework"},
|
||||||
|
"CrewAI": {"status": "Planned", "description": "Role-based collaborative agents"},
|
||||||
|
"LlamaIndex": {"status": "Planned", "description": "RAG-focused agent framework"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a frameworks comparison table
|
||||||
|
df_data = {
|
||||||
|
"Framework": list(frameworks.keys()),
|
||||||
|
"Status": [frameworks[f]["status"] for f in frameworks],
|
||||||
|
"Description": [frameworks[f]["description"] for f in frameworks]
|
||||||
|
}
|
||||||
|
|
||||||
|
st.dataframe(df_data, use_container_width=True)
|
||||||
|
|
||||||
|
# V10: Autonomous Framework Learning
|
||||||
|
with st.expander("V10: Autonomous Framework Learning"):
|
||||||
|
st.write("Self-learning from mistakes and continuous improvement")
|
||||||
|
|
||||||
|
st.write("#### Self-Improvement Process")
|
||||||
|
|
||||||
|
improvement_process = [
|
||||||
|
{"phase": "Error Detection", "description": "Identifies patterns in failed agent generations and runtime errors"},
|
||||||
|
{"phase": "Root Cause Analysis", "description": "Analyzes error patterns to determine underlying issues in prompts or examples"},
|
||||||
|
{"phase": "Prompt Refinement", "description": "Automatically updates system prompts to address identified weaknesses"},
|
||||||
|
{"phase": "Example Augmentation", "description": "Adds new examples to the prompt library based on successful generations"},
|
||||||
|
{"phase": "Tool Enhancement", "description": "Creates or modifies tools to handle edge cases and common failure modes"},
|
||||||
|
{"phase": "Validation", "description": "Tests improvements against historical failure cases to ensure progress"}
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, phase in enumerate(improvement_process):
|
||||||
|
st.write(f"**{i+1}. {phase['phase']}:** {phase['description']}")
|
||||||
|
|
||||||
|
st.info("This enables Archon to stay updated with the latest AI frameworks without manual intervention.")
|
||||||
|
|
||||||
|
# V11: Advanced RAG Techniques
|
||||||
|
with st.expander("V11: Advanced RAG Techniques"):
|
||||||
|
st.write("Enhanced retrieval and incorporation of framework documentation")
|
||||||
|
|
||||||
|
st.write("#### Advanced RAG Components")
|
||||||
|
|
||||||
|
col1, col2 = st.columns(2)
|
||||||
|
|
||||||
|
with col1:
|
||||||
|
st.markdown("#### Document Processing")
|
||||||
|
st.markdown("""
|
||||||
|
- **Hierarchical Chunking**: Multi-level chunking strategy that preserves document structure
|
||||||
|
- **Semantic Headers**: Extraction of meaningful section headers for better context
|
||||||
|
- **Code-Text Separation**: Specialized embedding models for code vs. natural language
|
||||||
|
- **Metadata Enrichment**: Automatic tagging with framework version, function types, etc.
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.markdown("#### Query Processing")
|
||||||
|
st.markdown("""
|
||||||
|
- **Query Decomposition**: Breaking complex queries into sub-queries
|
||||||
|
- **Framework Detection**: Identifying which framework the query relates to
|
||||||
|
- **Intent Classification**: Determining if query is about usage, concepts, or troubleshooting
|
||||||
|
- **Query Expansion**: Adding relevant framework-specific terminology
|
||||||
|
""")
|
||||||
|
|
||||||
|
with col2:
|
||||||
|
st.markdown("#### Retrieval Enhancements")
|
||||||
|
st.markdown("""
|
||||||
|
- **Hybrid Search**: Combining dense and sparse retrievers for optimal results
|
||||||
|
- **Re-ranking**: Post-retrieval scoring based on relevance to the specific task
|
||||||
|
- **Cross-Framework Retrieval**: Finding analogous patterns across different frameworks
|
||||||
|
- **Code Example Prioritization**: Boosting practical examples in search results
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.markdown("#### Knowledge Integration")
|
||||||
|
st.markdown("""
|
||||||
|
- **Context Stitching**: Intelligently combining information from multiple chunks
|
||||||
|
- **Framework Translation**: Converting patterns between frameworks (e.g., LangChain to LangGraph)
|
||||||
|
- **Version Awareness**: Handling differences between framework versions
|
||||||
|
- **Adaptive Retrieval**: Learning from successful and unsuccessful retrievals
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.info("This enables Archon to more effectively retrieve and incorporate framework documentation, leading to more accurate and contextually appropriate agent generation.")
|
||||||
|
|
||||||
|
# V12: MCP Agent Marketplace
|
||||||
|
with st.expander("V12: MCP Agent Marketplace"):
|
||||||
|
st.write("Integrating Archon agents as MCP servers and publishing to marketplaces")
|
||||||
|
|
||||||
|
st.write("#### MCP Integration Process")
|
||||||
|
|
||||||
|
mcp_integration_process = [
|
||||||
|
{"phase": "Protocol Implementation", "description": "Implement the Model Context Protocol to enable IDE integration"},
|
||||||
|
{"phase": "Agent Conversion", "description": "Transform Archon-generated agents into MCP-compatible servers"},
|
||||||
|
{"phase": "Specialized Agent Creation", "description": "Build purpose-specific agents for code review, refactoring, and testing"},
|
||||||
|
{"phase": "Marketplace Publishing", "description": "Package and publish agents to MCP marketplaces for distribution"},
|
||||||
|
{"phase": "IDE Integration", "description": "Enable seamless operation within Windsurf, Cursor, and other MCP-enabled IDEs"}
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, phase in enumerate(mcp_integration_process):
|
||||||
|
st.write(f"**{i+1}. {phase['phase']}:** {phase['description']}")
|
||||||
|
|
||||||
|
st.info("This enables Archon to create specialized agents that operate directly within IDEs through the MCP protocol, while also making them available through marketplace distribution channels.")
|
||||||
|
|
||||||
|
# Future Integrations section
|
||||||
|
st.write("### Future Integrations")
|
||||||
|
|
||||||
|
# LangSmith
|
||||||
|
with st.expander("LangSmith"):
|
||||||
|
st.write("Integration with LangChain's tracing and monitoring platform")
|
||||||
|
|
||||||
|
st.image("https://docs.smith.langchain.com/assets/images/trace-9510284b5b15ba55fc1cca6af2404657.png", width=600)
|
||||||
|
|
||||||
|
st.write("#### LangSmith Benefits")
|
||||||
|
st.markdown("""
|
||||||
|
- **Tracing**: Monitor agent execution steps and decisions
|
||||||
|
- **Debugging**: Identify issues in complex agent workflows
|
||||||
|
- **Analytics**: Track performance and cost metrics
|
||||||
|
- **Evaluation**: Assess agent quality with automated testing
|
||||||
|
- **Feedback Collection**: Gather human feedback to improve agents
|
||||||
|
""")
|
||||||
|
|
||||||
|
# MCP Marketplace
|
||||||
|
with st.expander("MCP Marketplace"):
|
||||||
|
st.write("Integration with AI IDE marketplaces")
|
||||||
|
|
||||||
|
st.write("#### MCP Marketplace Integration")
|
||||||
|
st.markdown("""
|
||||||
|
- Publish Archon itself as a premium agent in MCP marketplaces
|
||||||
|
- Create specialized Archon variants for different development needs
|
||||||
|
- Enable one-click installation directly from within IDEs
|
||||||
|
- Integrate seamlessly with existing development workflows
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.warning("The Model Context Protocol (MCP) is an emerging standard for AI assistant integration with IDEs like Windsurf, Cursor, and Cline.")
|
||||||
|
|
||||||
|
# Other Frameworks
|
||||||
|
with st.expander("Other Frameworks besides Pydantic AI"):
|
||||||
|
st.write("Support for additional agent frameworks")
|
||||||
|
|
||||||
|
st.write("#### Framework Adapter Architecture")
|
||||||
|
|
||||||
|
st.graphviz_chart('''
|
||||||
|
digraph {
|
||||||
|
rankdir=TB;
|
||||||
|
node [shape=box, style=filled, color=lightblue];
|
||||||
|
|
||||||
|
Archon [label="Archon Core"];
|
||||||
|
Adapter [label="Framework Adapter Layer"];
|
||||||
|
|
||||||
|
Pydantic [label="Pydantic AI", color=lightskyblue];
|
||||||
|
LangGraph [label="LangGraph", color=lightskyblue];
|
||||||
|
LangChain [label="LangChain", color=lightskyblue];
|
||||||
|
Agno [label="Agno", color=lightskyblue];
|
||||||
|
CrewAI [label="CrewAI", color=lightskyblue];
|
||||||
|
LlamaIndex [label="LlamaIndex", color=lightskyblue];
|
||||||
|
|
||||||
|
Archon -> Adapter;
|
||||||
|
Adapter -> Pydantic;
|
||||||
|
Adapter -> LangGraph;
|
||||||
|
Adapter -> LangChain;
|
||||||
|
Adapter -> Agno;
|
||||||
|
Adapter -> CrewAI;
|
||||||
|
Adapter -> LlamaIndex;
|
||||||
|
}
|
||||||
|
''')
|
||||||
|
|
||||||
|
# Vector Databases
|
||||||
|
with st.expander("Other Vector Databases besides Supabase"):
|
||||||
|
st.write("Support for additional vector databases")
|
||||||
|
|
||||||
|
vector_dbs = {
|
||||||
|
"Supabase": {"status": "Supported", "features": ["pgvector integration", "SQL API", "Real-time subscriptions"]},
|
||||||
|
"Pinecone": {"status": "Planned", "features": ["High scalability", "Low latency", "Serverless"]},
|
||||||
|
"Qdrant": {"status": "Planned", "features": ["Filtering", "Self-hosted option", "REST API"]},
|
||||||
|
"Milvus": {"status": "Planned", "features": ["Horizontal scaling", "Cloud-native", "Hybrid search"]},
|
||||||
|
"Chroma": {"status": "Planned", "features": ["Local-first", "Lightweight", "Simple API"]},
|
||||||
|
"Weaviate": {"status": "Planned", "features": ["GraphQL", "Multi-modal", "RESTful API"]}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create vector DB comparison table
|
||||||
|
df_data = {
|
||||||
|
"Vector Database": list(vector_dbs.keys()),
|
||||||
|
"Status": [vector_dbs[db]["status"] for db in vector_dbs],
|
||||||
|
"Key Features": [", ".join(vector_dbs[db]["features"]) for db in vector_dbs]
|
||||||
|
}
|
||||||
|
|
||||||
|
st.dataframe(df_data, use_container_width=True)
|
||||||
|
|
||||||
|
# Local AI Package
|
||||||
|
with st.expander("Local AI Package Integration"):
|
||||||
|
st.write("Integration with [Local AI Package](https://github.com/coleam00/local-ai-packaged)")
|
||||||
|
|
||||||
|
st.markdown("""
|
||||||
|
The Local AI Package enables running models entirely locally, providing:
|
||||||
|
|
||||||
|
- **Complete Privacy**: No data leaves your machine
|
||||||
|
- **Cost Savings**: Eliminate API usage fees
|
||||||
|
- **Offline Operation**: Work without internet connectivity
|
||||||
|
- **Custom Fine-tuning**: Adapt models to specific domains
|
||||||
|
- **Lower Latency**: Reduce response times for better UX
|
||||||
|
""")
|
||||||
|
|
||||||
|
st.info("This integration will allow Archon to operate fully offline with local models for both agent creation and execution.")
|
||||||
@ -21,6 +21,7 @@ from openai import AsyncOpenAI
|
|||||||
from supabase import Client, create_client
|
from supabase import Client, create_client
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from utils.utils import get_env_var, save_env_var, write_to_log
|
from utils.utils import get_env_var, save_env_var, write_to_log
|
||||||
|
from future_enhancements import future_enhancements_tab
|
||||||
|
|
||||||
# Import all the message part classes
|
# Import all the message part classes
|
||||||
from pydantic_ai.messages import (
|
from pydantic_ai.messages import (
|
||||||
@ -71,13 +72,13 @@ st.set_page_config(
|
|||||||
layout="wide",
|
layout="wide",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set custom theme colors to match Archon logo (pink and green)
|
# Set custom theme colors to match Archon logo (green and pink)
|
||||||
# Primary color (pink) and secondary color (green)
|
# Primary color (green) and secondary color (pink)
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #00CC99; /* Pink */
|
--primary-color: #00CC99; /* Green */
|
||||||
--secondary-color: #FF69B4; /* Green */
|
--secondary-color: #EB2D8C; /* Pink */
|
||||||
--text-color: #262730;
|
--text-color: #262730;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,9 +488,9 @@ def intro_tab():
|
|||||||
create_new_tab_button("Go to the Documentation Section (New Tab)", "Documentation", key="goto_docs", use_container_width=True)
|
create_new_tab_button("Go to the Documentation Section (New Tab)", "Documentation", key="goto_docs", use_container_width=True)
|
||||||
|
|
||||||
# Step 4: Agent Service
|
# Step 4: Agent Service
|
||||||
with st.expander("Step 4: Agent Service Setup", expanded=False):
|
with st.expander("Step 4: Agent Service Setup (for MCP)", expanded=False):
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
### Agent Service Setup
|
### MCP Agent Service Setup
|
||||||
|
|
||||||
Start the graph service for agent generation:
|
Start the graph service for agent generation:
|
||||||
|
|
||||||
@ -879,8 +880,8 @@ def show_manual_sql_instructions(sql, recreate=False):
|
|||||||
|
|
||||||
def agent_service_tab():
|
def agent_service_tab():
|
||||||
"""Display the agent service interface for managing the graph service"""
|
"""Display the agent service interface for managing the graph service"""
|
||||||
st.header("Agent Service")
|
st.header("MCP Agent Service")
|
||||||
st.write("Start, restart, and monitor the Archon agent service.")
|
st.write("Start, restart, and monitor the Archon agent service for MCP.")
|
||||||
|
|
||||||
# Initialize session state variables if they don't exist
|
# Initialize session state variables if they don't exist
|
||||||
if "service_process" not in st.session_state:
|
if "service_process" not in st.session_state:
|
||||||
@ -1207,7 +1208,7 @@ async def main():
|
|||||||
query_params = st.query_params
|
query_params = st.query_params
|
||||||
if "tab" in query_params:
|
if "tab" in query_params:
|
||||||
tab_name = query_params["tab"]
|
tab_name = query_params["tab"]
|
||||||
if tab_name in ["Intro", "Chat", "Environment", "Database", "Documentation", "Agent Service", "MCP"]:
|
if tab_name in ["Intro", "Chat", "Environment", "Database", "Documentation", "Agent Service", "MCP", "Future Enhancements"]:
|
||||||
st.session_state.selected_tab = tab_name
|
st.session_state.selected_tab = tab_name
|
||||||
|
|
||||||
# Add sidebar navigation
|
# Add sidebar navigation
|
||||||
@ -1229,6 +1230,7 @@ async def main():
|
|||||||
docs_button = st.button("Documentation", use_container_width=True, key="docs_button")
|
docs_button = st.button("Documentation", use_container_width=True, key="docs_button")
|
||||||
service_button = st.button("Agent Service", use_container_width=True, key="service_button")
|
service_button = st.button("Agent Service", use_container_width=True, key="service_button")
|
||||||
mcp_button = st.button("MCP", use_container_width=True, key="mcp_button")
|
mcp_button = st.button("MCP", use_container_width=True, key="mcp_button")
|
||||||
|
future_enhancements_button = st.button("Future Enhancements", use_container_width=True, key="future_enhancements_button")
|
||||||
|
|
||||||
# Update selected tab based on button clicks
|
# Update selected tab based on button clicks
|
||||||
if intro_button:
|
if intro_button:
|
||||||
@ -1245,6 +1247,8 @@ async def main():
|
|||||||
st.session_state.selected_tab = "Database"
|
st.session_state.selected_tab = "Database"
|
||||||
elif docs_button:
|
elif docs_button:
|
||||||
st.session_state.selected_tab = "Documentation"
|
st.session_state.selected_tab = "Documentation"
|
||||||
|
elif future_enhancements_button:
|
||||||
|
st.session_state.selected_tab = "Future Enhancements"
|
||||||
|
|
||||||
# Display the selected tab
|
# Display the selected tab
|
||||||
if st.session_state.selected_tab == "Intro":
|
if st.session_state.selected_tab == "Intro":
|
||||||
@ -1268,6 +1272,9 @@ async def main():
|
|||||||
elif st.session_state.selected_tab == "Documentation":
|
elif st.session_state.selected_tab == "Documentation":
|
||||||
st.title("Archon - Documentation")
|
st.title("Archon - Documentation")
|
||||||
documentation_tab()
|
documentation_tab()
|
||||||
|
elif st.session_state.selected_tab == "Future Enhancements":
|
||||||
|
st.title("Archon - Future Enhancements")
|
||||||
|
future_enhancements_tab()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user