agenticli 0.1.0__tar.gz

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.
@@ -0,0 +1,12 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+ .claude
12
+ .pytest_cache
@@ -0,0 +1,68 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+ - Bilingual documentation (English and Chinese)
12
+ - Comprehensive docstrings for all modules and public APIs
13
+
14
+ ### Changed
15
+ - Refactored `pyproject.toml` dependencies: core library now has zero required dependencies
16
+ - Updated minimum Python version requirement to 3.10 (from 3.12)
17
+
18
+ ### Documentation
19
+ - Created `docs/index_en.md` - English documentation
20
+ - Created `docs/index_zh.md` - Chinese documentation
21
+ - Updated `README.md` with new documentation links
22
+
23
+ ## [0.1.0] - Initial Release
24
+
25
+ ### Added
26
+ - `CommandRegistry` as the core execution and help system
27
+ - Multiple command registration patterns:
28
+ - Function decorator (`@command`)
29
+ - Command groups (`@command_group`)
30
+ - Class inheritance (`CliCommand`)
31
+ - Dataclass-based (`command_from_model`)
32
+ - Schema-based tool wrapping (`wrap_tool`)
33
+ - Command parsing:
34
+ - Positional arguments
35
+ - Long options (`--option value`)
36
+ - Short options (`-o value`)
37
+ - Boolean flags
38
+ - Inline values (`--option=value`)
39
+ - Help system:
40
+ - Local command help
41
+ - Group help with subcommands
42
+ - Structured execution API:
43
+ - `ExecutionResult` with ok/value/error
44
+ - `CommandError` with code, message, hint, and suggestion
45
+ - Command suggestions:
46
+ - Unknown command suggestions (did you mean)
47
+ - Unknown option suggestions
48
+ - Enum value suggestions
49
+ - Command metadata:
50
+ - Hidden commands (excluded from help)
51
+ - Deprecated commands with notice
52
+ - Parameter features:
53
+ - Ordering and positioning control
54
+ - Example values for documentation
55
+ - Hidden parameters
56
+ - Repeatable parameters
57
+ - List/dict/tuple parameter handling
58
+ - `requires` / `excludes` validation
59
+ - Lifecycle callbacks (`ExecutionCallbacks`):
60
+ - `before_execute`
61
+ - `after_execute`
62
+ - `on_error`
63
+ - Internal parameter injection (`Injected`, `Callback`, `State`)
64
+ - Chain execution with operators (`&&`, `||`, `;`)
65
+ - Built-in `ExecTool` for shell command execution
66
+
67
+ [Unreleased]: https://github.com/your-repo/agenticli/compare/v0.1.0...HEAD
68
+ [0.1.0]: https://github.com/your-repo/agenticli/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 agenticli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: agenticli
3
+ Version: 0.1.0
4
+ Summary: Expose tools as lightweight CLI commands for LLM agents
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Provides-Extra: dev
8
+ Requires-Dist: pytest-cov>=7.1.0; extra == 'dev'
9
+ Requires-Dist: pytest>=8.0; extra == 'dev'
10
+ Provides-Extra: examples
11
+ Requires-Dist: anthropic>=0.34; extra == 'examples'
12
+ Requires-Dist: openai>=2.32.0; extra == 'examples'
13
+ Provides-Extra: pydantic
14
+ Requires-Dist: pydantic<3,>=2; extra == 'pydantic'
15
+ Description-Content-Type: text/markdown
16
+
17
+ <div align="center">
18
+
19
+ # ⚡ agenticli
20
+
21
+ **Expose tools as lightweight CLI commands for LLM agents** 🔧✨
22
+
23
+ [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://python.org)
24
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
25
+ [![PyPI](https://img.shields.io/badge/pypi-agenticli-blue.svg)](https://pypi.org/project/agenticli/)
26
+
27
+ </div>
28
+
29
+ ---
30
+
31
+ ## ✨ What is this?
32
+
33
+ **llmcli** converts functions, classes, and schema-based tools into a stable CLI semantic layer. Instead of flooding prompts with large schemas, LLMs just output a single command string.
34
+
35
+ > 💡 **Philosophy: bash is everything.** The command string is the most stable, restrained, and observable intermediate representation between LLMs and tool systems.
36
+
37
+ ## 🎯 When to use llmcli?
38
+
39
+ | Scenario | llmcli helps? |
40
+ |----------|---------------|
41
+ | You have many tools/functions and need a unified interface for LLMs | ✅ |
42
+ | You don't want massive schemas injected into prompts | ✅ |
43
+ | You want models to see minimal hints, expanding via `--help` | ✅ |
44
+ | You want validation, help, errors, and lifecycle in one place | ✅ |
45
+
46
+ ## 🚀 Quick Start
47
+
48
+ ```bash
49
+ pip install llmcli
50
+ ```
51
+
52
+ ```python
53
+ from typing import Annotated
54
+ from llmcli import CommandRegistry, Option, command, command_group
55
+
56
+ @command_group(name="calc", description="Calculator commands")
57
+ class Calc:
58
+ @command(name="add", description="Add numbers")
59
+ def add(self,
60
+ values: Annotated[list[float], Option(positional=True, value_name="n")]
61
+ ) -> dict:
62
+ return {"result": sum(values)}
63
+
64
+ registry = CommandRegistry()
65
+ registry.register(Calc)
66
+
67
+ # LLM sees this minimal prompt:
68
+ print(registry.get_llm_prompt())
69
+ # -> You can use the following CLI commands:
70
+ # calc: Calculator commands
71
+
72
+ # Execute:
73
+ registry.parse_and_execute("calc add 10 20 30")
74
+ # -> {"result": 60.0}
75
+ ```
76
+
77
+ ## 🏗️ Core Architecture
78
+
79
+ ```
80
+ ┌─────────────────────────────────────────────────────────────┐
81
+ │ LLM Output │
82
+ │ "calc add 10 20 30" │
83
+ └─────────────────────────┬───────────────────────────────────┘
84
+
85
+
86
+ ┌─────────────────────────────────────────────────────────────┐
87
+ │ CommandRegistry │
88
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
89
+ │ │ Parse │─▶│ Validate │─▶│ Execute │─▶│ Result │ │
90
+ │ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
91
+ │ │
92
+ │ • Command hit/matching • Lifecycle callbacks │
93
+ │ • Help generation • Error with suggestions │
94
+ │ • Argument injection • Chain execution (&&, ||, ;) │
95
+ └─────────────────────────────────────────────────────────────┘
96
+
97
+
98
+ ┌─────────────────────────────────────────────────────────────┐
99
+ │ Your Functions / Tools │
100
+ └─────────────────────────────────────────────────────────────┘
101
+ ```
102
+
103
+ ## 📋 Key Features
104
+
105
+ | Feature | Description |
106
+ |---------|-------------|
107
+ | 🔌 **Multiple Registrations** | Decorators, class inheritance, dataclass, Pydantic, schema wrapping |
108
+ | ⚡ **CLI Parsing** | Positional args, `--option value`, `-o value`, `--opt=val`, flags |
109
+ | 📖 **Smart Help** | Auto-generated usage, help text, LLM prompts |
110
+ | ✅ **Validation** | Type coercion, `requires`/`excludes`, enums |
111
+ | 💡 **Suggestions** | "Did you mean X?" for unknown commands/options/enums |
112
+ | 🔄 **Lifecycle Hooks** | `before_execute`, `after_execute`, `on_error` |
113
+ | 🏃 **Internal Injection** | Hide callbacks/state from CLI, inject at runtime |
114
+ | 🔗 **Chain Execution** | `cmd1 && cmd2 || cmd3 ; cmd4` |
115
+
116
+ ## 📝 Registration Patterns
117
+
118
+ ### 1️⃣ Decorator (Most Common)
119
+
120
+ ```python
121
+ from typing import Annotated
122
+ from llmcli import command, Option
123
+
124
+ @command(name="ls", description="List directory")
125
+ def ls(
126
+ path: Annotated[str, Option(short='p', description="Directory path")],
127
+ verbose: Annotated[bool, Option(short='v')] = False,
128
+ ) -> list[str]:
129
+ import os
130
+ return os.listdir(path)
131
+ ```
132
+
133
+ ### 2️⃣ Command Group
134
+
135
+ ```python
136
+ from llmcli import command_group, command
137
+
138
+ @command_group(name="db", description="Database operations")
139
+ class Database:
140
+ @command(description="Create database")
141
+ def create(self, name: str) -> None: ...
142
+
143
+ @command(description="Drop database")
144
+ def drop(self, name: str) -> None: ...
145
+ ```
146
+
147
+ ### 3️⃣ Wrap Existing Tools
148
+
149
+ ```python
150
+ from llmcli import wrap_tool
151
+
152
+ class MyTool:
153
+ name = "my_tool"
154
+ description = "Does something"
155
+ parameters = {"type": "object", "properties": {"x": {"type": "int"}}}
156
+ async def execute(self, **kwargs): return kwargs
157
+
158
+ registry.register_spec(wrap_tool(MyTool()))
159
+ ```
160
+
161
+ ### 4️⃣ Class Inheritance
162
+
163
+ ```python
164
+ from llmcli import CliCommand, CommandRegistry
165
+
166
+ class AddCommand(CliCommand):
167
+ name = "add"
168
+ description = "Add numbers"
169
+ args_model = AddArgs
170
+
171
+ async def run(self, **kwargs) -> dict:
172
+ return {"result": sum(kwargs["values"])}
173
+
174
+ registry.register(AddCommand())
175
+ ```
176
+
177
+ ## 🤖 LLM Integration
178
+
179
+ ### Minimal Tool Schema
180
+
181
+ Expose only one `exec` tool to the LLM:
182
+
183
+ ```python
184
+ from llmcli import ExecTool
185
+
186
+ exec_tool = ExecTool(callback=registry.parse_and_execute)
187
+ # Tool schema: {name: "exec", params: {command: string, timeout?: int}}
188
+ ```
189
+
190
+ ### Lifecycle Callbacks
191
+
192
+ ```python
193
+ from llmcli import ExecutionCallbacks
194
+
195
+ def on_error(ctx):
196
+ print(f"Error: {ctx.error.code} - {ctx.error.message}")
197
+
198
+ registry = CommandRegistry(
199
+ callbacks=ExecutionCallbacks(on_error=on_error)
200
+ )
201
+ ```
202
+
203
+ ### Internal Parameter Injection
204
+
205
+ ```python
206
+ from typing import Annotated
207
+ from llmcli import Callback, State, command
208
+
209
+ @command(name="process")
210
+ def process(
211
+ data: list[str],
212
+ cache: Annotated[object, State(factory=lambda ctx: load_cache())] = None,
213
+ ):
214
+ # cache is injected automatically, hidden from CLI
215
+ return cached_transform(data, cache)
216
+ ```
217
+
218
+ ## 📦 Stable API
219
+
220
+ ```python
221
+ # Core
222
+ CommandRegistry
223
+ CommandRegistry.register(target)
224
+ CommandRegistry.register_spec(spec)
225
+ CommandRegistry.execute(command_str)
226
+ CommandRegistry.parse_and_execute(command_str)
227
+ CommandRegistry.render_help(command)
228
+ CommandRegistry.get_llm_prompt(detailed=False)
229
+
230
+ # Decorators
231
+ command(name=None, description="", aliases=None, hidden=False, deprecated=None)
232
+ command_group(name, description)
233
+
234
+ # Helpers
235
+ CliCommand
236
+ wrap_tool(tool)
237
+ command_from_model(name, model, handler)
238
+ command_from_method(name, target, method_name)
239
+ Option
240
+ Injected / Callback / State
241
+ ExecutionCallbacks
242
+ ExecTool
243
+ ```
244
+
245
+ ## 💡 Examples
246
+
247
+ See [example/demo.py](example/demo.py) for a complete calc system with OpenAI/Anthropic integration:
248
+
249
+ ```bash
250
+ pip install "llmcli[examples]"
251
+ python -m example.demo --provider openai
252
+ python -m example.demo --provider anthropic
253
+ ```
254
+
255
+ ## 📚 Documentation
256
+
257
+ | Language | Link |
258
+ |----------|------|
259
+ | 🇺🇸 English | [docs/index_en.md](docs/index_en.md) |
260
+ | 🇨🇳 中文 | [docs/index_zh.md](docs/index_zh.md) |
261
+
262
+ ## 📄 License
263
+
264
+ MIT
@@ -0,0 +1,248 @@
1
+ <div align="center">
2
+
3
+ # ⚡ agenticli
4
+
5
+ **Expose tools as lightweight CLI commands for LLM agents** 🔧✨
6
+
7
+ [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](https://python.org)
8
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
9
+ [![PyPI](https://img.shields.io/badge/pypi-agenticli-blue.svg)](https://pypi.org/project/agenticli/)
10
+
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## ✨ What is this?
16
+
17
+ **llmcli** converts functions, classes, and schema-based tools into a stable CLI semantic layer. Instead of flooding prompts with large schemas, LLMs just output a single command string.
18
+
19
+ > 💡 **Philosophy: bash is everything.** The command string is the most stable, restrained, and observable intermediate representation between LLMs and tool systems.
20
+
21
+ ## 🎯 When to use llmcli?
22
+
23
+ | Scenario | llmcli helps? |
24
+ |----------|---------------|
25
+ | You have many tools/functions and need a unified interface for LLMs | ✅ |
26
+ | You don't want massive schemas injected into prompts | ✅ |
27
+ | You want models to see minimal hints, expanding via `--help` | ✅ |
28
+ | You want validation, help, errors, and lifecycle in one place | ✅ |
29
+
30
+ ## 🚀 Quick Start
31
+
32
+ ```bash
33
+ pip install llmcli
34
+ ```
35
+
36
+ ```python
37
+ from typing import Annotated
38
+ from llmcli import CommandRegistry, Option, command, command_group
39
+
40
+ @command_group(name="calc", description="Calculator commands")
41
+ class Calc:
42
+ @command(name="add", description="Add numbers")
43
+ def add(self,
44
+ values: Annotated[list[float], Option(positional=True, value_name="n")]
45
+ ) -> dict:
46
+ return {"result": sum(values)}
47
+
48
+ registry = CommandRegistry()
49
+ registry.register(Calc)
50
+
51
+ # LLM sees this minimal prompt:
52
+ print(registry.get_llm_prompt())
53
+ # -> You can use the following CLI commands:
54
+ # calc: Calculator commands
55
+
56
+ # Execute:
57
+ registry.parse_and_execute("calc add 10 20 30")
58
+ # -> {"result": 60.0}
59
+ ```
60
+
61
+ ## 🏗️ Core Architecture
62
+
63
+ ```
64
+ ┌─────────────────────────────────────────────────────────────┐
65
+ │ LLM Output │
66
+ │ "calc add 10 20 30" │
67
+ └─────────────────────────┬───────────────────────────────────┘
68
+
69
+
70
+ ┌─────────────────────────────────────────────────────────────┐
71
+ │ CommandRegistry │
72
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
73
+ │ │ Parse │─▶│ Validate │─▶│ Execute │─▶│ Result │ │
74
+ │ └──────────┘ └──────────┘ └──────────┘ └────────────┘ │
75
+ │ │
76
+ │ • Command hit/matching • Lifecycle callbacks │
77
+ │ • Help generation • Error with suggestions │
78
+ │ • Argument injection • Chain execution (&&, ||, ;) │
79
+ └─────────────────────────────────────────────────────────────┘
80
+
81
+
82
+ ┌─────────────────────────────────────────────────────────────┐
83
+ │ Your Functions / Tools │
84
+ └─────────────────────────────────────────────────────────────┘
85
+ ```
86
+
87
+ ## 📋 Key Features
88
+
89
+ | Feature | Description |
90
+ |---------|-------------|
91
+ | 🔌 **Multiple Registrations** | Decorators, class inheritance, dataclass, Pydantic, schema wrapping |
92
+ | ⚡ **CLI Parsing** | Positional args, `--option value`, `-o value`, `--opt=val`, flags |
93
+ | 📖 **Smart Help** | Auto-generated usage, help text, LLM prompts |
94
+ | ✅ **Validation** | Type coercion, `requires`/`excludes`, enums |
95
+ | 💡 **Suggestions** | "Did you mean X?" for unknown commands/options/enums |
96
+ | 🔄 **Lifecycle Hooks** | `before_execute`, `after_execute`, `on_error` |
97
+ | 🏃 **Internal Injection** | Hide callbacks/state from CLI, inject at runtime |
98
+ | 🔗 **Chain Execution** | `cmd1 && cmd2 || cmd3 ; cmd4` |
99
+
100
+ ## 📝 Registration Patterns
101
+
102
+ ### 1️⃣ Decorator (Most Common)
103
+
104
+ ```python
105
+ from typing import Annotated
106
+ from llmcli import command, Option
107
+
108
+ @command(name="ls", description="List directory")
109
+ def ls(
110
+ path: Annotated[str, Option(short='p', description="Directory path")],
111
+ verbose: Annotated[bool, Option(short='v')] = False,
112
+ ) -> list[str]:
113
+ import os
114
+ return os.listdir(path)
115
+ ```
116
+
117
+ ### 2️⃣ Command Group
118
+
119
+ ```python
120
+ from llmcli import command_group, command
121
+
122
+ @command_group(name="db", description="Database operations")
123
+ class Database:
124
+ @command(description="Create database")
125
+ def create(self, name: str) -> None: ...
126
+
127
+ @command(description="Drop database")
128
+ def drop(self, name: str) -> None: ...
129
+ ```
130
+
131
+ ### 3️⃣ Wrap Existing Tools
132
+
133
+ ```python
134
+ from llmcli import wrap_tool
135
+
136
+ class MyTool:
137
+ name = "my_tool"
138
+ description = "Does something"
139
+ parameters = {"type": "object", "properties": {"x": {"type": "int"}}}
140
+ async def execute(self, **kwargs): return kwargs
141
+
142
+ registry.register_spec(wrap_tool(MyTool()))
143
+ ```
144
+
145
+ ### 4️⃣ Class Inheritance
146
+
147
+ ```python
148
+ from llmcli import CliCommand, CommandRegistry
149
+
150
+ class AddCommand(CliCommand):
151
+ name = "add"
152
+ description = "Add numbers"
153
+ args_model = AddArgs
154
+
155
+ async def run(self, **kwargs) -> dict:
156
+ return {"result": sum(kwargs["values"])}
157
+
158
+ registry.register(AddCommand())
159
+ ```
160
+
161
+ ## 🤖 LLM Integration
162
+
163
+ ### Minimal Tool Schema
164
+
165
+ Expose only one `exec` tool to the LLM:
166
+
167
+ ```python
168
+ from llmcli import ExecTool
169
+
170
+ exec_tool = ExecTool(callback=registry.parse_and_execute)
171
+ # Tool schema: {name: "exec", params: {command: string, timeout?: int}}
172
+ ```
173
+
174
+ ### Lifecycle Callbacks
175
+
176
+ ```python
177
+ from llmcli import ExecutionCallbacks
178
+
179
+ def on_error(ctx):
180
+ print(f"Error: {ctx.error.code} - {ctx.error.message}")
181
+
182
+ registry = CommandRegistry(
183
+ callbacks=ExecutionCallbacks(on_error=on_error)
184
+ )
185
+ ```
186
+
187
+ ### Internal Parameter Injection
188
+
189
+ ```python
190
+ from typing import Annotated
191
+ from llmcli import Callback, State, command
192
+
193
+ @command(name="process")
194
+ def process(
195
+ data: list[str],
196
+ cache: Annotated[object, State(factory=lambda ctx: load_cache())] = None,
197
+ ):
198
+ # cache is injected automatically, hidden from CLI
199
+ return cached_transform(data, cache)
200
+ ```
201
+
202
+ ## 📦 Stable API
203
+
204
+ ```python
205
+ # Core
206
+ CommandRegistry
207
+ CommandRegistry.register(target)
208
+ CommandRegistry.register_spec(spec)
209
+ CommandRegistry.execute(command_str)
210
+ CommandRegistry.parse_and_execute(command_str)
211
+ CommandRegistry.render_help(command)
212
+ CommandRegistry.get_llm_prompt(detailed=False)
213
+
214
+ # Decorators
215
+ command(name=None, description="", aliases=None, hidden=False, deprecated=None)
216
+ command_group(name, description)
217
+
218
+ # Helpers
219
+ CliCommand
220
+ wrap_tool(tool)
221
+ command_from_model(name, model, handler)
222
+ command_from_method(name, target, method_name)
223
+ Option
224
+ Injected / Callback / State
225
+ ExecutionCallbacks
226
+ ExecTool
227
+ ```
228
+
229
+ ## 💡 Examples
230
+
231
+ See [example/demo.py](example/demo.py) for a complete calc system with OpenAI/Anthropic integration:
232
+
233
+ ```bash
234
+ pip install "llmcli[examples]"
235
+ python -m example.demo --provider openai
236
+ python -m example.demo --provider anthropic
237
+ ```
238
+
239
+ ## 📚 Documentation
240
+
241
+ | Language | Link |
242
+ |----------|------|
243
+ | 🇺🇸 English | [docs/index_en.md](docs/index_en.md) |
244
+ | 🇨🇳 中文 | [docs/index_zh.md](docs/index_zh.md) |
245
+
246
+ ## 📄 License
247
+
248
+ MIT
@@ -0,0 +1,14 @@
1
+ # agenticli Documentation
2
+
3
+ This directory contains the documentation for agenticli.
4
+
5
+ ## Files
6
+
7
+ - [index_en.md](index_en.md) - English documentation
8
+ - [index_zh.md](index_zh.md) - Chinese documentation (中文文档)
9
+
10
+ ## Quick Links
11
+
12
+ For English documentation, see [index_en.md](index_en.md).
13
+
14
+ For Chinese documentation, see [index_zh.md](index_zh.md).