# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['lmoe',
 'lmoe.api',
 'lmoe.commands',
 'lmoe.experts',
 'lmoe.framework',
 'lmoe.templates',
 'lmoe.utils']

package_data = \
{'': ['*']}

install_requires = \
['PySocks>=1.7.1,<2.0.0',
 'PyYAML>=6.0.1,<7.0.0',
 'injector>=0.21.0,<0.22.0',
 'ollama>=0.1.6,<0.2.0',
 'pyperclip>=1.8.2,<2.0.0',
 'pytype>=2024.1.24,<2025.0.0',
 'requests>=2.31.0,<3.0.0',
 'urllib3==1.26.15']

entry_points = \
{'console_scripts': ['lmoe = lmoe.main:run',
                     'lmoe_update_docs = lmoe.release:update_readme_version']}

setup_kwargs = {
    'name': 'lmoe',
    'version': '0.3.12',
    'description': "lmoe (Layered Mixture of Experts,'Elmo') is your programmable CLI assistant.",
    'long_description': '# Introduction\n\n<img src="https://rybosome.github.io/lmoe/assets/lmoe-armadillo.png">\n\n`lmoe` (Layered Mixture of Experts, pronounced "Elmo") is a programmable, multimodal CLI assistant\nwith a natural language interface.\n\nRunning on [Ollama](https://github.com/ollama/ollama) and various [open-weight models](https://ollama.com/library), `lmoe` is a simple, yet powerful way to\ninteract with highly configurable AI models from the command line.\n\n## Setup\n\n### Dependencies\n\n#### Virtual environment\n\nIt is recommended to install `lmoe` in a [virtual environment](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/).\n\nI use [this script](https://github.com/rybosome/lmoe/blob/main/docs/scripts/venv.txt) to make them simpler to manage.\n\n```\n% venv mkdir lmoe\n% venv activate lmoe\n(lmoe) % \n```\n\n#### Ollama\n\nEnsure that an [Ollama](https://github.com/ollama/ollama) server is running.\n\n\n### Installation & Initialization\n\n```\n% pip install lmoe\n% lmoe --initialize\n```\n\nThis will download any base Ollama models not present on your machine and create `lmoe`-internal models.\n\n`lmoe` is now ready to use!\n\n## Overview\n\n`lmoe` is your CLI assistant. It [classifies](https://github.com/rybosome/lmoe/blob/main/lmoe/templates/classifier.modelfile.txt) your query to one of its various [experts](https://github.com/rybosome/lmoe/tree/main/lmoe/experts), which are [specializations](https://github.com/rybosome/lmoe/tree/main/lmoe/templates) of various [open-weight models](https://ollama.com/library).\n\nSee [more on the architecture](#architecture) below.\n\n**NOTE**: All examples below are real interactions with `lmoe` except where explicitly noted.\n\n### Natural language querying\n```\n% lmoe who was matisse\n\n Henri Matisse was a French painter, sculptor, and printmaker, known for his influential role in\n modern art. He was born on December 31, 1869, in Le Cateau-Cambrésis, France, and died on\n November 3, 1954. Matisse is recognized for his use of color and his fluid and expressive\n brushstrokes. His works include iconic paintings such as "The Joy of Life" and "Woman with a Hat."\n```\n\n### Piping context\n\n```\n% cat lmoe/main.py | lmoe what does this code do\n This code sets up and runs an instance of `lmoe` (Layered Mixture of Experts), a Python\n application. It imports various modules, including the native experts and plugin experts for\n `lmoe`. The `run()` function is then called to instantiate the app and defer execution to the\n command runner.\n```\n\n```\n% ls -la $HOME | lmoe how big is my zsh history\n\n The size of your Zsh history file is 16084 bytes.\n```\n\n### Pasting context\n\n```\n% print -x \'hello\'\nprint: positive integer expected after -x: hello\n```\n\nCopy this to the clipboard, then:\n\n```\n% lmoe --paste how do I fix this error\n To use the `-x` option with the `print` command in Bash, you need to provide a positional argument that is a file descriptor. Instead, you provided a string \'hello\'. Here\'s how you can correctly use it:\n\n1. Create or have a file with the name \'hello\' and make sure it exists in your working directory.\n2. Run the following command instead: `print -r -- < hello`. This reads the contents of the file \'hello\' as input for print, which displays its output to stdout.\n```\n\n### Sequencing\n\n`lmoe` can be piped into itself. This allows scriptable composition of primitives into more advanced\nfunctionality.\n\n```\n% lmoe what is the recommended layout for a python project with poetry |\nlmoe "make a project like this for a module called \'alexandria\' with 3 sub modules: \'auth\', \'util\', and \'io\'"\n\n mkdir alexandria/\n touch alexandria/pyproject.toml\n touch alexandria/README.rst\n touch alexandria/requirements.in\n mkdir alexandria/src/\n touch alexandria/src/__init__.py\n mkdir alexandria/src/alexandria/\n touch alexandria/src/alexandria/__init__.py\n mkdir alexandria/src/alexandria/auth/\n touch alexandria/src/alexandria/auth/__init__.py\n touch alexandria/src/alexandria/util/\n touch alexandria/src/alexandria/util/__init__.py\n touch alexandria/src/alexandria/io/\n touch alexandria/src/alexandria/io/__init__.py\n```\n\n\n\n## Capabilities\n\n`lmoe` supports a number of specific functions beyond general LLM querying and instruction.\n\nMore coming soon.\n\n### Image Recognition\n\n*Describe the contents of an image*\n\nThis is `lmoe`\'s first attempt to describe its default avatar.\n\n**Note**: currently this is raw, unparsed JSON output. Edited by hand for readability.\n\n```\n% curl -sS \'https://rybosome.github.io/lmoe/assets/lmoe-armadillo.png\' |\nbase64 -i - |\nlmoe what is in this picture\n{\n    "model":"llava",\n    "created_at":"2024-02-08T07:09:28.827507Z",\n    "response":" The image features a stylized, colorful creature that appears to be a combination\n                 of different animals. It has the body of a rat, with a prominent tail and ears,\n                 which is also typical of rats. The head resembles a cat, with pointy ears and what\n                 seems to be cat whiskers. The creature has eyes like those of a cat, and it\'s\n                 wearing a helmet or headgear that looks like an advanced robot with digital\n                 readouts on the forehead, giving it a cyberpunk aesthetic. The background is\n                 colorful with a rainbow pattern, enhancing the fantastical nature of the creature.\n                 This image is likely a piece of digital art designed to showcase imaginative and\n                 creative concepts. ",\n    "done":true,\n    "context":[733,16289,28793,767,349,297,456,5754,733,28748,16289,28793,415,3469,4190,264,341,2951,1332,28725,3181,1007,15287,369,8045,298,347,264,9470,302,1581,8222,28723,661,659,272,2187,302,264,6172,28725,395,264,15574,8675,304,12446,28725,690,349,835,10842,302,408,1449,28723,415,1335,312,5650,867,264,5255,28725,395,1305,28724,12446,304,767,3969,298,347,5255,26898,404,28723,415,15287,659,2282,737,1395,302,264,5255,28725,304,378,28742,28713,8192,264,26371,442,1335,490,283,369,4674,737,396,10023,18401,395,7153,1220,8508,356,272,18522,28725,5239,378,264,23449,28720,2060,27974,28723,415,5414,349,3181,1007,395,264,7296,11809,5340,28725,8050,7161,272,7399,529,745,4735,302,272,15287,28723,851,3469,349,3917,264,5511,302,7153,1524,5682,298,1347,2210,26671,1197,304,9811,16582,28723,28705],"total_duration":7148311208,"load_duration":2687336958,\n    "prompt_eval_count":1,\n    "prompt_eval_duration":1313448000,\n    "eval_count":151,\n    "eval_duration":3111945000}\n```\n\n### Project Generation\n\n*Generate a new programming project from an ascii or textual description.*\n\n```\n% lmoe what is the recommended layout for a python project with poetry\n With Poetry, a Python packaging and project management tool, a recommended layout for a Python\n project could include the following structure:\n\n myproject/\n ├── pyproject.toml\n ├── README.rst\n ├── requirements.in\n └── src/\n     ├── __init__.py\n     └── mypackage/\n         ├── __init__.py\n         ├── module1.py\n         └── module2.py\n\nIn this layout, the `myproject/` directory contains the root-level project files. The\n`pyproject.toml` file is used for managing dependencies and building your Python package. The\n`README.rst` file is optional, but common, to include documentation about your project. The\n`requirements.in` file lists the external packages required by your project.\n\nThe `src/` directory contains your source code for the project. In this example, there\'s a package\nnamed `mypackage`, which includes an `__init__.py` file and two modules: `module1.py` and\n`module2.py`.\n\nThis is just one suggested layout using Poetry. Depending on your specific project requirements and\npreferences, the layout might vary. Always refer to the [Poetry documentation](https://python-poetry.org/)\nfor more detailed information.\n```\n\nCopy this to the clipboard, and then:\n\n```\n% lmoe --paste "make a project like this for a module called \'alexandria\' with 3 sub modules: \'auth\', \'util\', and \'io\'"\nmkdir alexandria/\ntouch alexandria/pyproject.toml\ntouch alexandria/README.rst\ntouch alexandria/requirements.in\nmkdir alexandria/src/\ntouch alexandria/src/__init__.py\nmkdir alexandria/src/alexandria/\ntouch alexandria/src/alexandria/__init__.py\nmkdir alexandria/src/alexandria/auth/\ntouch alexandria/src/alexandria/auth/__init__.py\nmkdir alexandria/src/alexandria/util/\ntouch alexandria/src/alexandria/util/__init__.py\nmkdir alexandria/src/alexandria/io/\ntouch alexandria/src/alexandria/io/__init__.py\n```\n\n...for a list of runnable shell commands.\n\nComing soon: `lmoe` will offer to run them for you, open them in an editor, or stop.\n\n### Utilities\n\nCapabilities with multiple inputs listed are examples of different ways to activate it.\n\n#### Refresh\n\n*Update local Ollama modelfiles.*\n\nThis should be run any time you add a new expert, modelfile, or\nalter a modelfile template.\n\n```\n% lmoe refresh\n% lmoe update your models\n% lmoe refresh the models\n% lmoe update models\n\nDeleting existing lmoe_classifier...\nUpdating lmoe_classifier...\nDeleting existing lmoe_code...\nUpdating lmoe_code...\nDeleting existing lmoe_project_initialization...\nUpdating lmoe_project_initialization...\nDeleting existing lmoe_general...\nUpdating lmoe_general...\n```\n\n#### Model Listing\n\n*List Ollama metadata on models used internally by `lmoe`.*\n\n```\n% lmoe list\n% lmoe what are your models\n% lmoe list your models\n\n{\'name\': \'lmoe_classifier:latest\', \'model\': \'lmoe_classifier:latest\', \'modified_at\': \'2024-02-05T13:46:49.983916538-08:00\', \'size\': 4109868691, \'digest\': \'576c04e5f9c9e82b2ca14cfd5754ca56610619cddb737a6ca968d064c86bcb68\', \'details\': {\'parent_model\': \'\', \'format\': \'gguf\', \'family\': \'llama\', \'families\': [\'llama\'], \'parameter_size\': \'7B\', \'quantization_level\': \'Q4_0\'}}\n{\'name\': \'lmoe_code:latest\', \'model\': \'lmoe_code:latest\', \'modified_at\': \'2024-02-05T13:46:49.988112317-08:00\', \'size\': 4109866128, \'digest\': \'f387ef329bc0ebd9df25dcc8c4f014bbbe127e6a543c8dfa992a805d71fbbb1e\', \'details\': {\'parent_model\': \'\', \'format\': \'gguf\', \'family\': \'llama\', \'families\': [\'llama\'], \'parameter_size\': \'7B\', \'quantization_level\': \'Q4_0\'}}\n{\'name\': \'lmoe_general:latest\', \'model\': \'lmoe_general:latest\', \'modified_at\': \'2024-02-05T13:46:49.996594585-08:00\', \'size\': 4109867476, \'digest\': \'657788601d06890ac136d61bdecec9e3a8ebff4e9139c5cc0fbfa56377625d25\', \'details\': {\'parent_model\': \'\', \'format\': \'gguf\', \'family\': \'llama\', \'families\': [\'llama\'], \'parameter_size\': \'7B\', \'quantization_level\': \'Q4_0\'}}\n{\'name\': \'lmoe_project_initialization:latest\', \'model\': \'lmoe_project_initialization:latest\', \'modified_at\': \'2024-02-05T13:46:49.991328433-08:00\', \'size\': 4109868075, \'digest\': \'9af2d395e8883910952bee2668d18131206fb5c612bc5d4a207b6637e1bc6907\', \'details\': {\'parent_model\': \'\', \'format\': \'gguf\', \'family\': \'llama\', \'families\': [\'llama\'], \'parameter_size\': \'7B\', \'quantization_level\': \'Q4_0\'}}\n```\n\n## Architecture\n\n`lmoe` is a [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) of\nintelligent agents.\n\n![Legend for an lmoe architecture diagram](https://rybosome.github.io/lmoe/assets/lmoe-architecture-legend.png)\n\nNodes may be one of three types:\n\n*  **Classifier** - Determines how to route a query to a sub-expert\n*  **Action** - Generates a response from a model, or takes some other action\n*  **Library** - Uses an underlying model to interpret intent, or generate part of a response\n\n### Current\n\n![Current architecture of lmoe](https://rybosome.github.io/lmoe/assets/lmoe-architecture-current.png)\n\n`lmoe` is currently very basic. A small classifier routes between a few top-level nodes. Additional nodes not pictured:\n\n * Code: Generates code. Needs to be tuned and hooked to a different code model.\n * Nodes for operational commands like refreshing and listing models\n\n### Future Additions\n\n![Multi level classification](https://rybosome.github.io/lmoe/assets/lmoe-architecture-future.png)\n\nEarly testing suggests that single, large classification prompting with lots of examples scales\npoorly, but nested levels with small classifiers may scale better. For now, there is only one\nclassifier at the root. In the future, `lmoe` will support trees of classification.\n\n![Library dependencies](https://rybosome.github.io/lmoe/assets/lmoe-architecture-future-with-deps.png)\n\nMore advanced functionality can be enabled with library agents which rely on an underlying model to\ndeliver part of a response.\n\nFor instance, understanding filesystem intent - "/Users/me/Documents/document.text",\n"this directory", "somewhere in my downloads folder" - and reading the data can be an intermediate\ntask which allows other agents to function better.\n\nThis would allow simpler usage of, for instance, the image recognition agent. Instead of having to\nbase64 the contents of an image ourselves, we could do:\n\n```\n### THIS IS AN EXAMPLE, NOT A REAL INTERACTION ###\n% lmoe what is in the pic at /Users/me/Pictures/picture.png\nThere is a black and tan dog looking up at the camera with a cute expression on its face. The\nbackground is a colorful blend of autumn leaves.\n```\n\n## Extension Model\n\nNew capabilities can be added to `lmoe` with low overhead. All capabilities, internal and\nuser-defined, are implemented with the same programming model.\n\nAn `Expert` is implemented and registered with the root classifier, and can respond to user queries\nprogrammatically, through a model, or with a mix of both.\n\nTo get started, create a directory structure like this:\n\n```\n% mkdir -p "$HOME/lmoe_plugins/lmoe_plugins"\n```\n\n### All samples\n\nSee the [examples](https://github.com/rybosome/lmoe/main/docs/examples/lmoe_plugins) directory.\n\nHere are some to get started.\n\n### Adding a new expert with a model\n\nLet\'s add an expert which describes the weather in a random city.\n\nFirst, create a modelfile under `$HOME/lmoe_plugins/lmoe_plugins/random_weather.modelfile.txt`.\n\n```\nFROM mistral\nSYSTEM """\nYour job is to summarize a JSON object which has information about the current weather in a given\ncity. You are to give a natural language description of the weather conditions.\n\nHere are the keys of the JSON object.\n\n\'temperature_2m\': The temperature in farenheit\n\'relative_humidity_2m\': The relative humidity percentage\n\'cloud_cover\': The percentage of cloud coverage\n\'wind_speed_10m\': The wind speed in miles per hour\n\'rain\': Rainfall in millimeters\n\'showers\': Showers in millimeters\n\'snowfall\': Snowfall in millimeters\n\'name\': The name of the city\n\'country\': The name of the country\n\'description\': A short description of the weather conditions\n\nI\'ll share some examples.\n\nExample 1)\n\nuser: {\'temperature_2m\': 90.1, \'relative_humidity_2m\': 64, \'cloud_cover\': 46, \'wind_speed_10m\': 12.4, \'rain\': 0.0, \'showers\': 0.0, \'snowfall\': 0.0, \'city\': \'Chigorodó\', \'country\': \'Colombia\', \'description\': \'Partly cloudy\'}\nagent: It is currently 90 degrees and partly cloudy in Chigorodó, Colombia, with no recent precipitation.\n\nExample 2)\nuser: {\'temperature_2m\': 74.0, \'relative_humidity_2m\': 79, \'cloud_cover\': 42, \'wind_speed_10m\': 4.1, \'rain\': 0.0, \'showers\': 0.0, \'snowfall\': 0.0, \'city\': \'Boa Esperança\', \'country\': \'Brazil\', \'description\': \'Mainly clear\'}\nagent: The weather in Boa Esperança, Brazil is mainly clear. It is 74 degrees, with winds around 4 miles per hour.\n\nExample 3)\nuser: {\'temperature_2m\': 65.2, \'relative_humidity_2m\': 50, \'cloud_cover\': 67, \'wind_speed_10m\': 4.9, \'rain\': 0.0, \'showers\': 0.0, \'snowfall\': 0.0, \'city\': \'Sánchez Carrión Province\', \'country\': \'Peru\', \'description\': \'Partly cloudy\'}\nagent: It is a partly cloudy day in Sánchez Carrión Province, Peru, with 67% cloud coverage. It is currently 65 degrees, with winds around 5 miles per hour.\n\nExample 4)\nuser: {\'temperature_2m\': 75.1, \'relative_humidity_2m\': 71, \'cloud_cover\': 83, \'wind_speed_10m\': 6.2, \'rain\': 0.0, \'showers\': 0.0, \'snowfall\': 0.0, \'city\': \'Ribeirão das Neves\', \'country\': \'Brazil\', \'description\': \'Overcast\'}\nagent: Ribeirão das Neves, Brazil is currently 75 degrees and overcast. There has been no recent precipitation.\n"""\n```\n\nThen, let\'s create an expert class to generate this JSON object and pass it to the summarizer at `$HOME/lmoe_plugins/lmoe_plugins/random_weather.py`.\n\n```python\nimport json\nimport ollama\nimport os\nimport random\nimport requests\n\nfrom dataclasses import asdict, dataclass\nfrom enum import Enum\nfrom lmoe.api.lmoe_query import LmoeQuery\nfrom lmoe.api.model import Model\nfrom lmoe.api.model_expert import ModelExpert\nfrom lmoe.api.ollama_client import stream\nfrom lmoe.framework.expert_registry import expert\n\n\n@dataclass(frozen=True)\nclass City:\n    """Basic information about a city."""\n\n    name: str\n    country: str\n    latitude: float\n    longitude: float\n\n    """URL for a service which returns information on a city at the given index."""\n    _RANDOM_CITY_URL_TEMPLATE = "http://geodb-free-service.wirefreethought.com/v1/geo/cities?limit=1&offset={0}&hateoasMode=off"\n\n    """The maximum value returning a city instance for the above service."""\n    _MAX_RANDOM_CITY_INDEX = 28177\n\n    @classmethod\n    def random(cls) -> "City":\n        """Returns information on a random city."""\n        random_number = random.randint(1, cls._MAX_RANDOM_CITY_INDEX)\n        r = requests.get(cls._RANDOM_CITY_URL_TEMPLATE.format(random_number))\n        json = r.json()["data"][0]\n        return City(\n            name=json["city"],\n            country=json["country"],\n            latitude=json["latitude"],\n            longitude=json["longitude"],\n        )\n\n\nclass WMOInterpretationCode(Enum):\n    """Partial implementation of World Meteorological Organization codes describing weather conditions.\n\n    https://www.nodc.noaa.gov/archive/arc0021/0002199/1.1/data/0-data/HTML/WMO-CODE/WMO4677.HTM\n    """\n\n    CLEAR_SKY = 0\n    MAINLY_CLEAR = 1\n    PARTLY_CLOUDY = 2\n    OVERCAST = 3\n    FOG = 45\n    DEPOSITING_RIME_FOG = 48\n    LIGHT_DRIZZLE = 51\n    MODERATE_DRIZZLE = 53\n    DENSE_DRIZZLE = 55\n    LIGHT_FREEZING_DRIZZLE = 56\n    DENSE_FREEZING_DRIZZLE = 57\n    LIGHT_RAIN = 61\n    MODERATE_RAIN = 63\n    HEAVY_RAIN = 65\n    LIGHT_FREEZING_RAIN = 66\n    HEAVY_FREEZING_RAIN = 67\n    LIGHT_SNOW = 71\n    MODERATE_SNOW = 73\n    HEAVY_SNOW = 75\n    SNOW_GRAINS = 77\n    LIGHT_RAIN_SHOWERS = 80\n    MODERATE_RAIN_SHOWERS = 81\n    HEAVY_RAIN_SHOWERS = 82\n    LIGHT_SNOW_SHOWERS = 85\n    HEAVY_SNOW_SHOWERS = 86\n    THUNDERSTORMS = 95\n    THUNDERSTORMS_WITH_SLIGHT_HAIL = 96\n    THUNDERSTORMS_WITH_HEAVY_HAIL = 99\n\n    @classmethod\n    def describe(cls, code: int) -> str:\n        """Gives a title cased description of an int code if it exists, or an empty string."""\n        return (\n            cls(code).name.replace("_", " ").title() if code in cls.__members__ else ""\n        )\n\n\n@dataclass(frozen=True)\nclass WeatherReport:\n    """A description of weather conditions in a particular moment - (only current supported)."""\n    city: City\n    temperature_2m: str\n    relative_humidity_2m: int\n    cloud_cover: int\n    wind_speed_10m: float\n    rain: float\n    showers: float\n    snowfall: float\n    weather_description: str\n\n    """Base URL of the https://open-meteo.com/ current forecast API."""\n    _WEATHER_API_URL = "https://api.open-meteo.com/v1/forecast"\n\n    def json(self) -> str:\n        """Returns a JSON string."""\n        partial_dict = asdict(self)\n        return json.dumps(partial_dict)\n\n    @classmethod\n    def current(cls, city: City) -> "WeatherReport":\n        """Current weather conditions for the given city."""\n        r = requests.get(\n            cls._WEATHER_API_URL,\n            params={\n                "latitude": city.latitude,\n                "longitude": city.longitude,\n                "current": "temperature_2m,relative_humidity_2m,cloud_cover,wind_speed_10m,rain,showers,snowfall,weather_code",\n                "temperature_unit": "fahrenheit",\n            },\n        )\n        response = r.json()["current"]\n        return WeatherReport(\n            city=city,\n            temperature_2m=response["temperature_2m"],\n            relative_humidity_2m=response["relative_humidity_2m"],\n            cloud_cover=response["cloud_cover"],\n            wind_speed_10m=response["wind_speed_10m"],\n            rain=response["rain"],\n            showers=response["showers"],\n            snowfall=response["snowfall"],\n            weather_description=WMOInterpretationCode.describe(\n                response["weather_code"]\n            ),\n        )\n\nclass RandomWeatherModel(Model):\n    """A model instructed to summarize JSON blobs about weather in natural language."""\n\n    def __init__(self):\n        super(RandomWeatherModel, self).__init__("RANDOM_WEATHER")\n\n    @classmethod\n    def modelfile_name(cls):\n        home_dir = os.environ.get("HOME")\n        return f"{home_dir}/lmoe_plugins/lmoe_plugins/random_weather.modelfile.txt"\n\n    def modelfile_contents(self):\n        with open(self.modelfile_name(), "r") as file:\n            return file.read()\n\n\n@expert\nclass RandomWeather(ModelExpert):\n    """An expert which retrieves a random weather report in JSON and summarizes it."""\n\n    def __init__(self):\n        super(RandomWeather, self).__init__(RandomWeatherModel())\n\n    @classmethod\n    def name(cls):\n        return "RANDOM_WEATHER"\n\n    def description(self):\n        return "Describes the weather in a random city."\n\n    def example_queries(self):\n        return [\n            "tell me the weather in a random city",\n            "random weather",\n            "give me a random weather report",\n            "random weather report",\n        ]\n\n    def generate(self, lmoe_query: LmoeQuery):\n        weather_report = WeatherReport.current(City.random())\n\n        for chunk in stream(model=self.model, prompt=weather_report.json()):\n            print(chunk, end="", flush=True)\n        print("")\n```\n\nRefresh, and try out your new capability.\n\n```\n% lmoe refresh\n...\n\n% lmoe random weather\nIt is currently a chilly 19 degrees in Konkovo District, Russia, with overcast conditions and high\nrelative humidity of 90%. Winds are blowing around 9.2 miles per hour.\n\n% lmoe random weather\nIn Arbon District, Switzerland, the weather is currently overcast with a temperature of 43.5\ndegrees Fahrenheit and a relative humidity of 75%. The winds are blowing at a speed of 7.4 miles\nper hour. There has been no recent precipitation reported.\n```\n\n### Overriding a native expert\n\nLet\'s override the `GENERAL` expert with a less helpful variant.\n\n```\n% lmoe --classify why is the sky blue\nGENERAL\n% lmoe why is the sky blue\nThe scattering of sunlight in the atmosphere causes the sky to appear blue. This occurs because\nshorter wavelengths of light, such as blue and violet, are more likely to be scattered than longer\nwavelengths, like red or orange. As a result, the sky predominantly reflects and scatters blue\nlight, making it appear blue during a clear day.\n```\n\nStart by creating your new expert under `$HOME/lmoe_plugins/lmoe_plugins/general_rude.py`, and\ninherit from the base expert you wish to override.\n\n```python\nfrom lmoe.api.lmoe_query import LmoeQuery\nfrom lmoe.experts.general import General\nfrom lmoe.framework.expert_registry import expert\n\n\n@expert\nclass GeneralRude(General):\n\n    @classmethod\n    def has_model(cls):\n        return False\n\n    def generate(self, lmoe_query: LmoeQuery):\n        print("I\'m not going to dignify that with a response.")\n```\n\nRefresh `lmoe` and try it out!\n\n```\n% lmoe refresh\n...\n% lmoe --classify why is the sky blue\nGENERAL\n% lmoe why is the sky blue\nI\'m not going to dignify that with a response.\n```\n\n### Depending on natively provided dependencies\n\nIf you\'d like to add commands which depend on existing experts or other core elements of the `lmoe`\nframework, you can do so.\n\nThis relies on the [injector](https://pypi.org/project/injector/) framework.\n\nFirst, create a new expert under `$HOME/lmoe_plugins/lmoe_plugins/print_args.py`.\n\n```python\nfrom injector import inject\nfrom lmoe.api.base_expert import BaseExpert\nfrom lmoe.api.lmoe_query import LmoeQuery\nfrom lmoe.framework.expert_registry import expert\n\nimport argparse\n\n\n@expert\nclass PrintArgs(BaseExpert):\n\n    def __init__(self, parsed_args: argparse.Namespace):\n        self.parsed_args = parsed_args\n\n    @classmethod\n    def name(cls):\n        return "PRINT_ARGS"\n\n    @classmethod\n    def has_model(cls):\n        return False\n\n    def description(self):\n        return "Prints the commandline arguments that were used to invoke lmoe."\n\n    def example_queries(self):\n        return [\n            "print args",\n            "print the commandline args",\n        ]\n\n    def generate(self, lmoe_query: LmoeQuery):\n        print("These are the arguments that were passed to me:")\n        print(self.parsed_args)\n```\n\nThen, create a [Module](https://injector.readthedocs.io/en/latest/api.html#injector.Module) under `$HOME/lmoe_plugins/lmoe_plugins/lmoe_plugin_module.py`.\n\n```python\nfrom injector import Module, provider, singleton\nfrom lmoe.framework.plugin_module_registry import plugin_module\nfrom lmoe_plugins.print_args import PrintArgs\n\nimport argparse\n\n\n@plugin_module\nclass LmoePluginModule(Module):\n\n    @singleton\n    @provider\n    def provide_print_args(self, parsed_args: argparse.Namespace) -> PrintArgs:\n        return PrintArgs(parsed_args)\n```\n\nRefresh `lmoe` and try your new capability.\n\n```\n% lmoe refresh\n...\n% lmoe print args\nThese are the arguments that were passed to me:\nNamespace(query=[\'print\', \'args\'], paste=False, classify=False, classifier_modelfile=False, refresh=False)\n```\n\n## Status\n\nVersion 0.3.12\n\nSupports the following core experts:\n\n * general\n * image recognition\n * project initialization\n * code\n\nTuning of each is needed.\n\nThis is currently a very basic implementation, but may be useful to others.\n\nThe extension model is working, but is not guaranteed to be a stable API.\n\n### Upcoming features\n\n* error handling\n* persisted context (i.e. memory, chat-like experience without a formal chat interface)\n* configurability\n* tests\n* further tuning of classification, code generation, and project initialization\n* dry-run for mutating actions, ability to execute mutating actions\n* RAG agent\n* many more commands\n  * filesystem interaction\n    * finding file contents from various queries (specific file path, fuzzy description, "this directory", etc.)\n  * executors for existing bash commands\n    * awk\n    * curl\n  * API clients\n    * weather\n    * wikipedia\n* openAI API integration\n\n## Lmoe Armadillo\n\nThe avatar of `lmoe` is Lmoe Armadillo, a cybernetic [Cingulata](https://en.wikipedia.org/wiki/Cingulata)\nwho is ready to dig soil and execute toil.\n\nLmoe Armadillo is a curious critter who assumes many different manifestations.\n\n![Lmoe\'s default avatar against a lit background](https://rybosome.github.io/lmoe/assets/lmoe-armadillo-alt4-380px.jpg)\n![An alternative Lmoe with a cute face](https://rybosome.github.io/lmoe/assets/lmoe-armadillo-alt1-380px.jpg)\n![A blue-nosed Lmoe Armadillo](https://rybosome.github.io/lmoe/assets/lmoe-armadillo-alt3-380px.jpg)\n![A realistic Lmoe Armadillo against a surrealist backdrop](https://rybosome.github.io/lmoe/assets/lmoe-armadillo-alt2-380px.jpg)\n',
    'author': 'Ryan Eiger',
    'author_email': 'ryebosome@gmail.com',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'None',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.9,<4.0',
}


setup(**setup_kwargs)
