# title: Mixture of Expert Agents (MoEA - Fixed)
# author: techelpr + ChatGPT
# version: 1.1
# required_open_webui_version: 0.3.9
from pydantic import BaseModel, Field
from typing import Optional, List
import requests
import json
class Filter:
class Valves(BaseModel):
models: List[str] = Field(
default=[], description="List of models to use in the MoEA architecture."
)
openai_api_base: str = Field(
default="http://host.docker.internal:11434/v1",
description="Base URL for Ollama API.",
)
num_layers: int = Field(default=1, description="Number of MoEA layers.")
def __init__(self):
self.valves = self.Valves()
def inlet(self, body: dict, user: Optional[dict] = None) -> dict:
"""
Injects MoEA-enhanced system context into the prompt, preserving original user message.
"""
messages = body.get("messages", [])
if not messages:
return body
# Get last user message and any system prompt (usually character sheet)
system_msg = next((m for m in messages if m["role"] == "system"), None)
user_msg = messages[-1]
user_prompt = user_msg.get("content", "")
base_context = system_msg["content"] if system_msg else ""
# Generate MoEA reflections
moea_context = self.moa_process(user_prompt)
# Merge the user's character/system prompt with MoEA thoughts
full_context = base_context.strip() + "\n\n" + "----\n" + moea_context.strip()
# Rebuild message list
body["messages"] = [
{"role": "system", "content": full_context},
{"role": "user", "content": user_prompt},
]
return body
def agent_prompt(self, original_prompt: str, previous_responses: List[str]) -> str:
"""
Create a reflection-style context prompt for experts.
"""
internal = "\n".join(f"- {r.strip()}" for r in previous_responses)
return f"*Internal Thoughts (from other agents):*\n{internal}\n\n*User Prompt:*\n{original_prompt}"
def moa_process(self, prompt: str) -> str:
"""
MoEA pipeline: Routes the user prompt through expert agents,
aggregates internal thoughts, and formats a guiding system message.
"""
layer_outputs = []
if not self.valves.models or not self.valves.openai_api_base:
return "Error: MoEA valve misconfiguration."
for layer in range(self.valves.num_layers):
current_layer_outputs = []
for model in self.valves.models:
instruct_prompt = (
prompt
if layer == 0
else self.agent_prompt(prompt, layer_outputs[-1])
)
response = self.query_ollama(model, instruct_prompt)
current_layer_outputs.append(response)
layer_outputs.append(current_layer_outputs)
# Flatten and summarize all expert outputs
merged_responses = []
for layer in layer_outputs:
merged_responses.extend(layer)
# Construct invisible guiding system message
internal_thoughts = "\n".join(f"- {r.strip()}" for r in merged_responses)
system_prompt = (
"You are a creative, role-playing AI. You are aware of multiple internal expert thoughts:\n\n"
f"{internal_thoughts}\n\n"
"These thoughts should shape your response subtly, never being mentioned directly.\n"
"Focus entirely on the user's prompt while integrating useful details and ideas from the internal thoughts.\n"
"Maintain immersive storytelling or RP tone. Do not acknowledge these thoughts unless explicitly instructed."
)
return system_prompt
def query_ollama(self, model: str, prompt: str) -> str:
"""
Calls Ollama-compatible API to get model output for a given prompt.
"""
try:
url = f"{self.valves.openai_api_base}/chat/completions"
headers = {"Content-Type": "application/json"}
data = {"model": model, "messages": [{"role": "user", "content": prompt}]}
response = requests.post(url, headers=headers, data=json.dumps(data))
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except requests.exceptions.RequestException:
return f"Error: Could not query model {model}"