chatatp-cli 1.0.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,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: chatatp-cli
3
+ Version: 1.0.0
4
+ Summary: ChatATP CLI - Terminal Interface for ChatATP API
5
+ Author-email: ChatATP Team <support@chatatp.com>
6
+ Project-URL: Homepage, https://chat-atp.com
7
+ Project-URL: Documentation, https://docs.chat-atp.com
8
+ Project-URL: Repository, https://github.com/sam-14uel/ChatATP-Python-Cli
9
+ Project-URL: Issues, https://github.com/sam-14uel/ChatATP-Python-Cli/issues
10
+ Requires-Dist: requests
11
+ Requires-Dist: click
12
+ Requires-Dist: rich
13
+ Requires-Dist: pyyaml
14
+ Requires-Dist: python-dotenv
@@ -0,0 +1,341 @@
1
+ # ChatATP CLI
2
+
3
+ A powerful terminal interface for the ChatATP API, built with Python. Interact with ChatATP's AI models, manage chatrooms, toolkits, integrations, and more directly from your command line.
4
+
5
+ ## ✨ What's New (v1.0.0)
6
+
7
+ ### 🚀 Agentic Loop Support
8
+ - **Interactive Conversations**: Back-and-forth chat with persistent context
9
+ - **Real-time Streaming**: Responses appear as they're generated with tool call visualization
10
+ - **Auto-enter Chatrooms**: `chat new` now creates AND enters chat automatically
11
+ - **In-chat Commands**: Rich command system during conversations (`/exit`, `/help`, `/clear`, `/history`)
12
+
13
+ ### 🔄 Chat Evolution
14
+ - **Before**: One-shot messages that exit immediately
15
+ - **Now**: Persistent interactive sessions with agentic conversations
16
+ - **Streaming**: Tool calls, thinking blocks, and responses all visualized in real-time
17
+
18
+ ## Features
19
+
20
+ - **Account Management**: View your ChatATP account information
21
+ - **Model Management**: List and manage AI models
22
+ - **Interactive Chat**: Agentic loop support with back-and-forth conversations
23
+ - **Toolkit Management**: Browse and manage your toolkits and collections
24
+ - **Integration Management**: Manage OAuth and custom integrations
25
+ - **AI Configuration**: Configure AI providers, models, and settings
26
+ - **Media Management**: Browse and manage uploaded media files
27
+ - **Store Access**: Browse featured and popular toolkits
28
+ - **MCP Support**: Manage MCP servers and connections
29
+
30
+ ## Installation
31
+
32
+ ### From PyPI (Recommended)
33
+
34
+ ```bash
35
+ pip install chatatp-cli
36
+ ```
37
+
38
+ ### From Source
39
+
40
+ 1. Clone or download this repository
41
+ 2. Install dependencies:
42
+ ```bash
43
+ pip install -r requirements.txt
44
+ ```
45
+
46
+ 3. Make the script executable (optional):
47
+ ```bash
48
+ chmod +x main.py
49
+ ```
50
+
51
+ ## Configuration
52
+
53
+ Before using the CLI, you need to configure your API token:
54
+
55
+ ```bash
56
+ python main.py config set-token YOUR_API_TOKEN_HERE
57
+ ```
58
+
59
+ You can also configure other settings:
60
+
61
+ ```bash
62
+ # Set custom API base URL (default: https://api.chat-atp.com)
63
+ python main.py config set-base-url https://your-custom-api-url.com
64
+
65
+ # Set default model
66
+ python main.py config set-default-model gpt-oss-120b
67
+
68
+ # View current configuration
69
+ python main.py config show
70
+ ```
71
+
72
+ ## Usage
73
+
74
+ ### Getting Help
75
+
76
+ ```bash
77
+ python main.py --help
78
+ ```
79
+
80
+ ### Account Information
81
+
82
+ ```bash
83
+ python main.py account
84
+ ```
85
+
86
+ ### Models
87
+
88
+ ```bash
89
+ # List available models
90
+ python main.py models
91
+
92
+ # List models for a specific provider
93
+ python main.py ai provider-models PROVIDER_ID
94
+ ```
95
+
96
+ ## 🎯 Interactive Chat System
97
+
98
+ The ChatATP CLI now supports **true agentic conversations** with persistent context, just like chatting with ChatGPT or Claude!
99
+
100
+ ### New Interactive Commands
101
+
102
+ #### **Start New Interactive Chat**
103
+ ```bash
104
+ python main.py chat new "Tell me about machine learning"
105
+ ```
106
+ - Creates a new chatroom
107
+ - Automatically enters interactive mode
108
+ - Sends your initial message
109
+ - Starts back-and-forth conversation loop
110
+
111
+ #### **Enter Existing Chatroom**
112
+ ```bash
113
+ python main.py chat converse ROOM_ID
114
+ ```
115
+ - Enter any existing chatroom for interactive chat
116
+ - Continue conversations where you left off
117
+ - Same interactive experience as new chats
118
+
119
+ ### In-Chat Commands
120
+
121
+ While in interactive mode, you have access to these commands:
122
+
123
+ - **`/exit`**, **`/quit`**, **`/q`** - Exit the current chat session
124
+ - **`/help`**, **`/h`** - Show available commands
125
+ - **`/clear`** - Clear the screen and show current chat info
126
+ - **`/history`** - Show recent messages from chat history
127
+
128
+ ### Interactive Chat Flow
129
+
130
+ ```
131
+ $ python main.py chat new "Hello, let's discuss AI"
132
+
133
+ Chatroom created: abc123
134
+ Entered chatroom: abc123
135
+ Type your message or '/exit' to quit, '/help' for commands
136
+
137
+ You: Hello, let's discuss AI
138
+
139
+ ChatATP ·
140
+
141
+ Hello! I'd be happy to discuss AI with you. What specific aspects of artificial intelligence are you interested in? Whether it's machine learning algorithms, current trends, ethical considerations, or practical applications, I'm here to help!
142
+
143
+ ─────────────────────────────────
144
+ You: Tell me about neural networks
145
+
146
+ ChatATP ·
147
+
148
+ Neural networks are fascinating! Let me explain them step by step:
149
+
150
+ A neural network is a computational model inspired by the human brain's neural structure. It consists of interconnected nodes (neurons) organized in layers...
151
+
152
+ ─────────────────────────────────
153
+ You: /help
154
+
155
+ Available commands:
156
+ /exit, /quit, /q - Exit the chat
157
+ /help, /h - Show this help
158
+ /clear - Clear the screen
159
+ /history - Show chat history
160
+
161
+ You: /exit
162
+ Exiting chat...
163
+ ```
164
+
165
+ ### Legacy Commands (Still Supported)
166
+
167
+ #### **One-shot Message Sending**
168
+ ```bash
169
+ # Send single message (legacy - exits immediately)
170
+ python main.py chat send ROOM_ID "Your message here"
171
+
172
+ # Send with specific model and toolkits
173
+ python main.py chat send ROOM_ID "Analyze this data" --model gpt-oss-120b --toolkits TOOLKIT_ID1 TOOLKIT_ID2
174
+
175
+ # Debug mode to see raw chunks
176
+ python main.py chat send ROOM_ID "Debug message" --debug
177
+ ```
178
+
179
+ #### **Chatroom Management**
180
+ ```bash
181
+ # List your chatrooms
182
+ python main.py chat rooms
183
+
184
+ # Show details of a specific chatroom
185
+ python main.py chat show ROOM_ID
186
+ ```
187
+
188
+ ### Toolkits
189
+
190
+ ```bash
191
+ # List your toolkits
192
+ python main.py toolkits
193
+
194
+ # Browse featured toolkits
195
+ python main.py store featured
196
+
197
+ # Browse popular toolkits
198
+ python main.py store popular
199
+ ```
200
+
201
+ ### Integrations
202
+
203
+ ```bash
204
+ # List OAuth integrations
205
+ python main.py integrations list
206
+
207
+ # List custom integrations
208
+ python main.py integrations custom
209
+ ```
210
+
211
+ ### AI Management
212
+
213
+ ```bash
214
+ # List AI providers
215
+ python main.py ai providers
216
+
217
+ # List AI configurations
218
+ python main.py ai configs
219
+
220
+ # Show AI settings
221
+ python main.py ai settings
222
+ ```
223
+
224
+ ### Media
225
+
226
+ ```bash
227
+ # List your media files
228
+ python main.py media
229
+
230
+ # Search media
231
+ python main.py media --search "document name"
232
+
233
+ # Filter by type
234
+ python main.py media --type image
235
+
236
+ # Pagination
237
+ python main.py media --page 2 --page-size 20
238
+ ```
239
+
240
+ ### Pricing
241
+
242
+ ```bash
243
+ # View pricing plans
244
+ python main.py pricing
245
+ ```
246
+
247
+ ## Authentication
248
+
249
+ All commands require authentication. Make sure you've set your API token using:
250
+
251
+ ```bash
252
+ python main.py config set-token YOUR_TOKEN
253
+ ```
254
+
255
+ The token will be stored securely in your home directory under `~/.chatatp/config.yaml`.
256
+
257
+ ## Advanced Features
258
+
259
+ ### Real-time Streaming with Tool Visualization
260
+
261
+ The CLI now provides rich visualization of:
262
+
263
+ - **Tool Calls**: See when tools are being executed with timing
264
+ - **Thinking Blocks**: Visual indicators when AI is reasoning
265
+ - **Progress Indicators**: Spinners and status updates during processing
266
+ - **Error Handling**: Graceful handling of network issues and API errors
267
+
268
+ ### Example with Tool Calls
269
+
270
+ ```
271
+ You: Search for information about OpenClaw AI
272
+
273
+ ChatATP ·
274
+
275
+ I need to search for information about OpenClaw AI. Let me use the search tool.
276
+
277
+ ┌ search_web · web_search_toolkit
278
+ └ done 0.34s
279
+
280
+ Based on my search, OpenClaw is...
281
+ ```
282
+
283
+ ### Interactive vs One-shot Mode Comparison
284
+
285
+ | Feature | Interactive Mode (`chat new/converse`) | One-shot Mode (`chat send`) |
286
+ |---------|----------------------------------------|----------------------------|
287
+ | **Persistence** | ✅ Back-and-forth conversation | ❌ Single message only |
288
+ | **Context** | ✅ Full conversation history | ❌ No context retention |
289
+ | **Commands** | ✅ Rich in-chat commands | ❌ None |
290
+ | **Tool Visualization** | ✅ Real-time with progress | ✅ Basic streaming |
291
+ | **Exit Behavior** | Manual exit with `/exit` | Auto-exit after response |
292
+ | **Use Case** | Deep conversations, exploration | Quick questions, automation |
293
+
294
+ ## Error Handling
295
+
296
+ The CLI provides clear error messages for common issues:
297
+ - Missing API token
298
+ - Invalid room IDs
299
+ - Network errors
300
+ - Authentication failures
301
+ - Streaming interruptions
302
+
303
+ ## Dependencies
304
+
305
+ - requests: HTTP client
306
+ - click: Command line interface
307
+ - rich: Beautiful terminal output with progress indicators
308
+ - pyyaml: Configuration file handling
309
+ - python-dotenv: Environment variable support
310
+
311
+ ## Migration Guide
312
+
313
+ ### From v1.x to v2.0
314
+
315
+ **Old workflow:**
316
+ ```bash
317
+ # Create room
318
+ python main.py chat new "Hello"
319
+ # Copy room ID
320
+ # Send messages one by one
321
+ python main.py chat send ROOM_ID "Follow up question"
322
+ python main.py chat send ROOM_ID "Another question"
323
+ ```
324
+
325
+ **New workflow:**
326
+ ```bash
327
+ # Single command starts interactive session
328
+ python main.py chat new "Hello, let's have a conversation"
329
+ # Now chat back and forth naturally!
330
+ # Type /exit when done
331
+ ```
332
+
333
+ **Legacy commands still work:** All v1.x commands (`chat send`, etc.) remain fully functional for scripts and automation.
334
+
335
+ ## Contributing
336
+
337
+ Feel free to submit issues and pull requests to improve the ChatATP CLI.
338
+
339
+ ## License
340
+
341
+ This project is licensed under the MIT License.
File without changes
@@ -0,0 +1,183 @@
1
+ import requests
2
+ from typing import Dict, List, Optional, Any
3
+ import json
4
+ from config import Config
5
+
6
+ class ChatATPAPI:
7
+ def __init__(self, config: Config):
8
+ self.config = config
9
+ self.session = requests.Session()
10
+ self.session.headers.update(self.config.get_headers())
11
+
12
+ def _get(self, endpoint: str, params: Optional[Dict] = None) -> Dict:
13
+ """Make GET request"""
14
+ url = f"{self.config.api_base_url}{endpoint}"
15
+ response = self.session.get(url, params=params)
16
+ response.raise_for_status()
17
+ return response.json()
18
+
19
+ def _post(self, endpoint: str, data: Optional[Dict] = None) -> Dict:
20
+ """Make POST request"""
21
+ url = f"{self.config.api_base_url}{endpoint}"
22
+ response = self.session.post(url, json=data)
23
+ response.raise_for_status()
24
+ return response.json()
25
+
26
+ def _patch(self, endpoint: str, data: Optional[Dict] = None) -> Dict:
27
+ """Make PATCH request"""
28
+ url = f"{self.config.api_base_url}{endpoint}"
29
+ response = self.session.patch(url, json=data)
30
+ response.raise_for_status()
31
+ return response.json()
32
+
33
+ def _delete(self, endpoint: str) -> Dict:
34
+ """Make DELETE request"""
35
+ url = f"{self.config.api_base_url}{endpoint}"
36
+ response = self.session.delete(url)
37
+ response.raise_for_status()
38
+ return response.json() if response.content else {}
39
+
40
+ # Account endpoints
41
+ def get_account(self) -> Dict:
42
+ """Get user account information"""
43
+ return self._get('/api/v1/account/')
44
+
45
+ # Models endpoints
46
+ def list_models(self) -> List[Dict]:
47
+ """List available models"""
48
+ return self._get('/api/v1/list-models/')
49
+
50
+ # Collections/Toolkits endpoints
51
+ def list_collections(self) -> Dict:
52
+ """List toolkits collections"""
53
+ return self._get('/api/v1/collections/toolkits/')
54
+
55
+ # MCP endpoints
56
+ def list_mcp_connections(self) -> Dict:
57
+ """List MCP connections"""
58
+ return self._get('/api/v1/mcp/connections/')
59
+
60
+ def list_mcp_servers(self) -> Dict:
61
+ """List MCP servers"""
62
+ return self._get('/api/v1/mcp/servers/')
63
+
64
+ # Chat endpoints
65
+ def list_chatrooms(self) -> Dict:
66
+ """List chatrooms"""
67
+ return self._get('/api/v1/chatrooms/')
68
+
69
+ def get_chatroom(self, room_id: str) -> Dict:
70
+ """Get chatroom details"""
71
+ return self._get(f'/api/v1/chats/{room_id}/')
72
+
73
+ def create_chatroom(self, message: str, model: str = None, toolkit_ids: List[str] = None,
74
+ mcp_server_connection_ids: List[str] = None) -> Dict:
75
+ """Create new chatroom"""
76
+ data = {'message': message}
77
+ if model:
78
+ data['model'] = model
79
+ if toolkit_ids:
80
+ data['toolkit_ids'] = toolkit_ids
81
+ if mcp_server_connection_ids:
82
+ data['mcp_server_connection_ids'] = mcp_server_connection_ids
83
+ return self._post('/api/v1/chats/new/', data)
84
+
85
+ def send_chat_message_stream(self, room_id: str, message: str, model: str = None,
86
+ toolkit_ids: List[str] = None, mcp_server_connection_ids: List[str] = None,
87
+ attachments: List = None):
88
+ """Send chat message and yield streaming response chunks"""
89
+ url = f"{self.config.api_base_url}/api/v1/chats/{room_id}/completions/stream/"
90
+ data = {
91
+ 'message_type': 'chat_message',
92
+ 'message': message,
93
+ 'model': model or self.config.default_model,
94
+ 'toolkit_ids': toolkit_ids or [],
95
+ 'mcp_server_connection_ids': mcp_server_connection_ids or [],
96
+ 'attachments': attachments or []
97
+ }
98
+
99
+ with self.session.post(url, json=data, stream=True) as response:
100
+ response.raise_for_status()
101
+ buffer = ""
102
+
103
+ for line in response.iter_lines():
104
+ if not line:
105
+ continue
106
+
107
+ line = line.decode('utf-8')
108
+
109
+ # Handle SSE format: "data: {...}"
110
+ if line.startswith('data: '):
111
+ line = line[6:]
112
+
113
+ # Skip SSE comments or keep-alive
114
+ if line.startswith(':'):
115
+ continue
116
+
117
+ buffer += line
118
+
119
+ # Try to parse whatever is in the buffer
120
+ while buffer:
121
+ buffer = buffer.strip()
122
+ if not buffer:
123
+ break
124
+ try:
125
+ chunk, idx = json.JSONDecoder().raw_decode(buffer)
126
+ yield chunk
127
+ buffer = buffer[idx:].strip()
128
+ except json.JSONDecodeError:
129
+ # Incomplete JSON, wait for more data
130
+ break
131
+
132
+ # Media endpoints
133
+ def list_media(self, page: int = 1, page_size: int = 12, media_type: str = None, search: str = None) -> Dict:
134
+ """List user media"""
135
+ params = {'page': page, 'page_size': page_size}
136
+ if media_type:
137
+ params['type'] = media_type
138
+ if search:
139
+ params['search'] = search
140
+ return self._get('/api/v1/media/', params)
141
+
142
+ # Integrations endpoints
143
+ def list_integrations(self) -> Dict:
144
+ """List integrated accounts"""
145
+ return self._get('/api/v1/integrations/')
146
+
147
+ def list_custom_integrations(self) -> Dict:
148
+ """List custom integrated accounts"""
149
+ return self._get('/api/v1/integrations/custom/')
150
+
151
+ def list_ai_configs(self) -> List[Dict]:
152
+ """List AI provider configurations"""
153
+ return self._get('/api/v1/integrations/ai/providers/configs/')
154
+
155
+ def list_ai_providers(self) -> List[Dict]:
156
+ """List AI providers"""
157
+ return self._get('/api/v1/integrations/ai/providers/')
158
+
159
+ def list_provider_models(self, provider_id: str) -> List[Dict]:
160
+ """List models for a provider"""
161
+ return self._get('/api/v1/list-provider-models/', {'provider': provider_id})
162
+
163
+ def get_ai_settings(self) -> Dict:
164
+ """Get AI settings"""
165
+ return self._get('/api/v1/integrations/ai/settings/')
166
+
167
+ # Store endpoints
168
+ def list_featured_toolkits(self) -> Dict:
169
+ """List featured toolkits"""
170
+ return self._get('/api/v1/store/toolkits/featured/')
171
+
172
+ def list_popular_toolkits(self) -> Dict:
173
+ """List popular toolkits"""
174
+ return self._get('/api/v1/store/toolkits/popular/')
175
+
176
+ def list_recommended_toolkits(self) -> Dict:
177
+ """List recommended toolkits"""
178
+ return self._get('/api/v1/store/toolkits/for_you/')
179
+
180
+ # Pricing endpoints
181
+ def get_pricing(self) -> List[Dict]:
182
+ """Get pricing information"""
183
+ return self._get('/api/v1/payments/pricing/')
@@ -0,0 +1,68 @@
1
+ import os
2
+ from typing import Optional
3
+ import yaml
4
+ from pathlib import Path
5
+
6
+ class Config:
7
+ def __init__(self, config_file: str = None):
8
+ self.config_file = config_file or os.path.join(Path.home(), '.chatatp', 'config.yaml')
9
+ self._config = {}
10
+ self.load_config()
11
+
12
+ def load_config(self):
13
+ """Load configuration from file"""
14
+ try:
15
+ if os.path.exists(self.config_file):
16
+ with open(self.config_file, 'r') as f:
17
+ self._config = yaml.safe_load(f) or {}
18
+ else:
19
+ self._config = {}
20
+ except Exception as e:
21
+ print(f"Warning: Could not load config file: {e}")
22
+ self._config = {}
23
+
24
+ def save_config(self):
25
+ """Save configuration to file"""
26
+ try:
27
+ os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
28
+ with open(self.config_file, 'w') as f:
29
+ yaml.dump(self._config, f, default_flow_style=False)
30
+ except Exception as e:
31
+ print(f"Error saving config: {e}")
32
+
33
+ @property
34
+ def api_base_url(self) -> str:
35
+ return self._config.get('api_base_url', 'https://api.chat-atp.com')
36
+
37
+ @api_base_url.setter
38
+ def api_base_url(self, value: str):
39
+ self._config['api_base_url'] = value
40
+ self.save_config()
41
+
42
+ @property
43
+ def api_token(self) -> Optional[str]:
44
+ return self._config.get('api_token')
45
+
46
+ @api_token.setter
47
+ def api_token(self, value: str):
48
+ self._config['api_token'] = value
49
+ self.save_config()
50
+
51
+ @property
52
+ def default_model(self) -> str:
53
+ return self._config.get('default_model', 'gpt-oss-120b')
54
+
55
+ @default_model.setter
56
+ def default_model(self, value: str):
57
+ self._config['default_model'] = value
58
+ self.save_config()
59
+
60
+ def get_headers(self) -> dict:
61
+ """Get headers for API requests"""
62
+ headers = {
63
+ 'Content-Type': 'application/json',
64
+ 'Accept': 'application/json'
65
+ }
66
+ if self.api_token:
67
+ headers['Authorization'] = f'Token {self.api_token}'
68
+ return headers