agent-brain-cli 1.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,95 @@
1
+ Metadata-Version: 2.3
2
+ Name: agent-brain-cli
3
+ Version: 1.1.0
4
+ Summary: CLI management tool for agent-brain-rag server
5
+ License: MIT
6
+ Keywords: rag,cli,documentation,semantic-search,ai-agent,brain
7
+ Author: Spillwave Solutions
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Dist: click (>=8.1.0,<9.0.0)
19
+ Requires-Dist: httpx (>=0.28.0,<0.29.0)
20
+ Requires-Dist: rich (>=13.9.0,<14.0.0)
21
+ Project-URL: Homepage, https://github.com/SpillwaveSolutions/doc-serve
22
+ Project-URL: Repository, https://github.com/SpillwaveSolutions/doc-serve
23
+ Description-Content-Type: text/markdown
24
+
25
+ # doc-svr-ctl
26
+
27
+ Command-line interface for managing the Doc-Serve document indexing and search server.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install doc-serve-cli
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```bash
38
+ doc-svr-ctl init # Initialize project
39
+ doc-svr-ctl start # Start server
40
+ doc-svr-ctl index ./docs # Index documents
41
+ doc-svr-ctl query "search term"
42
+ ```
43
+
44
+ ## Development Installation
45
+
46
+ ```bash
47
+ cd doc-svr-ctl
48
+ poetry install
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```bash
54
+ # Check server status
55
+ doc-svr-ctl status
56
+
57
+ # Search documents
58
+ doc-svr-ctl query "how to use python"
59
+
60
+ # Index documents from a folder
61
+ doc-svr-ctl index ./docs
62
+
63
+ # Reset/clear the index
64
+ doc-svr-ctl reset --yes
65
+ ```
66
+
67
+ ## Configuration
68
+
69
+ Set the server URL via environment variable:
70
+
71
+ ```bash
72
+ export DOC_SERVE_URL=http://localhost:8000
73
+ ```
74
+
75
+ Or use the `--url` flag:
76
+
77
+ ```bash
78
+ doc-svr-ctl --url http://localhost:8000 status
79
+ ```
80
+
81
+ ## Commands
82
+
83
+ | Command | Description |
84
+ |---------|-------------|
85
+ | `status` | Check server health and indexing status |
86
+ | `query` | Search indexed documents |
87
+ | `index` | Start indexing documents from a folder |
88
+ | `reset` | Clear all indexed documents |
89
+
90
+ ## Options
91
+
92
+ All commands support:
93
+ - `--url` - Server URL (or `DOC_SERVE_URL` env var)
94
+ - `--json` - Output as JSON for scripting
95
+
@@ -0,0 +1,70 @@
1
+ # doc-svr-ctl
2
+
3
+ Command-line interface for managing the Doc-Serve document indexing and search server.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install doc-serve-cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ doc-svr-ctl init # Initialize project
15
+ doc-svr-ctl start # Start server
16
+ doc-svr-ctl index ./docs # Index documents
17
+ doc-svr-ctl query "search term"
18
+ ```
19
+
20
+ ## Development Installation
21
+
22
+ ```bash
23
+ cd doc-svr-ctl
24
+ poetry install
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ # Check server status
31
+ doc-svr-ctl status
32
+
33
+ # Search documents
34
+ doc-svr-ctl query "how to use python"
35
+
36
+ # Index documents from a folder
37
+ doc-svr-ctl index ./docs
38
+
39
+ # Reset/clear the index
40
+ doc-svr-ctl reset --yes
41
+ ```
42
+
43
+ ## Configuration
44
+
45
+ Set the server URL via environment variable:
46
+
47
+ ```bash
48
+ export DOC_SERVE_URL=http://localhost:8000
49
+ ```
50
+
51
+ Or use the `--url` flag:
52
+
53
+ ```bash
54
+ doc-svr-ctl --url http://localhost:8000 status
55
+ ```
56
+
57
+ ## Commands
58
+
59
+ | Command | Description |
60
+ |---------|-------------|
61
+ | `status` | Check server health and indexing status |
62
+ | `query` | Search indexed documents |
63
+ | `index` | Start indexing documents from a folder |
64
+ | `reset` | Clear all indexed documents |
65
+
66
+ ## Options
67
+
68
+ All commands support:
69
+ - `--url` - Server URL (or `DOC_SERVE_URL` env var)
70
+ - `--json` - Output as JSON for scripting
@@ -0,0 +1,3 @@
1
+ """Doc-Serve CLI - Command-line interface for managing Doc-Serve server."""
2
+
3
+ __version__ = "1.1.0"
@@ -0,0 +1,70 @@
1
+ """Main CLI entry point for doc-svr-ctl."""
2
+
3
+ import click
4
+
5
+ from . import __version__
6
+ from .commands import (
7
+ index_command,
8
+ init_command,
9
+ list_command,
10
+ query_command,
11
+ reset_command,
12
+ start_command,
13
+ status_command,
14
+ stop_command,
15
+ )
16
+
17
+
18
+ @click.group()
19
+ @click.version_option(version=__version__, prog_name="doc-svr-ctl")
20
+ def cli() -> None:
21
+ """Doc-Serve CLI - Manage and query the Doc-Serve server.
22
+
23
+ A command-line interface for interacting with the Doc-Serve document
24
+ indexing and semantic search API.
25
+
26
+ \b
27
+ Project Commands:
28
+ init Initialize a new doc-serve project
29
+ start Start the server for this project
30
+ stop Stop the server for this project
31
+ list List all running doc-serve instances
32
+
33
+ \b
34
+ Server Commands:
35
+ status Check server status
36
+ query Search documents
37
+ index Index documents from a folder
38
+ reset Clear all indexed documents
39
+
40
+ \b
41
+ Examples:
42
+ doc-svr-ctl init # Initialize project
43
+ doc-svr-ctl start # Start server
44
+ doc-svr-ctl status # Check server status
45
+ doc-svr-ctl query "how to use python" # Search documents
46
+ doc-svr-ctl index ./docs # Index documents
47
+ doc-svr-ctl stop # Stop server
48
+
49
+ \b
50
+ Environment Variables:
51
+ DOC_SERVE_URL Server URL (default: http://127.0.0.1:8000)
52
+ """
53
+ pass
54
+
55
+
56
+ # Register project management commands
57
+ cli.add_command(init_command, name="init")
58
+ cli.add_command(start_command, name="start")
59
+ cli.add_command(stop_command, name="stop")
60
+ cli.add_command(list_command, name="list")
61
+
62
+ # Register server interaction commands
63
+ cli.add_command(status_command, name="status")
64
+ cli.add_command(query_command, name="query")
65
+ cli.add_command(index_command, name="index")
66
+ cli.add_command(reset_command, name="reset")
67
+
68
+
69
+ if __name__ == "__main__":
70
+ cli()
@@ -0,0 +1,5 @@
1
+ """HTTP client for communicating with Doc-Serve server."""
2
+
3
+ from .api_client import ConnectionError, DocServeClient, DocServeError, ServerError
4
+
5
+ __all__ = ["DocServeClient", "DocServeError", "ConnectionError", "ServerError"]
@@ -0,0 +1,334 @@
1
+ """HTTP client for Doc-Serve API communication."""
2
+
3
+ from dataclasses import dataclass
4
+ from types import TracebackType
5
+ from typing import Any, Optional
6
+
7
+ import httpx
8
+
9
+
10
+ class DocServeError(Exception):
11
+ """Base exception for Doc-Serve client errors."""
12
+
13
+ pass
14
+
15
+
16
+ class ConnectionError(DocServeError):
17
+ """Raised when unable to connect to the server."""
18
+
19
+ pass
20
+
21
+
22
+ class ServerError(DocServeError):
23
+ """Raised when server returns an error response."""
24
+
25
+ def __init__(self, message: str, status_code: int, detail: Optional[str] = None):
26
+ super().__init__(message)
27
+ self.status_code = status_code
28
+ self.detail = detail
29
+
30
+
31
+ @dataclass
32
+ class HealthStatus:
33
+ """Server health status."""
34
+
35
+ status: str
36
+ message: Optional[str]
37
+ version: str
38
+ timestamp: str
39
+
40
+
41
+ @dataclass
42
+ class IndexingStatus:
43
+ """Detailed indexing status."""
44
+
45
+ total_documents: int
46
+ total_chunks: int
47
+ indexing_in_progress: bool
48
+ current_job_id: Optional[str]
49
+ progress_percent: float
50
+ last_indexed_at: Optional[str]
51
+ indexed_folders: list[str]
52
+
53
+
54
+ @dataclass
55
+ class QueryResult:
56
+ """Single query result."""
57
+
58
+ text: str
59
+ source: str
60
+ score: float
61
+ chunk_id: str
62
+ metadata: dict[str, Any]
63
+ vector_score: Optional[float] = None
64
+ bm25_score: Optional[float] = None
65
+
66
+
67
+ @dataclass
68
+ class QueryResponse:
69
+ """Query response with results."""
70
+
71
+ results: list[QueryResult]
72
+ query_time_ms: float
73
+ total_results: int
74
+
75
+
76
+ @dataclass
77
+ class IndexResponse:
78
+ """Indexing operation response."""
79
+
80
+ job_id: str
81
+ status: str
82
+ message: Optional[str]
83
+
84
+
85
+ class DocServeClient:
86
+ """HTTP client for Doc-Serve API."""
87
+
88
+ def __init__(
89
+ self,
90
+ base_url: str = "http://127.0.0.1:8000",
91
+ timeout: float = 30.0,
92
+ ):
93
+ """
94
+ Initialize the client.
95
+
96
+ Args:
97
+ base_url: Server base URL.
98
+ timeout: Request timeout in seconds.
99
+ """
100
+ self.base_url = base_url.rstrip("/")
101
+ self.timeout = timeout
102
+ self._client = httpx.Client(timeout=timeout)
103
+
104
+ def __enter__(self) -> "DocServeClient":
105
+ return self
106
+
107
+ def __exit__(
108
+ self,
109
+ exc_type: Optional[type[BaseException]],
110
+ exc_val: Optional[BaseException],
111
+ exc_tb: Optional[TracebackType],
112
+ ) -> None:
113
+ self.close()
114
+
115
+ def close(self) -> None:
116
+ """Close the HTTP client."""
117
+ self._client.close()
118
+
119
+ def _request(
120
+ self,
121
+ method: str,
122
+ path: str,
123
+ json: Optional[dict[str, Any]] = None,
124
+ ) -> dict[str, Any]:
125
+ """
126
+ Make an HTTP request to the server.
127
+
128
+ Args:
129
+ method: HTTP method (GET, POST, DELETE).
130
+ path: API path.
131
+ json: Optional JSON body.
132
+
133
+ Returns:
134
+ Response JSON data.
135
+
136
+ Raises:
137
+ ConnectionError: If unable to connect.
138
+ ServerError: If server returns an error.
139
+ """
140
+ url = f"{self.base_url}{path}"
141
+
142
+ try:
143
+ response = self._client.request(method, url, json=json)
144
+ except httpx.ConnectError as e:
145
+ raise ConnectionError(
146
+ f"Unable to connect to server at {self.base_url}. "
147
+ f"Is the server running? Error: {e}"
148
+ ) from e
149
+ except httpx.TimeoutException as e:
150
+ raise ConnectionError(
151
+ f"Request timed out after {self.timeout}s. "
152
+ "The server may be overloaded or unresponsive."
153
+ ) from e
154
+
155
+ if response.status_code >= 400:
156
+ detail = None
157
+ try:
158
+ error_data = response.json()
159
+ detail = error_data.get("detail", str(error_data))
160
+ except Exception:
161
+ detail = response.text
162
+
163
+ raise ServerError(
164
+ f"Server returned {response.status_code}",
165
+ status_code=response.status_code,
166
+ detail=detail,
167
+ )
168
+
169
+ result: dict[str, Any] = response.json()
170
+ return result
171
+
172
+ def health(self) -> HealthStatus:
173
+ """
174
+ Get server health status.
175
+
176
+ Returns:
177
+ HealthStatus with current status.
178
+ """
179
+ data = self._request("GET", "/health/")
180
+ return HealthStatus(
181
+ status=data["status"],
182
+ message=data.get("message"),
183
+ version=data.get("version", "unknown"),
184
+ timestamp=data.get("timestamp", ""),
185
+ )
186
+
187
+ def status(self) -> IndexingStatus:
188
+ """
189
+ Get detailed indexing status.
190
+
191
+ Returns:
192
+ IndexingStatus with document counts and progress.
193
+ """
194
+ data = self._request("GET", "/health/status")
195
+ return IndexingStatus(
196
+ total_documents=data.get("total_documents", 0),
197
+ total_chunks=data.get("total_chunks", 0),
198
+ indexing_in_progress=data.get("indexing_in_progress", False),
199
+ current_job_id=data.get("current_job_id"),
200
+ progress_percent=data.get("progress_percent", 0.0),
201
+ last_indexed_at=data.get("last_indexed_at"),
202
+ indexed_folders=data.get("indexed_folders", []),
203
+ )
204
+
205
+ def query(
206
+ self,
207
+ query_text: str,
208
+ top_k: int = 5,
209
+ similarity_threshold: float = 0.7,
210
+ mode: str = "hybrid",
211
+ alpha: float = 0.5,
212
+ source_types: Optional[list[str]] = None,
213
+ languages: Optional[list[str]] = None,
214
+ file_paths: Optional[list[str]] = None,
215
+ ) -> QueryResponse:
216
+ """
217
+ Query indexed documents.
218
+
219
+ Args:
220
+ query_text: Search query.
221
+ top_k: Number of results to return.
222
+ similarity_threshold: Minimum similarity score.
223
+ mode: Retrieval mode (vector, bm25, hybrid).
224
+ alpha: Hybrid search weighting (1.0=vector, 0.0=bm25).
225
+ source_types: Filter by source types (doc, code, test).
226
+ languages: Filter by programming languages.
227
+ file_paths: Filter by file path patterns.
228
+
229
+ Returns:
230
+ QueryResponse with matching results.
231
+ """
232
+ request_data = {
233
+ "query": query_text,
234
+ "top_k": top_k,
235
+ "similarity_threshold": similarity_threshold,
236
+ "mode": mode,
237
+ "alpha": alpha,
238
+ }
239
+ if source_types is not None:
240
+ request_data["source_types"] = source_types
241
+ if languages is not None:
242
+ request_data["languages"] = languages
243
+ if file_paths is not None:
244
+ request_data["file_paths"] = file_paths
245
+
246
+ data = self._request("POST", "/query/", json=request_data)
247
+
248
+ results = [
249
+ QueryResult(
250
+ text=r["text"],
251
+ source=r["source"],
252
+ score=r["score"],
253
+ chunk_id=r["chunk_id"],
254
+ metadata=r.get("metadata", {}),
255
+ vector_score=r.get("vector_score"),
256
+ bm25_score=r.get("bm25_score"),
257
+ )
258
+ for r in data.get("results", [])
259
+ ]
260
+
261
+ return QueryResponse(
262
+ results=results,
263
+ query_time_ms=data.get("query_time_ms", 0.0),
264
+ total_results=data.get("total_results", len(results)),
265
+ )
266
+
267
+ def index(
268
+ self,
269
+ folder_path: str,
270
+ chunk_size: int = 512,
271
+ chunk_overlap: int = 50,
272
+ recursive: bool = True,
273
+ include_code: bool = False,
274
+ supported_languages: Optional[list[str]] = None,
275
+ code_chunk_strategy: str = "ast_aware",
276
+ include_patterns: Optional[list[str]] = None,
277
+ exclude_patterns: Optional[list[str]] = None,
278
+ generate_summaries: bool = False,
279
+ ) -> IndexResponse:
280
+ """
281
+ Start indexing documents and optionally code from a folder.
282
+
283
+ Args:
284
+ folder_path: Path to folder with documents.
285
+ chunk_size: Target chunk size in tokens.
286
+ chunk_overlap: Overlap between chunks.
287
+ recursive: Whether to scan recursively.
288
+ include_code: Whether to index source code files.
289
+ supported_languages: Languages to index (defaults to all).
290
+ code_chunk_strategy: Strategy for code chunking.
291
+ include_patterns: Additional include patterns.
292
+ exclude_patterns: Additional exclude patterns.
293
+ generate_summaries: Generate LLM summaries for code chunks.
294
+
295
+ Returns:
296
+ IndexResponse with job ID.
297
+ """
298
+ data = self._request(
299
+ "POST",
300
+ "/index/",
301
+ json={
302
+ "folder_path": folder_path,
303
+ "chunk_size": chunk_size,
304
+ "chunk_overlap": chunk_overlap,
305
+ "recursive": recursive,
306
+ "include_code": include_code,
307
+ "supported_languages": supported_languages,
308
+ "code_chunk_strategy": code_chunk_strategy,
309
+ "include_patterns": include_patterns,
310
+ "exclude_patterns": exclude_patterns,
311
+ "generate_summaries": generate_summaries,
312
+ },
313
+ )
314
+
315
+ return IndexResponse(
316
+ job_id=data["job_id"],
317
+ status=data["status"],
318
+ message=data.get("message"),
319
+ )
320
+
321
+ def reset(self) -> IndexResponse:
322
+ """
323
+ Reset the index by deleting all documents.
324
+
325
+ Returns:
326
+ IndexResponse confirming reset.
327
+ """
328
+ data = self._request("DELETE", "/index/")
329
+
330
+ return IndexResponse(
331
+ job_id=data.get("job_id", "reset"),
332
+ status=data["status"],
333
+ message=data.get("message"),
334
+ )
@@ -0,0 +1,21 @@
1
+ """CLI commands for doc-svr-ctl."""
2
+
3
+ from .index import index_command
4
+ from .init import init_command
5
+ from .list_cmd import list_command
6
+ from .query import query_command
7
+ from .reset import reset_command
8
+ from .start import start_command
9
+ from .status import status_command
10
+ from .stop import stop_command
11
+
12
+ __all__ = [
13
+ "index_command",
14
+ "init_command",
15
+ "list_command",
16
+ "query_command",
17
+ "reset_command",
18
+ "start_command",
19
+ "status_command",
20
+ "stop_command",
21
+ ]