Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</p>

ShellOracle is an innovative terminal utility designed for intelligent shell command generation, bringing a new level of
efficiency to your command-line interactions. ShellOracle currently supports Ollama, OpenAI, Deepseek, LocalAI, and Grok!
efficiency to your command-line interactions. ShellOracle currently supports Ollama, llmman, OpenAI, Deepseek, LocalAI, and Grok!

![ShellOracle](https://i.imgur.com/lqTW1lO.gif)

Expand Down Expand Up @@ -93,6 +93,16 @@ ollama pull qwen2.5-coder

Refer to the [Ollama docs](https://ollama.ai) for installation, available models, and usage.

### llmman

[llmman](https://github.com/llmmanorg/llmman) serves the Ollama API on port 17434. Start it and pull the model you
chose in the configure step. For example, if you chose `gemma4`, run:

```shell
llmman serve
llmman pull gemma4
```

### OpenAI

To use ShellOracle with OpenAI's models, create an [API key](https://platform.openai.com/account/api-keys). Edit
Expand Down
2 changes: 2 additions & 0 deletions src/shelloracle/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def __get__(self, instance: Provider, owner: type[Provider]) -> T:
def _providers() -> dict[str, type[Provider]]:
from shelloracle.providers.deepseek import Deepseek
from shelloracle.providers.google import Google
from shelloracle.providers.llmman import Llmman
from shelloracle.providers.localai import LocalAI
from shelloracle.providers.ollama import Ollama
from shelloracle.providers.openai import OpenAI
Expand All @@ -92,6 +93,7 @@ def _providers() -> dict[str, type[Provider]]:

return {
Ollama.name: Ollama,
Llmman.name: Llmman,
OpenAI.name: OpenAI,
OpenAICompat.name: OpenAICompat,
LocalAI.name: LocalAI,
Expand Down
13 changes: 13 additions & 0 deletions src/shelloracle/providers/llmman.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from __future__ import annotations

from shelloracle.providers import Setting
from shelloracle.providers.ollama import Ollama


class Llmman(Ollama):
"""llmman (https://github.com/llmmanorg/llmman) serves the Ollama API on port 17434."""

name = "llmman"

port = Setting(default=17434)
model = Setting(default="gemma4")
2 changes: 1 addition & 1 deletion src/shelloracle/providers/ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ async def generate(self, prompt: str) -> AsyncIterator[str]:
raise ProviderError(response["error"])
yield response["response"]
except (httpx.HTTPError, httpx.StreamError) as e:
msg = f"Something went wrong while querying Ollama: {e}"
msg = f"Something went wrong while querying {self.name}: {e}"
raise ProviderError(msg) from e
54 changes: 54 additions & 0 deletions tests/providers/test_llmman.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import pytest
from pytest_httpx import IteratorStream

from shelloracle.config import Configuration
from shelloracle.providers.llmman import Llmman


class TestLlmman:
@pytest.fixture
def llmman_config(self):
config = {
"shelloracle": {"provider": "llmman"},
"provider": {"llmman": {"host": "localhost", "port": 17434, "model": "gemma4"}},
}
return Configuration(config)

@pytest.fixture
def llmman_instance(self, llmman_config):
return Llmman(llmman_config)

def test_name(self):
assert Llmman.name == "llmman"

def test_host(self, llmman_instance):
assert llmman_instance.host == "localhost"

def test_port(self, llmman_instance):
assert llmman_instance.port == 17434

def test_model(self, llmman_instance):
assert llmman_instance.model == "gemma4"

def test_endpoint(self, llmman_instance):
assert llmman_instance.endpoint == "http://localhost:17434/api/generate"

def test_defaults(self):
instance = Llmman(Configuration({"shelloracle": {"provider": "llmman"}, "provider": {}}))
assert instance.endpoint == "http://localhost:17434/api/generate"
assert instance.model == "gemma4"

@pytest.mark.asyncio
async def test_generate(self, llmman_instance, httpx_mock):
responses = [
b'{"response": "cat"}\n',
b'{"response": " test"}\n',
b'{"response": "."}\n',
b'{"response": "py"}\n',
b'{"response": ""}\n',
]
httpx_mock.add_response(stream=IteratorStream(responses))
result = ""
async for response in llmman_instance.generate(""):
result += response
assert result == "cat test.py"