kader 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cli/README.md +169 -0
- cli/__init__.py +5 -0
- cli/__main__.py +6 -0
- cli/app.py +707 -0
- cli/app.tcss +664 -0
- cli/utils.py +68 -0
- cli/widgets/__init__.py +13 -0
- cli/widgets/confirmation.py +309 -0
- cli/widgets/conversation.py +55 -0
- cli/widgets/loading.py +59 -0
- kader/__init__.py +22 -0
- kader/agent/__init__.py +8 -0
- kader/agent/agents.py +126 -0
- kader/agent/base.py +927 -0
- kader/agent/logger.py +170 -0
- kader/config.py +139 -0
- kader/memory/__init__.py +66 -0
- kader/memory/conversation.py +409 -0
- kader/memory/session.py +385 -0
- kader/memory/state.py +211 -0
- kader/memory/types.py +116 -0
- kader/prompts/__init__.py +9 -0
- kader/prompts/agent_prompts.py +27 -0
- kader/prompts/base.py +81 -0
- kader/prompts/templates/planning_agent.j2 +26 -0
- kader/prompts/templates/react_agent.j2 +18 -0
- kader/providers/__init__.py +9 -0
- kader/providers/base.py +581 -0
- kader/providers/mock.py +96 -0
- kader/providers/ollama.py +447 -0
- kader/tools/README.md +483 -0
- kader/tools/__init__.py +130 -0
- kader/tools/base.py +955 -0
- kader/tools/exec_commands.py +249 -0
- kader/tools/filesys.py +650 -0
- kader/tools/filesystem.py +607 -0
- kader/tools/protocol.py +456 -0
- kader/tools/rag.py +555 -0
- kader/tools/todo.py +210 -0
- kader/tools/utils.py +456 -0
- kader/tools/web.py +246 -0
- kader-0.1.5.dist-info/METADATA +321 -0
- kader-0.1.5.dist-info/RECORD +45 -0
- kader-0.1.5.dist-info/WHEEL +4 -0
- kader-0.1.5.dist-info/entry_points.txt +2 -0
kader/tools/web.py
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Web Tools for Agentic Operations.
|
|
3
|
+
|
|
4
|
+
Provides web search and fetch capabilities using Ollama's native API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from .base import (
|
|
11
|
+
BaseTool,
|
|
12
|
+
ParameterSchema,
|
|
13
|
+
ToolCategory,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
import ollama
|
|
18
|
+
except ImportError:
|
|
19
|
+
ollama = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WebSearchTool(BaseTool[list[dict[str, Any]]]):
|
|
23
|
+
"""
|
|
24
|
+
Tool to search the web using Ollama's search capability.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
"""Initialize the web search tool."""
|
|
29
|
+
super().__init__(
|
|
30
|
+
name="web_search",
|
|
31
|
+
description=(
|
|
32
|
+
"Search the web for information. Returns a list of relevant "
|
|
33
|
+
"results with titles, descriptions, and URLs."
|
|
34
|
+
),
|
|
35
|
+
parameters=[
|
|
36
|
+
ParameterSchema(
|
|
37
|
+
name="query",
|
|
38
|
+
type="string",
|
|
39
|
+
description="Search query",
|
|
40
|
+
),
|
|
41
|
+
ParameterSchema(
|
|
42
|
+
name="limit",
|
|
43
|
+
type="integer",
|
|
44
|
+
description="Number of results to return (max 10)",
|
|
45
|
+
required=False,
|
|
46
|
+
default=5,
|
|
47
|
+
minimum=1,
|
|
48
|
+
maximum=10,
|
|
49
|
+
),
|
|
50
|
+
],
|
|
51
|
+
category=ToolCategory.WEB,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def execute(self, query: str, limit: int = 5) -> list[dict[str, Any]]:
|
|
55
|
+
"""
|
|
56
|
+
Execute web search.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
query: Search query
|
|
60
|
+
limit: Number of results (default 5)
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
"""
|
|
64
|
+
if ollama is None:
|
|
65
|
+
raise ImportError(
|
|
66
|
+
"ollama is required for web tools. Install it with: uv add ollama"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
# Note: Ollama python lib uses 'limit' or just implicitly returns results
|
|
71
|
+
# The exact signature might vary as it's experimental, but based on docs:
|
|
72
|
+
# results = ollama.web_search(query=query)
|
|
73
|
+
# We'll try to slice manually if limit is not supported directly
|
|
74
|
+
|
|
75
|
+
# Using getattr to avoid static analysis errors if method is missing in older stub
|
|
76
|
+
search_func = getattr(ollama, "web_search", None)
|
|
77
|
+
|
|
78
|
+
if not search_func:
|
|
79
|
+
# Fallback or error if not available
|
|
80
|
+
# Assuming duckduckgo-search as fallback if allowed, but plan said Ollama first
|
|
81
|
+
# Let's check if we can import duckduckgo search as a robust fallback
|
|
82
|
+
# since "ollama.web_search" might be a hosted-only feature in some contexts.
|
|
83
|
+
# But per instruction, we use Ollama.
|
|
84
|
+
|
|
85
|
+
# If function is missing, raise clear error
|
|
86
|
+
raise NotImplementedError(
|
|
87
|
+
"ollama.web_search is not available in the installed library version. "
|
|
88
|
+
"Ensure 'ollama>=0.6.0' is installed."
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Execute search
|
|
92
|
+
response = search_func(query=query)
|
|
93
|
+
|
|
94
|
+
# Parse results
|
|
95
|
+
# Response might be a dict, an object with .results, or a list
|
|
96
|
+
results = []
|
|
97
|
+
|
|
98
|
+
if isinstance(response, dict):
|
|
99
|
+
results = response.get("results", [])
|
|
100
|
+
elif hasattr(response, "results"):
|
|
101
|
+
results = response.results
|
|
102
|
+
elif hasattr(response, "__dict__") and "results" in response.__dict__:
|
|
103
|
+
# Handle WebSearchResult object specifically
|
|
104
|
+
results = response.results
|
|
105
|
+
elif isinstance(response, list):
|
|
106
|
+
results = response
|
|
107
|
+
else:
|
|
108
|
+
# If it's some other object that behaves like a dict but failed above checks
|
|
109
|
+
try:
|
|
110
|
+
results = response["results"]
|
|
111
|
+
except (TypeError, KeyError, AttributeError):
|
|
112
|
+
# As a last resort, assume the response itself might be the iterable result
|
|
113
|
+
results = response
|
|
114
|
+
|
|
115
|
+
# Type check results to ensure it's a list (or iterable)
|
|
116
|
+
if not isinstance(results, list):
|
|
117
|
+
# Try to convert to list if it's iterable
|
|
118
|
+
try:
|
|
119
|
+
results = list(results)
|
|
120
|
+
except TypeError:
|
|
121
|
+
# If not iterable, wrap it or return empty
|
|
122
|
+
results = []
|
|
123
|
+
|
|
124
|
+
# Ensure results are JSON serializable
|
|
125
|
+
serializable_results = []
|
|
126
|
+
for item in results[:limit]:
|
|
127
|
+
if isinstance(item, (str, int, float, bool, type(None))):
|
|
128
|
+
serializable_results.append(item)
|
|
129
|
+
elif isinstance(item, dict):
|
|
130
|
+
# Ensure all dict values are serializable
|
|
131
|
+
serializable_dict = {}
|
|
132
|
+
for k, v in item.items():
|
|
133
|
+
try:
|
|
134
|
+
json.dumps(v) # Test if serializable
|
|
135
|
+
serializable_dict[k] = v
|
|
136
|
+
except TypeError:
|
|
137
|
+
serializable_dict[k] = str(
|
|
138
|
+
v
|
|
139
|
+
) # Convert non-serializable to string
|
|
140
|
+
serializable_results.append(serializable_dict)
|
|
141
|
+
else:
|
|
142
|
+
# Convert any other type to string representation
|
|
143
|
+
serializable_results.append(str(item))
|
|
144
|
+
|
|
145
|
+
return serializable_results
|
|
146
|
+
|
|
147
|
+
except NotImplementedError:
|
|
148
|
+
raise
|
|
149
|
+
except Exception as e:
|
|
150
|
+
# Handle specific Ollama errors
|
|
151
|
+
raise RuntimeError(f"Web search failed: {str(e)}")
|
|
152
|
+
|
|
153
|
+
async def aexecute(self, query: str, limit: int = 5) -> list[dict[str, Any]]:
|
|
154
|
+
"""Async version of execute."""
|
|
155
|
+
import asyncio
|
|
156
|
+
|
|
157
|
+
return await asyncio.to_thread(self.execute, query, limit)
|
|
158
|
+
|
|
159
|
+
def get_interruption_message(self, query: str, **kwargs) -> str:
|
|
160
|
+
"""Get interruption message for user confirmation."""
|
|
161
|
+
return f"execute web_search: {query}"
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class WebFetchTool(BaseTool[str]):
|
|
165
|
+
"""
|
|
166
|
+
Tool to fetch and extract text content from a web page.
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
def __init__(self) -> None:
|
|
170
|
+
"""Initialize the web fetch tool."""
|
|
171
|
+
super().__init__(
|
|
172
|
+
name="web_fetch",
|
|
173
|
+
description=(
|
|
174
|
+
"Fetch and extract readable text content from a URL. "
|
|
175
|
+
"Useful for reading documentation, articles, or web pages found via search."
|
|
176
|
+
),
|
|
177
|
+
parameters=[
|
|
178
|
+
ParameterSchema(
|
|
179
|
+
name="url",
|
|
180
|
+
type="string",
|
|
181
|
+
description="URL of the page to fetch",
|
|
182
|
+
),
|
|
183
|
+
],
|
|
184
|
+
category=ToolCategory.WEB,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
def execute(self, url: str) -> str:
|
|
188
|
+
"""
|
|
189
|
+
Fetch web page content.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
url: URL to fetch
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Extracted text content
|
|
196
|
+
"""
|
|
197
|
+
if ollama is None:
|
|
198
|
+
raise ImportError(
|
|
199
|
+
"ollama is required for web tools. Install it with: uv add ollama"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
fetch_func = getattr(ollama, "web_fetch", None)
|
|
204
|
+
|
|
205
|
+
if not fetch_func:
|
|
206
|
+
raise NotImplementedError(
|
|
207
|
+
"ollama.web_fetch is not available in the installed library version."
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
response = fetch_func(url=url)
|
|
211
|
+
|
|
212
|
+
# Return content (assuming response implies content string or dict with content)
|
|
213
|
+
if isinstance(response, dict):
|
|
214
|
+
content = response.get("content", str(response))
|
|
215
|
+
else:
|
|
216
|
+
content = str(response)
|
|
217
|
+
|
|
218
|
+
# Ensure the content is JSON serializable
|
|
219
|
+
try:
|
|
220
|
+
json.dumps(content) # Test if serializable
|
|
221
|
+
return content
|
|
222
|
+
except TypeError:
|
|
223
|
+
return str(content) # Convert non-serializable to string
|
|
224
|
+
|
|
225
|
+
except NotImplementedError:
|
|
226
|
+
raise
|
|
227
|
+
except Exception as e:
|
|
228
|
+
raise RuntimeError(f"Web fetch failed: {str(e)}")
|
|
229
|
+
|
|
230
|
+
async def aexecute(self, url: str) -> str:
|
|
231
|
+
"""Async version of execute."""
|
|
232
|
+
import asyncio
|
|
233
|
+
|
|
234
|
+
return await asyncio.to_thread(self.execute, url)
|
|
235
|
+
|
|
236
|
+
def get_interruption_message(self, url: str, **kwargs) -> str:
|
|
237
|
+
"""Get interruption message for user confirmation."""
|
|
238
|
+
return f"execute web_fetch: {url}"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def get_web_tools() -> list[BaseTool]:
|
|
242
|
+
"""Get all web tools."""
|
|
243
|
+
return [
|
|
244
|
+
WebSearchTool(),
|
|
245
|
+
WebFetchTool(),
|
|
246
|
+
]
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kader
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: kader coding agent
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: faiss-cpu>=1.9.0
|
|
7
|
+
Requires-Dist: jinja2>=3.1.6
|
|
8
|
+
Requires-Dist: loguru>=0.7.3
|
|
9
|
+
Requires-Dist: ollama>=0.6.1
|
|
10
|
+
Requires-Dist: outdated>=0.2.2
|
|
11
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
12
|
+
Requires-Dist: tenacity>=9.1.2
|
|
13
|
+
Requires-Dist: textual[syntax]>=6.8.0
|
|
14
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
15
|
+
Requires-Dist: wcmatch>=10.1
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Kader
|
|
19
|
+
|
|
20
|
+
Kader is an intelligent coding agent designed to assist with software development tasks. It provides a comprehensive framework for building AI-powered agents with advanced reasoning capabilities and tool integration.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- 🤖 **AI-powered Code Assistance** - Using Ollama for local LLM execution
|
|
25
|
+
- 🖥️ **Interactive CLI** - Modern TUI interface built with Textual
|
|
26
|
+
- 🛠️ **Tool Integration** - File system, command execution, web search, and more
|
|
27
|
+
- 🧠 **Memory Management** - State persistence and conversation history
|
|
28
|
+
- 🔁 **Session Management** - Save and load conversation sessions
|
|
29
|
+
- 🎨 **Theming** - Multiple color themes for the CLI interface
|
|
30
|
+
- ⌨️ **Keyboard Shortcuts** - Efficient navigation and operations
|
|
31
|
+
- 📝 **YAML Configuration** - Agent configuration via YAML files
|
|
32
|
+
- 🔄 **ReAct Agent Framework** - Reasoning and Acting agent architecture
|
|
33
|
+
- 🗂️ **File System Tools** - Read, write, search, and edit files
|
|
34
|
+
- 🔍 **Planning Agent** - Task planning and execution capabilities
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
### Prerequisites
|
|
39
|
+
|
|
40
|
+
- Python 3.11 or higher
|
|
41
|
+
- [Ollama](https://ollama.ai/) running locally to use LLMs
|
|
42
|
+
- [uv](https://docs.astral.sh/uv/) package manager (recommended) or [pip](https://pypi.org/project/pip/)
|
|
43
|
+
|
|
44
|
+
### Using uv (recommended)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Clone the repository
|
|
48
|
+
git clone https://github.com/your-repo/kader.git
|
|
49
|
+
cd kader
|
|
50
|
+
|
|
51
|
+
# Install dependencies with uv
|
|
52
|
+
uv sync
|
|
53
|
+
|
|
54
|
+
# Run the CLI
|
|
55
|
+
uv run python -m cli
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Using pip
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Clone the repository
|
|
62
|
+
git clone https://github.com/your-repo/kader.git
|
|
63
|
+
cd kader
|
|
64
|
+
|
|
65
|
+
# Install in development mode
|
|
66
|
+
pip install -e .
|
|
67
|
+
|
|
68
|
+
# Run the CLI
|
|
69
|
+
python -m cli
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Quick Start
|
|
73
|
+
|
|
74
|
+
### Running the CLI
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Run the Kader CLI using uv
|
|
78
|
+
uv run python -m cli
|
|
79
|
+
|
|
80
|
+
# Or using pip
|
|
81
|
+
python -m cli
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### First Steps in CLI
|
|
85
|
+
|
|
86
|
+
Once the CLI is running:
|
|
87
|
+
|
|
88
|
+
1. Type any question to start chatting with the agent
|
|
89
|
+
2. Use `/help` to see available commands
|
|
90
|
+
3. Use `/models` to check available models
|
|
91
|
+
4. Use `/theme` to cycle through color themes
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
When the kader module is imported for the first time, it automatically:
|
|
96
|
+
1. Creates a `.kader` directory in your home directory (`~/.kader` on Unix systems, `%USERPROFILE%\.kader` on Windows)
|
|
97
|
+
2. Creates a `.env` file with the required configuration (including `OLLAMA_API_KEY=''`)
|
|
98
|
+
3. Loads all environment variables from the `.env` file into the application environment
|
|
99
|
+
|
|
100
|
+
### Environment Variables
|
|
101
|
+
|
|
102
|
+
The application automatically loads environment variables from `~/.kader/.env`:
|
|
103
|
+
- `OLLAMA_API_KEY`: API key for Ollama service (default: empty)
|
|
104
|
+
- Additional variables can be added to the `.env` file and will be automatically loaded
|
|
105
|
+
|
|
106
|
+
### Memory and Sessions
|
|
107
|
+
|
|
108
|
+
Kader stores data in `~/.kader/`:
|
|
109
|
+
- Sessions: `~/.kader/sessions/`
|
|
110
|
+
- Configuration: `~/.kader/`
|
|
111
|
+
- Memory files: `~/.kader/memory/`
|
|
112
|
+
|
|
113
|
+
## CLI Commands
|
|
114
|
+
|
|
115
|
+
| Command | Description |
|
|
116
|
+
|---------|-------------|
|
|
117
|
+
| `/help` | Show command reference |
|
|
118
|
+
| `/models` | Show available Ollama models |
|
|
119
|
+
| `/theme` | Cycle color themes |
|
|
120
|
+
| `/clear` | Clear conversation |
|
|
121
|
+
| `/save` | Save current session |
|
|
122
|
+
| `/load <id>` | Load a saved session |
|
|
123
|
+
| `/sessions` | List saved sessions |
|
|
124
|
+
| `/refresh` | Refresh file tree |
|
|
125
|
+
| `/exit` | Exit the CLI |
|
|
126
|
+
|
|
127
|
+
### Keyboard Shortcuts
|
|
128
|
+
|
|
129
|
+
| Shortcut | Action |
|
|
130
|
+
|----------|--------|
|
|
131
|
+
| `Ctrl+Q` | Quit |
|
|
132
|
+
| `Ctrl+L` | Clear conversation |
|
|
133
|
+
| `Ctrl+T` | Cycle theme |
|
|
134
|
+
| `Ctrl+S` | Save session |
|
|
135
|
+
| `Ctrl+R` | Refresh file tree |
|
|
136
|
+
| `Tab` | Navigate panels |
|
|
137
|
+
|
|
138
|
+
## Project Structure
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
kader/
|
|
142
|
+
├── cli/ # Interactive command-line interface
|
|
143
|
+
│ ├── app.py # Main application entry point
|
|
144
|
+
│ ├── app.tcss # Textual CSS for styling
|
|
145
|
+
│ ├── utils.py # Utility functions and constants
|
|
146
|
+
│ ├── widgets/ # Custom Textual widgets
|
|
147
|
+
│ │ ├── conversation.py # Chat display widget
|
|
148
|
+
│ │ ├── loading.py # Loading spinner widget
|
|
149
|
+
│ │ └── confirmation.py # Tool/model selection widgets
|
|
150
|
+
│ └── README.md # CLI documentation
|
|
151
|
+
├── examples/ # Example implementations
|
|
152
|
+
│ ├── memory_example.py # Memory management examples
|
|
153
|
+
│ ├── ollama_example.py # Ollama provider examples
|
|
154
|
+
│ ├── react_agent_example.py # ReAct agent examples
|
|
155
|
+
│ ├── planning_agent_example.py # Planning agent examples
|
|
156
|
+
│ ├── python_developer/ # Python expert agent example
|
|
157
|
+
│ ├── todo_agent/ # Todo management agent example
|
|
158
|
+
│ └── README.md # Examples documentation
|
|
159
|
+
├── kader/ # Core framework
|
|
160
|
+
│ ├── agent/ # Agent implementations
|
|
161
|
+
│ ├── memory/ # Memory management
|
|
162
|
+
│ ├── providers/ # LLM providers
|
|
163
|
+
│ ├── tools/ # Tools and utilities
|
|
164
|
+
│ └── prompts/ # Prompt templates
|
|
165
|
+
├── pyproject.toml # Project dependencies
|
|
166
|
+
├── README.md # This file
|
|
167
|
+
└── uv.lock # Dependency lock file
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Core Components
|
|
171
|
+
|
|
172
|
+
### Agents
|
|
173
|
+
|
|
174
|
+
Kader provides several agent types:
|
|
175
|
+
|
|
176
|
+
- **ReActAgent**: Reasoning and Acting agent that combines thoughts with actions
|
|
177
|
+
- **PlanningAgent**: Agent that plans multi-step tasks
|
|
178
|
+
- **BaseAgent**: Base agent class for creating custom agents
|
|
179
|
+
|
|
180
|
+
### Memory Management
|
|
181
|
+
|
|
182
|
+
Kader's memory system includes:
|
|
183
|
+
|
|
184
|
+
- **AgentState**: Persistent key-value storage for agents
|
|
185
|
+
- **RequestState**: Ephemeral request-scoped state
|
|
186
|
+
- **FileSessionManager**: Session persistence to disk
|
|
187
|
+
- **SlidingWindowConversationManager**: Conversation windowing
|
|
188
|
+
|
|
189
|
+
### Tools
|
|
190
|
+
|
|
191
|
+
Kader includes a rich set of tools:
|
|
192
|
+
|
|
193
|
+
- **File System Tools**: Read, write, edit, search files
|
|
194
|
+
- **Command Executor**: Execute shell commands safely
|
|
195
|
+
- **Web Tools**: Search and fetch web content
|
|
196
|
+
- **RAG Tools**: Retrieval Augmented Generation capabilities
|
|
197
|
+
|
|
198
|
+
## Examples
|
|
199
|
+
|
|
200
|
+
Check out the examples directory for comprehensive demonstrations of Kader's features:
|
|
201
|
+
|
|
202
|
+
### Basic Examples
|
|
203
|
+
|
|
204
|
+
- `memory_example.py`: Shows memory management capabilities
|
|
205
|
+
- `ollama_example.py`: Demonstrates how to use the Ollama provider for LLM interactions
|
|
206
|
+
- `tools_example.py`: Demonstrates the various tools available in Kader
|
|
207
|
+
- `simple_agent.py`: Basic agent implementation example
|
|
208
|
+
|
|
209
|
+
### Advanced Examples
|
|
210
|
+
|
|
211
|
+
- `react_agent_example.py`: Interactive ReAct agent with tool integration
|
|
212
|
+
- `planning_agent_example.py`: Planning agent for multi-step tasks
|
|
213
|
+
- `python_developer/`: Specialized Python expert agent (YAML-configured)
|
|
214
|
+
- `todo_agent/`: Task management agent with TodoTool
|
|
215
|
+
|
|
216
|
+
### Running Examples
|
|
217
|
+
|
|
218
|
+
Use uv to run examples:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
uv run python -m examples.memory_example
|
|
222
|
+
uv run python -m examples.ollama_example
|
|
223
|
+
uv run python -m examples.tools_example
|
|
224
|
+
uv run python -m examples.react_agent_example
|
|
225
|
+
uv run python -m examples.python_developer.main
|
|
226
|
+
uv run python -m examples.todo_agent.main
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Architecture
|
|
230
|
+
|
|
231
|
+
### Agent Architecture
|
|
232
|
+
|
|
233
|
+
Kader uses a modular architecture where:
|
|
234
|
+
|
|
235
|
+
1. **Agents** define the behavior and reasoning strategy
|
|
236
|
+
2. **Tools** provide capabilities for external interactions
|
|
237
|
+
3. **Memory** manages state and conversation history
|
|
238
|
+
4. **Providers** handle LLM interactions
|
|
239
|
+
|
|
240
|
+
### Tool Architecture
|
|
241
|
+
|
|
242
|
+
Tools in Kader follow a standardized interface:
|
|
243
|
+
|
|
244
|
+
- Each tool has a schema defining its inputs and outputs
|
|
245
|
+
- Tools can be registered in a ToolRegistry
|
|
246
|
+
- Tools can be executed synchronously or asynchronously
|
|
247
|
+
- Tools can be configured with parameters
|
|
248
|
+
|
|
249
|
+
## Development
|
|
250
|
+
|
|
251
|
+
### Setting up for Development
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Clone the repository
|
|
255
|
+
git clone https://github.com/your-repo/kader.git
|
|
256
|
+
cd kader
|
|
257
|
+
|
|
258
|
+
# Install in development mode with uv
|
|
259
|
+
uv sync
|
|
260
|
+
|
|
261
|
+
# Run the CLI with hot reload for development
|
|
262
|
+
uv run textual run --dev cli.app:KaderApp
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Running Tests
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
# Run tests with uv
|
|
269
|
+
uv run pytest
|
|
270
|
+
|
|
271
|
+
# Run tests with specific options
|
|
272
|
+
uv run pytest --verbose
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Code Quality
|
|
276
|
+
|
|
277
|
+
Kader uses various tools for maintaining code quality:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Run linter
|
|
281
|
+
uv run ruff check .
|
|
282
|
+
|
|
283
|
+
# Format code
|
|
284
|
+
uv run ruff format .
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
### Common Issues
|
|
290
|
+
|
|
291
|
+
- **No models found**: Make sure Ollama is running and you have at least one model installed (e.g., `ollama pull gpt-oss:120b-cloud`)
|
|
292
|
+
- **Connection errors**: Verify that Ollama service is accessible at the configured endpoint
|
|
293
|
+
- **Theme not changing**: Some terminal emulators may not support all color themes
|
|
294
|
+
|
|
295
|
+
### Debugging
|
|
296
|
+
|
|
297
|
+
If you encounter issues:
|
|
298
|
+
|
|
299
|
+
1. Check that Ollama is running: `ollama serve`
|
|
300
|
+
2. Verify your model is pulled: `ollama list`
|
|
301
|
+
3. Ensure your terminal supports the required features
|
|
302
|
+
4. Check the logs for specific error messages
|
|
303
|
+
|
|
304
|
+
## Contributing
|
|
305
|
+
|
|
306
|
+
1. Fork the repository
|
|
307
|
+
2. Create a feature branch
|
|
308
|
+
3. Make your changes
|
|
309
|
+
4. Add tests if applicable
|
|
310
|
+
5. Run the test suite
|
|
311
|
+
6. Submit a pull request
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
316
|
+
|
|
317
|
+
## Acknowledgments
|
|
318
|
+
|
|
319
|
+
- Built with [Textual](https://textual.textualize.io/) for the beautiful CLI interface
|
|
320
|
+
- Uses [Ollama](https://ollama.ai/) for local LLM execution
|
|
321
|
+
- Inspired by ReAct (Reasoning and Acting) agent architecture
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
cli/README.md,sha256=DY3X7w6LPka1GzhtTrGwhpkFmx0YyRpcTCHjFmti3Yg,4654
|
|
2
|
+
cli/__init__.py,sha256=OAi_KSwcuYXR0sRxKuw1DYQrz1jbu8p7vn41_99f36I,107
|
|
3
|
+
cli/__main__.py,sha256=xO2JVjCsh691b-cjSBAEKocJeUeI3P0gfUqM-f1Mp1A,95
|
|
4
|
+
cli/app.py,sha256=-Kd3gK_UFPIC5Ky3J-6VgbtqP4QLYinpa4ZX1LHYC3U,26054
|
|
5
|
+
cli/app.tcss,sha256=BPwrPt2kxJI9GRHmHg-52XOPgRKkTqORgJCaxGpZTew,10374
|
|
6
|
+
cli/utils.py,sha256=ySTPf1xX7D26NgglChXX5NVhtYjmnFn1axL8HDrDn2U,1877
|
|
7
|
+
cli/widgets/__init__.py,sha256=1vj31CrJyxZROLthkKr79i_GbNyj8g3q60ZQPbJHK5k,300
|
|
8
|
+
cli/widgets/confirmation.py,sha256=7hXqGyhW5V9fmtjgiWR4z2fJWmKxWhUH9RigqDrTKp4,9396
|
|
9
|
+
cli/widgets/conversation.py,sha256=tW2Euox239B9avkGqmRnVwP1RMLd3oGFpjRrAyS4rn0,1519
|
|
10
|
+
cli/widgets/loading.py,sha256=wlhQ47ppSj8vCEqjrbG2mk1yKnfo8dWC5429Z2q1-0g,1689
|
|
11
|
+
kader/__init__.py,sha256=QXb0aQvySAiNmhP2kNMNtuuzG_eSUgRVcTRSafko1r0,602
|
|
12
|
+
kader/config.py,sha256=B1s1PNgZ5SrFEJU5TtJG-ZAc7Umff4cwyHR7mfQgeLA,4261
|
|
13
|
+
kader/agent/__init__.py,sha256=UJzUw9NIzggCrhIBHC6nJnfzkhCjCZnIzmD6uUn2SNA,159
|
|
14
|
+
kader/agent/agents.py,sha256=lo41hlkPm3CStI9VAwSOR6IYhCBkqQJ48Ego5XN1XU8,4299
|
|
15
|
+
kader/agent/base.py,sha256=-0pzD2IeCLuNSLs6pffxrPllAHjHD-a_i8Pq5dyoRhc,36703
|
|
16
|
+
kader/agent/logger.py,sha256=3vFwz_yycSBU-5mcdalfZ3KBVT9P_20Q-WT5Al8yIXo,5796
|
|
17
|
+
kader/memory/__init__.py,sha256=VUzzhGOWvO_2aYB6uuavmtNI8l94K7H3uPn4_1MVUUs,1473
|
|
18
|
+
kader/memory/conversation.py,sha256=h6Bamd8_rYnk0Bwt4MJWZRfv2wxCcg6eUxPvzP-tIyA,11810
|
|
19
|
+
kader/memory/session.py,sha256=VhRPEO474SlwM5UOuFt-b_28sJs3j4SNrobCZvoP5Os,10811
|
|
20
|
+
kader/memory/state.py,sha256=itwRjA4PvLlqlRStu-PnMWgSNsMTeU7R0qPOuj0mVDM,5722
|
|
21
|
+
kader/memory/types.py,sha256=h8B40dupNHNZgYC9WJ4hArnlUbX28Pv-XtgIcfUeqQw,3338
|
|
22
|
+
kader/prompts/__init__.py,sha256=TS1kYmEX6TkZcB9GDiulZLI0i9RvFuqMR_kPZEn7AZU,230
|
|
23
|
+
kader/prompts/agent_prompts.py,sha256=Gn3LKPlVLNy3JMWmtv4jcGr5jXu_YcR-0Y4qHjq-Y_s,809
|
|
24
|
+
kader/prompts/base.py,sha256=mFfPfuTX7VNjjiBqez10S7oxyNpiw9U63hTVVAPmlKY,2387
|
|
25
|
+
kader/prompts/templates/planning_agent.j2,sha256=Uc4SnMPv4vKWchhO0RLRNjbEio5CVlRgqDJG_dgM2Pk,1315
|
|
26
|
+
kader/prompts/templates/react_agent.j2,sha256=yME6Qgj2WTW8jRZ_yuQcY6xlXKcV7YUv5sz5ZfCl8P4,606
|
|
27
|
+
kader/providers/__init__.py,sha256=DYEZakt2SRy0Xd2vem93V_TRlY2s19KaJC9bSaOB1WY,154
|
|
28
|
+
kader/providers/base.py,sha256=gxpomjRAX9q3Qf4GHYxdiGI_GsRW9BG7PM38SKUAeCk,17105
|
|
29
|
+
kader/providers/mock.py,sha256=VBuOFFPvDWn4QVFS9HXlwu3jswP0NNNxrMyL4Qgvm50,2723
|
|
30
|
+
kader/providers/ollama.py,sha256=lTuwzFFPMmlD5xBhK_mYG2AvTA0-OLcPDfPwc3lLkTQ,15557
|
|
31
|
+
kader/tools/README.md,sha256=lmw-Ghm8ie2pNcSTL4sJ7OKerkGvbXmlD9Zi87hiC-8,14347
|
|
32
|
+
kader/tools/__init__.py,sha256=6h4Tif5VcYyaL18b_feM91LEF_9nXqcaQwaQ920wRI0,2527
|
|
33
|
+
kader/tools/base.py,sha256=oHqY1-5ihcH4ilvuHd-c5Vb81xm3jAlMrkRlR_8wltE,28840
|
|
34
|
+
kader/tools/exec_commands.py,sha256=nRKkV84Q8b9kHn8vSIKYe6eKhLx9pGRL-5C1hC11-7Y,7948
|
|
35
|
+
kader/tools/filesys.py,sha256=offjTGg1cOolwAGnGnnKguh3225tbVUUu-ipJ2TpaC8,19570
|
|
36
|
+
kader/tools/filesystem.py,sha256=ANTyiFgdxvYSWbp-hSH0AxGH_x-gx2V6XwYypE2MtoM,22733
|
|
37
|
+
kader/tools/protocol.py,sha256=xyLc-5xY1f9VvumnruoJpLldRk3vzDi1WEDcYXgH7o4,15825
|
|
38
|
+
kader/tools/rag.py,sha256=37Nd49D5R_DlWmMyhSdSvst_XFOnoxpaFNtlbLEt6qM,15653
|
|
39
|
+
kader/tools/todo.py,sha256=omirxoG7_KVHAmMoD12DGmn7scqRaewbI1cqWm0ShUo,7735
|
|
40
|
+
kader/tools/utils.py,sha256=bfq7b1vpA1qBaL_QZYBFTqOM35-omu_UeDjo6v0rxEg,14176
|
|
41
|
+
kader/tools/web.py,sha256=2Aqy0nO7ZwNLAqE9IWjCg5y8qnhbt-AIZOHy02XgbxA,8464
|
|
42
|
+
kader-0.1.5.dist-info/METADATA,sha256=YASfdVzY-r5WWh0Yvz134_R0Xo_WEsGt4fdQxmKpPZk,9521
|
|
43
|
+
kader-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
44
|
+
kader-0.1.5.dist-info/entry_points.txt,sha256=TK0VOtrfDFqZ8JQfxpuAHHvDLHyoiafUjS-VOixl02c,39
|
|
45
|
+
kader-0.1.5.dist-info/RECORD,,
|