utcp-cli 1.0.0__tar.gz → 1.0.2__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.
- utcp_cli-1.0.2/PKG-INFO +188 -0
- utcp_cli-1.0.2/README.md +162 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/pyproject.toml +2 -2
- utcp_cli-1.0.2/src/utcp_cli/cli_call_template.py +110 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli/cli_communication_protocol.py +91 -75
- utcp_cli-1.0.2/src/utcp_cli.egg-info/PKG-INFO +188 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli.egg-info/SOURCES.txt +1 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/tests/test_cli_communication_protocol.py +1 -1
- utcp_cli-1.0.0/PKG-INFO +0 -25
- utcp_cli-1.0.0/src/utcp_cli/cli_call_template.py +0 -44
- utcp_cli-1.0.0/src/utcp_cli.egg-info/PKG-INFO +0 -25
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/setup.cfg +0 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli/__init__.py +0 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli.egg-info/dependency_links.txt +0 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli.egg-info/entry_points.txt +0 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli.egg-info/requires.txt +0 -0
- {utcp_cli-1.0.0 → utcp_cli-1.0.2}/src/utcp_cli.egg-info/top_level.txt +0 -0
utcp_cli-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: utcp-cli
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: UTCP communication protocol plugin for wrapping local command-line tools.
|
|
5
|
+
Author: UTCP Contributors
|
|
6
|
+
License-Expression: MPL-2.0
|
|
7
|
+
Project-URL: Homepage, https://utcp.io
|
|
8
|
+
Project-URL: Source, https://github.com/universal-tool-calling-protocol/python-utcp
|
|
9
|
+
Project-URL: Issues, https://github.com/universal-tool-calling-protocol/python-utcp/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: utcp>=1.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
+
Requires-Dist: coverage; extra == "dev"
|
|
25
|
+
Requires-Dist: twine; extra == "dev"
|
|
26
|
+
|
|
27
|
+
# UTCP CLI Plugin
|
|
28
|
+
|
|
29
|
+
[](https://pepy.tech/projects/utcp-cli)
|
|
30
|
+
|
|
31
|
+
Command-line interface plugin for UTCP, enabling integration with command-line tools and processes.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- **Command Execution**: Run any command-line tool as a UTCP tool
|
|
36
|
+
- **Environment Variables**: Secure credential and configuration passing
|
|
37
|
+
- **Working Directory Control**: Execute commands in specific directories
|
|
38
|
+
- **Input/Output Handling**: Support for stdin, stdout, stderr processing
|
|
39
|
+
- **Cross-Platform**: Works on Windows, macOS, and Linux
|
|
40
|
+
- **Timeout Management**: Configurable execution timeouts
|
|
41
|
+
- **Argument Validation**: Optional input sanitization
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install utcp-cli
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from utcp.utcp_client import UtcpClient
|
|
53
|
+
|
|
54
|
+
# Basic CLI tool
|
|
55
|
+
client = await UtcpClient.create(config={
|
|
56
|
+
"manual_call_templates": [{
|
|
57
|
+
"name": "file_tools",
|
|
58
|
+
"call_template_type": "cli",
|
|
59
|
+
"command_name": "ls -la ${path}"
|
|
60
|
+
}]
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
result = await client.call_tool("file_tools.list", {"path": "/home"})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration Examples
|
|
67
|
+
|
|
68
|
+
### Basic Command
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"name": "file_ops",
|
|
72
|
+
"call_template_type": "cli",
|
|
73
|
+
"command_name": "ls -la ${path}",
|
|
74
|
+
"working_dir": "/tmp"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### With Environment Variables
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"name": "python_script",
|
|
82
|
+
"call_template_type": "cli",
|
|
83
|
+
"command_name": "python script.py ${input}",
|
|
84
|
+
"env_vars": {
|
|
85
|
+
"PYTHONPATH": "/custom/path",
|
|
86
|
+
"API_KEY": "${API_KEY}"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Processing JSON with jq
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"name": "json_processor",
|
|
95
|
+
"call_template_type": "cli",
|
|
96
|
+
"command_name": "jq '.data'",
|
|
97
|
+
"stdin": "${json_input}",
|
|
98
|
+
"timeout": 10
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Git Operations
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"name": "git_tools",
|
|
106
|
+
"call_template_type": "cli",
|
|
107
|
+
"command_name": "git ${operation} ${args}",
|
|
108
|
+
"working_dir": "${repo_path}",
|
|
109
|
+
"env_vars": {
|
|
110
|
+
"GIT_AUTHOR_NAME": "${author_name}",
|
|
111
|
+
"GIT_AUTHOR_EMAIL": "${author_email}"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Security Considerations
|
|
117
|
+
|
|
118
|
+
- Commands run in isolated subprocesses
|
|
119
|
+
- Environment variables provide secure credential passing
|
|
120
|
+
- Working directory restrictions limit file system access
|
|
121
|
+
- Input validation prevents command injection
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"name": "safe_grep",
|
|
126
|
+
"call_template_type": "cli",
|
|
127
|
+
"command_name": "grep ${pattern} ${file}",
|
|
128
|
+
"working_dir": "/safe/directory",
|
|
129
|
+
"allowed_args": {
|
|
130
|
+
"pattern": "^[a-zA-Z0-9_-]+$",
|
|
131
|
+
"file": "^[a-zA-Z0-9_./-]+\\.txt$"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Error Handling
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from utcp.exceptions import ToolCallError
|
|
140
|
+
import subprocess
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
result = await client.call_tool("cli_tool.command", {"arg": "value"})
|
|
144
|
+
except ToolCallError as e:
|
|
145
|
+
if isinstance(e.__cause__, subprocess.CalledProcessError):
|
|
146
|
+
print(f"Command failed with exit code {e.__cause__.returncode}")
|
|
147
|
+
print(f"stderr: {e.__cause__.stderr}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Common Use Cases
|
|
151
|
+
|
|
152
|
+
- **File Operations**: ls, find, grep, awk, sed
|
|
153
|
+
- **Data Processing**: jq, sort, uniq, cut
|
|
154
|
+
- **System Monitoring**: ps, top, df, netstat
|
|
155
|
+
- **Development Tools**: git, npm, pip, docker
|
|
156
|
+
- **Custom Scripts**: Python, bash, PowerShell scripts
|
|
157
|
+
|
|
158
|
+
## Testing CLI Tools
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
import pytest
|
|
162
|
+
from utcp.utcp_client import UtcpClient
|
|
163
|
+
|
|
164
|
+
@pytest.mark.asyncio
|
|
165
|
+
async def test_cli_tool():
|
|
166
|
+
client = await UtcpClient.create(config={
|
|
167
|
+
"manual_call_templates": [{
|
|
168
|
+
"name": "test_cli",
|
|
169
|
+
"call_template_type": "cli",
|
|
170
|
+
"command_name": "echo ${message}"
|
|
171
|
+
}]
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
result = await client.call_tool("test_cli.echo", {"message": "hello"})
|
|
175
|
+
assert "hello" in result["stdout"]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Related Documentation
|
|
179
|
+
|
|
180
|
+
- [Main UTCP Documentation](../../../README.md)
|
|
181
|
+
- [Core Package Documentation](../../../core/README.md)
|
|
182
|
+
- [HTTP Plugin](../http/README.md)
|
|
183
|
+
- [MCP Plugin](../mcp/README.md)
|
|
184
|
+
- [Text Plugin](../text/README.md)
|
|
185
|
+
|
|
186
|
+
## Examples
|
|
187
|
+
|
|
188
|
+
For complete examples, see the [UTCP examples repository](https://github.com/universal-tool-calling-protocol/utcp-examples).
|
utcp_cli-1.0.2/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# UTCP CLI Plugin
|
|
2
|
+
|
|
3
|
+
[](https://pepy.tech/projects/utcp-cli)
|
|
4
|
+
|
|
5
|
+
Command-line interface plugin for UTCP, enabling integration with command-line tools and processes.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Command Execution**: Run any command-line tool as a UTCP tool
|
|
10
|
+
- **Environment Variables**: Secure credential and configuration passing
|
|
11
|
+
- **Working Directory Control**: Execute commands in specific directories
|
|
12
|
+
- **Input/Output Handling**: Support for stdin, stdout, stderr processing
|
|
13
|
+
- **Cross-Platform**: Works on Windows, macOS, and Linux
|
|
14
|
+
- **Timeout Management**: Configurable execution timeouts
|
|
15
|
+
- **Argument Validation**: Optional input sanitization
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install utcp-cli
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from utcp.utcp_client import UtcpClient
|
|
27
|
+
|
|
28
|
+
# Basic CLI tool
|
|
29
|
+
client = await UtcpClient.create(config={
|
|
30
|
+
"manual_call_templates": [{
|
|
31
|
+
"name": "file_tools",
|
|
32
|
+
"call_template_type": "cli",
|
|
33
|
+
"command_name": "ls -la ${path}"
|
|
34
|
+
}]
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
result = await client.call_tool("file_tools.list", {"path": "/home"})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration Examples
|
|
41
|
+
|
|
42
|
+
### Basic Command
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"name": "file_ops",
|
|
46
|
+
"call_template_type": "cli",
|
|
47
|
+
"command_name": "ls -la ${path}",
|
|
48
|
+
"working_dir": "/tmp"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### With Environment Variables
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"name": "python_script",
|
|
56
|
+
"call_template_type": "cli",
|
|
57
|
+
"command_name": "python script.py ${input}",
|
|
58
|
+
"env_vars": {
|
|
59
|
+
"PYTHONPATH": "/custom/path",
|
|
60
|
+
"API_KEY": "${API_KEY}"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Processing JSON with jq
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"name": "json_processor",
|
|
69
|
+
"call_template_type": "cli",
|
|
70
|
+
"command_name": "jq '.data'",
|
|
71
|
+
"stdin": "${json_input}",
|
|
72
|
+
"timeout": 10
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Git Operations
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"name": "git_tools",
|
|
80
|
+
"call_template_type": "cli",
|
|
81
|
+
"command_name": "git ${operation} ${args}",
|
|
82
|
+
"working_dir": "${repo_path}",
|
|
83
|
+
"env_vars": {
|
|
84
|
+
"GIT_AUTHOR_NAME": "${author_name}",
|
|
85
|
+
"GIT_AUTHOR_EMAIL": "${author_email}"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Security Considerations
|
|
91
|
+
|
|
92
|
+
- Commands run in isolated subprocesses
|
|
93
|
+
- Environment variables provide secure credential passing
|
|
94
|
+
- Working directory restrictions limit file system access
|
|
95
|
+
- Input validation prevents command injection
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"name": "safe_grep",
|
|
100
|
+
"call_template_type": "cli",
|
|
101
|
+
"command_name": "grep ${pattern} ${file}",
|
|
102
|
+
"working_dir": "/safe/directory",
|
|
103
|
+
"allowed_args": {
|
|
104
|
+
"pattern": "^[a-zA-Z0-9_-]+$",
|
|
105
|
+
"file": "^[a-zA-Z0-9_./-]+\\.txt$"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Error Handling
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from utcp.exceptions import ToolCallError
|
|
114
|
+
import subprocess
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
result = await client.call_tool("cli_tool.command", {"arg": "value"})
|
|
118
|
+
except ToolCallError as e:
|
|
119
|
+
if isinstance(e.__cause__, subprocess.CalledProcessError):
|
|
120
|
+
print(f"Command failed with exit code {e.__cause__.returncode}")
|
|
121
|
+
print(f"stderr: {e.__cause__.stderr}")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Common Use Cases
|
|
125
|
+
|
|
126
|
+
- **File Operations**: ls, find, grep, awk, sed
|
|
127
|
+
- **Data Processing**: jq, sort, uniq, cut
|
|
128
|
+
- **System Monitoring**: ps, top, df, netstat
|
|
129
|
+
- **Development Tools**: git, npm, pip, docker
|
|
130
|
+
- **Custom Scripts**: Python, bash, PowerShell scripts
|
|
131
|
+
|
|
132
|
+
## Testing CLI Tools
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import pytest
|
|
136
|
+
from utcp.utcp_client import UtcpClient
|
|
137
|
+
|
|
138
|
+
@pytest.mark.asyncio
|
|
139
|
+
async def test_cli_tool():
|
|
140
|
+
client = await UtcpClient.create(config={
|
|
141
|
+
"manual_call_templates": [{
|
|
142
|
+
"name": "test_cli",
|
|
143
|
+
"call_template_type": "cli",
|
|
144
|
+
"command_name": "echo ${message}"
|
|
145
|
+
}]
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
result = await client.call_tool("test_cli.echo", {"message": "hello"})
|
|
149
|
+
assert "hello" in result["stdout"]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Related Documentation
|
|
153
|
+
|
|
154
|
+
- [Main UTCP Documentation](../../../README.md)
|
|
155
|
+
- [Core Package Documentation](../../../core/README.md)
|
|
156
|
+
- [HTTP Plugin](../http/README.md)
|
|
157
|
+
- [MCP Plugin](../mcp/README.md)
|
|
158
|
+
- [Text Plugin](../text/README.md)
|
|
159
|
+
|
|
160
|
+
## Examples
|
|
161
|
+
|
|
162
|
+
For complete examples, see the [UTCP examples repository](https://github.com/universal-tool-calling-protocol/utcp-examples).
|
|
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "utcp-cli"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.2"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "UTCP Contributors" },
|
|
10
10
|
]
|
|
11
|
-
description = "
|
|
11
|
+
description = "UTCP communication protocol plugin for wrapping local command-line tools."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
14
14
|
dependencies = [
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from typing import Optional, Dict, Literal
|
|
2
|
+
from pydantic import Field
|
|
3
|
+
|
|
4
|
+
from utcp.data.call_template import CallTemplate
|
|
5
|
+
from utcp.interfaces.serializer import Serializer
|
|
6
|
+
from utcp.exceptions import UtcpSerializerValidationError
|
|
7
|
+
import traceback
|
|
8
|
+
|
|
9
|
+
class CliCallTemplate(CallTemplate):
|
|
10
|
+
"""REQUIRED
|
|
11
|
+
Call template configuration for Command Line Interface (CLI) tools.
|
|
12
|
+
|
|
13
|
+
This class defines the configuration for executing command-line tools and
|
|
14
|
+
programs as UTCP tool providers. It supports environment variable injection,
|
|
15
|
+
custom working directories, and defines the command to be executed.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
call_template_type: The type of the call template. Must be "cli".
|
|
19
|
+
command_name: The command or path of the program to execute. It can
|
|
20
|
+
contain placeholders for arguments that will be substituted at
|
|
21
|
+
runtime (e.g., `${arg_name}`).
|
|
22
|
+
env_vars: A dictionary of environment variables to set for the command's
|
|
23
|
+
execution context. Values can be static strings or placeholders for
|
|
24
|
+
variables from the UTCP client's variable substitutor.
|
|
25
|
+
working_dir: The working directory from which to run the command. If not
|
|
26
|
+
provided, it defaults to the current process's working directory.
|
|
27
|
+
auth: Authentication details. Not applicable to the CLI protocol, so it
|
|
28
|
+
is always None.
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
Basic CLI command:
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"name": "list_files_tool",
|
|
35
|
+
"call_template_type": "cli",
|
|
36
|
+
"command_name": "ls -la",
|
|
37
|
+
"working_dir": "/tmp"
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Command with environment variables and argument placeholders:
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"name": "python_script_tool",
|
|
45
|
+
"call_template_type": "cli",
|
|
46
|
+
"command_name": "python script.py --input ${input_file}",
|
|
47
|
+
"env_vars": {
|
|
48
|
+
"PYTHONPATH": "/custom/path",
|
|
49
|
+
"API_KEY": "${API_KEY_VAR}"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Security Considerations:
|
|
55
|
+
- Commands are executed in a subprocess. Ensure that the commands
|
|
56
|
+
specified are from a trusted source.
|
|
57
|
+
- Avoid passing unsanitized user input directly into the command string.
|
|
58
|
+
Use tool argument validation where possible.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
call_template_type: Literal["cli"] = "cli"
|
|
62
|
+
command_name: str
|
|
63
|
+
env_vars: Optional[Dict[str, str]] = Field(
|
|
64
|
+
default=None, description="Environment variables to set when executing the command"
|
|
65
|
+
)
|
|
66
|
+
working_dir: Optional[str] = Field(
|
|
67
|
+
default=None, description="Working directory for command execution"
|
|
68
|
+
)
|
|
69
|
+
auth: None = None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class CliCallTemplateSerializer(Serializer[CliCallTemplate]):
|
|
73
|
+
"""REQUIRED
|
|
74
|
+
Serializer for converting between `CliCallTemplate` and dictionary representations.
|
|
75
|
+
|
|
76
|
+
This class handles the serialization and deserialization of `CliCallTemplate`
|
|
77
|
+
objects, ensuring that they can be correctly represented as dictionaries and
|
|
78
|
+
reconstructed from them, with validation.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def to_dict(self, obj: CliCallTemplate) -> dict:
|
|
82
|
+
"""REQUIRED
|
|
83
|
+
Converts a `CliCallTemplate` instance to its dictionary representation.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
obj: The `CliCallTemplate` instance to serialize.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
A dictionary representing the `CliCallTemplate`.
|
|
90
|
+
"""
|
|
91
|
+
return obj.model_dump()
|
|
92
|
+
|
|
93
|
+
def validate_dict(self, obj: dict) -> CliCallTemplate:
|
|
94
|
+
"""REQUIRED
|
|
95
|
+
Validates a dictionary and constructs a `CliCallTemplate` instance.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
obj: The dictionary to validate and deserialize.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
A `CliCallTemplate` instance.
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
UtcpSerializerValidationError: If the dictionary is not a valid
|
|
105
|
+
representation of a `CliCallTemplate`.
|
|
106
|
+
"""
|
|
107
|
+
try:
|
|
108
|
+
return CliCallTemplate.model_validate(obj)
|
|
109
|
+
except Exception as e:
|
|
110
|
+
raise UtcpSerializerValidationError("Invalid CliCallTemplate: " + traceback.format_exc()) from e
|
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
"""Command Line Interface (CLI)
|
|
1
|
+
"""Command Line Interface (CLI) communication protocol for the UTCP client.
|
|
2
2
|
|
|
3
|
-
This module provides
|
|
4
|
-
to interact with command-line tools
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
This module provides an implementation of the `CommunicationProtocol` interface
|
|
4
|
+
that enables the UTCP client to interact with command-line tools. It supports
|
|
5
|
+
discovering tools by executing a command and parsing its output for a UTCP
|
|
6
|
+
manual, as well as calling those tools with arguments.
|
|
7
7
|
|
|
8
8
|
Key Features:
|
|
9
|
-
- Asynchronous
|
|
10
|
-
- Tool discovery
|
|
11
|
-
- Flexible argument formatting for
|
|
12
|
-
-
|
|
13
|
-
- JSON output
|
|
14
|
-
- Cross-platform command parsing
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- Environment variables can be controlled per provider
|
|
20
|
-
- Working directory can be restricted
|
|
9
|
+
- Asynchronous execution of shell commands.
|
|
10
|
+
- Tool discovery by running a command that outputs a UTCP manual.
|
|
11
|
+
- Flexible argument formatting for different CLI conventions.
|
|
12
|
+
- Support for environment variables and custom working directories.
|
|
13
|
+
- Automatic parsing of JSON output with a fallback to raw text.
|
|
14
|
+
- Cross-platform command parsing for Windows and Unix-like systems.
|
|
15
|
+
|
|
16
|
+
Security Considerations:
|
|
17
|
+
Executing arbitrary command-line tools can be dangerous. This protocol
|
|
18
|
+
should only be used with trusted tools.
|
|
21
19
|
"""
|
|
22
20
|
import asyncio
|
|
23
21
|
import json
|
|
24
22
|
import os
|
|
25
23
|
import shlex
|
|
24
|
+
import sys
|
|
26
25
|
from typing import Dict, Any, List, Optional, Callable, AsyncGenerator
|
|
27
26
|
|
|
28
27
|
from utcp.interfaces.communication_protocol import CommunicationProtocol
|
|
@@ -33,37 +32,26 @@ from utcp.data.register_manual_response import RegisterManualResult
|
|
|
33
32
|
from utcp_cli.cli_call_template import CliCallTemplate, CliCallTemplateSerializer
|
|
34
33
|
import logging
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
logging.basicConfig(
|
|
36
|
+
level=logging.INFO,
|
|
37
|
+
format="%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s"
|
|
38
|
+
)
|
|
37
39
|
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
38
41
|
|
|
39
42
|
class CliCommunicationProtocol(CommunicationProtocol):
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Tool discovery through startup commands returning UTCP manuals
|
|
49
|
-
- Flexible argument formatting for various CLI conventions
|
|
50
|
-
- Environment variable injection for authentication
|
|
51
|
-
- JSON output parsing with graceful fallback to text
|
|
52
|
-
- Cross-platform command parsing and execution
|
|
53
|
-
- Configurable working directories and timeouts
|
|
54
|
-
- Process lifecycle management with proper termination
|
|
55
|
-
|
|
56
|
-
Architecture:
|
|
57
|
-
CLI tools are discovered by executing the provider's command_name
|
|
58
|
-
and parsing the output for UTCP manual JSON. Tool calls execute
|
|
59
|
-
the same command with formatted arguments and return processed output.
|
|
60
|
-
|
|
61
|
-
Attributes:
|
|
62
|
-
_log: Logger function for debugging and error reporting.
|
|
43
|
+
"""REQUIRED
|
|
44
|
+
Communication protocol for interacting with CLI-based tool providers.
|
|
45
|
+
|
|
46
|
+
This class implements the `CommunicationProtocol` interface to handle
|
|
47
|
+
communication with command-line tools. It discovers tools by executing a
|
|
48
|
+
command specified in a `CliCallTemplate` and parsing the output for a UTCP
|
|
49
|
+
manual. It also executes tool calls by running the corresponding command
|
|
50
|
+
with the provided arguments.
|
|
63
51
|
"""
|
|
64
52
|
|
|
65
53
|
def __init__(self):
|
|
66
|
-
"""
|
|
54
|
+
"""Initializes the `CliCommunicationProtocol`."""
|
|
67
55
|
|
|
68
56
|
def _log_info(self, message: str):
|
|
69
57
|
"""Log informational messages."""
|
|
@@ -154,9 +142,25 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
154
142
|
raise
|
|
155
143
|
|
|
156
144
|
async def register_manual(self, caller, manual_call_template: CallTemplate) -> RegisterManualResult:
|
|
157
|
-
"""
|
|
158
|
-
|
|
159
|
-
|
|
145
|
+
"""REQUIRED
|
|
146
|
+
Registers a CLI-based manual and discovers its tools.
|
|
147
|
+
|
|
148
|
+
This method executes the command specified in the `CliCallTemplate`'s
|
|
149
|
+
`command_name` field. It then attempts to parse the command's output
|
|
150
|
+
(stdout) as a UTCP manual in JSON format.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
caller: The UTCP client instance that is calling this method.
|
|
154
|
+
manual_call_template: The `CliCallTemplate` containing the details for
|
|
155
|
+
tool discovery, such as the command to run.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
A `RegisterManualResult` object indicating whether the registration
|
|
159
|
+
was successful and containing the discovered tools.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
ValueError: If the `manual_call_template` is not an instance of
|
|
163
|
+
`CliCallTemplate` or if `command_name` is not set.
|
|
160
164
|
"""
|
|
161
165
|
if not isinstance(manual_call_template, CliCallTemplate):
|
|
162
166
|
raise ValueError("CliCommunicationProtocol can only be used with CliCallTemplate")
|
|
@@ -193,7 +197,7 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
193
197
|
return RegisterManualResult(
|
|
194
198
|
success=False,
|
|
195
199
|
manual_call_template=manual_call_template,
|
|
196
|
-
manual=UtcpManual(
|
|
200
|
+
manual=UtcpManual(manual_version="0.0.0", tools=[]),
|
|
197
201
|
errors=[
|
|
198
202
|
f"No output from discovery command for CLI provider '{manual_call_template.name}'"
|
|
199
203
|
],
|
|
@@ -212,7 +216,7 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
212
216
|
return RegisterManualResult(
|
|
213
217
|
success=False,
|
|
214
218
|
manual_call_template=manual_call_template,
|
|
215
|
-
manual=UtcpManual(
|
|
219
|
+
manual=UtcpManual(manual_version="0.0.0", tools=[]),
|
|
216
220
|
errors=[error_msg],
|
|
217
221
|
)
|
|
218
222
|
|
|
@@ -232,12 +236,21 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
232
236
|
return RegisterManualResult(
|
|
233
237
|
success=False,
|
|
234
238
|
manual_call_template=manual_call_template,
|
|
235
|
-
manual=UtcpManual(
|
|
239
|
+
manual=UtcpManual(manual_version="0.0.0", tools=[]),
|
|
236
240
|
errors=[error_msg],
|
|
237
241
|
)
|
|
238
242
|
|
|
239
243
|
async def deregister_manual(self, caller, manual_call_template: CallTemplate) -> None:
|
|
240
|
-
"""
|
|
244
|
+
"""REQUIRED
|
|
245
|
+
Deregisters a CLI manual.
|
|
246
|
+
|
|
247
|
+
For the CLI protocol, this is a no-op as there are no persistent
|
|
248
|
+
connections to terminate.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
caller: The UTCP client instance that is calling this method.
|
|
252
|
+
manual_call_template: The call template of the manual to deregister.
|
|
253
|
+
"""
|
|
241
254
|
if isinstance(manual_call_template, CliCallTemplate):
|
|
242
255
|
self._log_info(
|
|
243
256
|
f"Deregistering CLI manual '{manual_call_template.name}' (no-op)"
|
|
@@ -285,12 +298,12 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
285
298
|
# Fallback: try to parse tools from possibly-legacy structure
|
|
286
299
|
tools = self._parse_tool_data(data, provider_name)
|
|
287
300
|
if tools:
|
|
288
|
-
return UtcpManual(
|
|
301
|
+
return UtcpManual(manual_version="0.0.0", tools=tools)
|
|
289
302
|
return None
|
|
290
303
|
# Fallback: try to parse as tools
|
|
291
304
|
tools = self._parse_tool_data(data, provider_name)
|
|
292
305
|
if tools:
|
|
293
|
-
return UtcpManual(
|
|
306
|
+
return UtcpManual(manual_version="0.0.0", tools=tools)
|
|
294
307
|
except json.JSONDecodeError:
|
|
295
308
|
pass
|
|
296
309
|
|
|
@@ -313,7 +326,7 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
313
326
|
# Fallback: try to parse tools from possibly-legacy structure
|
|
314
327
|
tools = self._parse_tool_data(data, provider_name)
|
|
315
328
|
if tools:
|
|
316
|
-
return UtcpManual(
|
|
329
|
+
return UtcpManual(manual_version="0.0.0", tools=tools)
|
|
317
330
|
return None
|
|
318
331
|
found_tools = self._parse_tool_data(data, provider_name)
|
|
319
332
|
aggregated_tools.extend(found_tools)
|
|
@@ -321,7 +334,7 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
321
334
|
continue
|
|
322
335
|
|
|
323
336
|
if aggregated_tools:
|
|
324
|
-
return UtcpManual(
|
|
337
|
+
return UtcpManual(manual_version="0.0.0", tools=aggregated_tools)
|
|
325
338
|
|
|
326
339
|
return None
|
|
327
340
|
|
|
@@ -399,23 +412,28 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
399
412
|
return tools
|
|
400
413
|
|
|
401
414
|
async def call_tool(self, caller, tool_name: str, tool_args: Dict[str, Any], tool_call_template: CallTemplate) -> Any:
|
|
402
|
-
"""
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
415
|
+
"""REQUIRED
|
|
416
|
+
Calls a CLI tool by executing its command.
|
|
417
|
+
|
|
418
|
+
This method constructs and executes the command specified in the
|
|
419
|
+
`CliCallTemplate`. It formats the provided `tool_args` as command-line
|
|
420
|
+
arguments and runs the command in a subprocess.
|
|
421
|
+
|
|
406
422
|
Args:
|
|
407
|
-
caller: The UTCP client that is calling this method.
|
|
408
|
-
tool_name:
|
|
409
|
-
tool_args:
|
|
410
|
-
tool_call_template: The CliCallTemplate for the tool
|
|
411
|
-
|
|
423
|
+
caller: The UTCP client instance that is calling this method.
|
|
424
|
+
tool_name: The name of the tool to call.
|
|
425
|
+
tool_args: A dictionary of arguments for the tool call.
|
|
426
|
+
tool_call_template: The `CliCallTemplate` for the tool.
|
|
427
|
+
|
|
412
428
|
Returns:
|
|
413
|
-
The
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
429
|
+
The result of the command execution. If the command exits with a code
|
|
430
|
+
of 0, it returns the content of stdout. If the exit code is non-zero,
|
|
431
|
+
it returns the content of stderr. The output is parsed as JSON if
|
|
432
|
+
possible; otherwise, it is returned as a raw string.
|
|
433
|
+
|
|
417
434
|
Raises:
|
|
418
|
-
ValueError: If
|
|
435
|
+
ValueError: If `tool_call_template` is not an instance of
|
|
436
|
+
`CliCallTemplate` or if `command_name` is not set.
|
|
419
437
|
"""
|
|
420
438
|
if not isinstance(tool_call_template, CliCallTemplate):
|
|
421
439
|
raise ValueError("CliCommunicationProtocol can only be used with CliCallTemplate")
|
|
@@ -471,12 +489,10 @@ class CliCommunicationProtocol(CommunicationProtocol):
|
|
|
471
489
|
raise
|
|
472
490
|
|
|
473
491
|
async def call_tool_streaming(self, caller, tool_name: str, tool_args: Dict[str, Any], tool_call_template: CallTemplate) -> AsyncGenerator[Any, None]:
|
|
474
|
-
"""
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
This is a no-op for CLI transports since they don't maintain connections.
|
|
492
|
+
"""REQUIRED
|
|
493
|
+
Streaming calls are not supported for the CLI protocol.
|
|
494
|
+
|
|
495
|
+
Raises:
|
|
496
|
+
NotImplementedError: Always, as this functionality is not supported.
|
|
481
497
|
"""
|
|
482
|
-
|
|
498
|
+
raise NotImplementedError("Streaming is not supported by the CLI communication protocol.")
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: utcp-cli
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: UTCP communication protocol plugin for wrapping local command-line tools.
|
|
5
|
+
Author: UTCP Contributors
|
|
6
|
+
License-Expression: MPL-2.0
|
|
7
|
+
Project-URL: Homepage, https://utcp.io
|
|
8
|
+
Project-URL: Source, https://github.com/universal-tool-calling-protocol/python-utcp
|
|
9
|
+
Project-URL: Issues, https://github.com/universal-tool-calling-protocol/python-utcp/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: utcp>=1.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: build; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
+
Requires-Dist: coverage; extra == "dev"
|
|
25
|
+
Requires-Dist: twine; extra == "dev"
|
|
26
|
+
|
|
27
|
+
# UTCP CLI Plugin
|
|
28
|
+
|
|
29
|
+
[](https://pepy.tech/projects/utcp-cli)
|
|
30
|
+
|
|
31
|
+
Command-line interface plugin for UTCP, enabling integration with command-line tools and processes.
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
- **Command Execution**: Run any command-line tool as a UTCP tool
|
|
36
|
+
- **Environment Variables**: Secure credential and configuration passing
|
|
37
|
+
- **Working Directory Control**: Execute commands in specific directories
|
|
38
|
+
- **Input/Output Handling**: Support for stdin, stdout, stderr processing
|
|
39
|
+
- **Cross-Platform**: Works on Windows, macOS, and Linux
|
|
40
|
+
- **Timeout Management**: Configurable execution timeouts
|
|
41
|
+
- **Argument Validation**: Optional input sanitization
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install utcp-cli
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from utcp.utcp_client import UtcpClient
|
|
53
|
+
|
|
54
|
+
# Basic CLI tool
|
|
55
|
+
client = await UtcpClient.create(config={
|
|
56
|
+
"manual_call_templates": [{
|
|
57
|
+
"name": "file_tools",
|
|
58
|
+
"call_template_type": "cli",
|
|
59
|
+
"command_name": "ls -la ${path}"
|
|
60
|
+
}]
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
result = await client.call_tool("file_tools.list", {"path": "/home"})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration Examples
|
|
67
|
+
|
|
68
|
+
### Basic Command
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"name": "file_ops",
|
|
72
|
+
"call_template_type": "cli",
|
|
73
|
+
"command_name": "ls -la ${path}",
|
|
74
|
+
"working_dir": "/tmp"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### With Environment Variables
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"name": "python_script",
|
|
82
|
+
"call_template_type": "cli",
|
|
83
|
+
"command_name": "python script.py ${input}",
|
|
84
|
+
"env_vars": {
|
|
85
|
+
"PYTHONPATH": "/custom/path",
|
|
86
|
+
"API_KEY": "${API_KEY}"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Processing JSON with jq
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"name": "json_processor",
|
|
95
|
+
"call_template_type": "cli",
|
|
96
|
+
"command_name": "jq '.data'",
|
|
97
|
+
"stdin": "${json_input}",
|
|
98
|
+
"timeout": 10
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Git Operations
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"name": "git_tools",
|
|
106
|
+
"call_template_type": "cli",
|
|
107
|
+
"command_name": "git ${operation} ${args}",
|
|
108
|
+
"working_dir": "${repo_path}",
|
|
109
|
+
"env_vars": {
|
|
110
|
+
"GIT_AUTHOR_NAME": "${author_name}",
|
|
111
|
+
"GIT_AUTHOR_EMAIL": "${author_email}"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Security Considerations
|
|
117
|
+
|
|
118
|
+
- Commands run in isolated subprocesses
|
|
119
|
+
- Environment variables provide secure credential passing
|
|
120
|
+
- Working directory restrictions limit file system access
|
|
121
|
+
- Input validation prevents command injection
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"name": "safe_grep",
|
|
126
|
+
"call_template_type": "cli",
|
|
127
|
+
"command_name": "grep ${pattern} ${file}",
|
|
128
|
+
"working_dir": "/safe/directory",
|
|
129
|
+
"allowed_args": {
|
|
130
|
+
"pattern": "^[a-zA-Z0-9_-]+$",
|
|
131
|
+
"file": "^[a-zA-Z0-9_./-]+\\.txt$"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Error Handling
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from utcp.exceptions import ToolCallError
|
|
140
|
+
import subprocess
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
result = await client.call_tool("cli_tool.command", {"arg": "value"})
|
|
144
|
+
except ToolCallError as e:
|
|
145
|
+
if isinstance(e.__cause__, subprocess.CalledProcessError):
|
|
146
|
+
print(f"Command failed with exit code {e.__cause__.returncode}")
|
|
147
|
+
print(f"stderr: {e.__cause__.stderr}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Common Use Cases
|
|
151
|
+
|
|
152
|
+
- **File Operations**: ls, find, grep, awk, sed
|
|
153
|
+
- **Data Processing**: jq, sort, uniq, cut
|
|
154
|
+
- **System Monitoring**: ps, top, df, netstat
|
|
155
|
+
- **Development Tools**: git, npm, pip, docker
|
|
156
|
+
- **Custom Scripts**: Python, bash, PowerShell scripts
|
|
157
|
+
|
|
158
|
+
## Testing CLI Tools
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
import pytest
|
|
162
|
+
from utcp.utcp_client import UtcpClient
|
|
163
|
+
|
|
164
|
+
@pytest.mark.asyncio
|
|
165
|
+
async def test_cli_tool():
|
|
166
|
+
client = await UtcpClient.create(config={
|
|
167
|
+
"manual_call_templates": [{
|
|
168
|
+
"name": "test_cli",
|
|
169
|
+
"call_template_type": "cli",
|
|
170
|
+
"command_name": "echo ${message}"
|
|
171
|
+
}]
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
result = await client.call_tool("test_cli.echo", {"message": "hello"})
|
|
175
|
+
assert "hello" in result["stdout"]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Related Documentation
|
|
179
|
+
|
|
180
|
+
- [Main UTCP Documentation](../../../README.md)
|
|
181
|
+
- [Core Package Documentation](../../../core/README.md)
|
|
182
|
+
- [HTTP Plugin](../http/README.md)
|
|
183
|
+
- [MCP Plugin](../mcp/README.md)
|
|
184
|
+
- [Text Plugin](../text/README.md)
|
|
185
|
+
|
|
186
|
+
## Examples
|
|
187
|
+
|
|
188
|
+
For complete examples, see the [UTCP examples repository](https://github.com/universal-tool-calling-protocol/utcp-examples).
|
utcp_cli-1.0.0/PKG-INFO
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: utcp-cli
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Universal Tool Calling Protocol (UTCP) client library for Python
|
|
5
|
-
Author: UTCP Contributors
|
|
6
|
-
License-Expression: MPL-2.0
|
|
7
|
-
Project-URL: Homepage, https://utcp.io
|
|
8
|
-
Project-URL: Source, https://github.com/universal-tool-calling-protocol/python-utcp
|
|
9
|
-
Project-URL: Issues, https://github.com/universal-tool-calling-protocol/python-utcp/issues
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
Requires-Dist: pydantic>=2.0
|
|
17
|
-
Requires-Dist: pyyaml>=6.0
|
|
18
|
-
Requires-Dist: utcp>=1.0
|
|
19
|
-
Provides-Extra: dev
|
|
20
|
-
Requires-Dist: build; extra == "dev"
|
|
21
|
-
Requires-Dist: pytest; extra == "dev"
|
|
22
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
23
|
-
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
-
Requires-Dist: coverage; extra == "dev"
|
|
25
|
-
Requires-Dist: twine; extra == "dev"
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
from typing import Optional, Dict, Literal
|
|
2
|
-
from pydantic import Field
|
|
3
|
-
|
|
4
|
-
from utcp.data.call_template import CallTemplate
|
|
5
|
-
from utcp.interfaces.serializer import Serializer
|
|
6
|
-
from utcp.exceptions import UtcpSerializerValidationError
|
|
7
|
-
import traceback
|
|
8
|
-
|
|
9
|
-
class CliCallTemplate(CallTemplate):
|
|
10
|
-
"""Call template configuration for Command Line Interface tools.
|
|
11
|
-
|
|
12
|
-
Enables execution of command-line tools and programs as UTCP providers.
|
|
13
|
-
Supports environment variable injection and custom working directories.
|
|
14
|
-
|
|
15
|
-
Attributes:
|
|
16
|
-
call_template_type: Always "cli" for CLI providers.
|
|
17
|
-
command_name: The name or path of the command to execute.
|
|
18
|
-
env_vars: Optional environment variables to set during command execution.
|
|
19
|
-
working_dir: Optional custom working directory for command execution.
|
|
20
|
-
auth: Always None - CLI providers don't support authentication.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
call_template_type: Literal["cli"] = "cli"
|
|
24
|
-
command_name: str
|
|
25
|
-
env_vars: Optional[Dict[str, str]] = Field(
|
|
26
|
-
default=None, description="Environment variables to set when executing the command"
|
|
27
|
-
)
|
|
28
|
-
working_dir: Optional[str] = Field(
|
|
29
|
-
default=None, description="Working directory for command execution"
|
|
30
|
-
)
|
|
31
|
-
auth: None = None
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class CliCallTemplateSerializer(Serializer[CliCallTemplate]):
|
|
35
|
-
"""Serializer for CliCallTemplate."""
|
|
36
|
-
|
|
37
|
-
def to_dict(self, obj: CliCallTemplate) -> dict:
|
|
38
|
-
return obj.model_dump()
|
|
39
|
-
|
|
40
|
-
def validate_dict(self, obj: dict) -> CliCallTemplate:
|
|
41
|
-
try:
|
|
42
|
-
return CliCallTemplate.model_validate(obj)
|
|
43
|
-
except Exception as e:
|
|
44
|
-
raise UtcpSerializerValidationError("Invalid CliCallTemplate: " + traceback.format_exc()) from e
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: utcp-cli
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Universal Tool Calling Protocol (UTCP) client library for Python
|
|
5
|
-
Author: UTCP Contributors
|
|
6
|
-
License-Expression: MPL-2.0
|
|
7
|
-
Project-URL: Homepage, https://utcp.io
|
|
8
|
-
Project-URL: Source, https://github.com/universal-tool-calling-protocol/python-utcp
|
|
9
|
-
Project-URL: Issues, https://github.com/universal-tool-calling-protocol/python-utcp/issues
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Operating System :: OS Independent
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
Requires-Dist: pydantic>=2.0
|
|
17
|
-
Requires-Dist: pyyaml>=6.0
|
|
18
|
-
Requires-Dist: utcp>=1.0
|
|
19
|
-
Provides-Extra: dev
|
|
20
|
-
Requires-Dist: build; extra == "dev"
|
|
21
|
-
Requires-Dist: pytest; extra == "dev"
|
|
22
|
-
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
23
|
-
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
-
Requires-Dist: coverage; extra == "dev"
|
|
25
|
-
Requires-Dist: twine; extra == "dev"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|