deepflow-openagent-cli 0.1.0__tar.gz → 0.1.3__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.
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/PKG-INFO +31 -9
- deepflow_openagent_cli-0.1.3/README.md +69 -0
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/pyproject.toml +4 -4
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli/__init__.py +1 -1
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli/cli.py +150 -14
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/PKG-INFO +31 -9
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/SOURCES.txt +2 -1
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/requires.txt +1 -0
- deepflow_openagent_cli-0.1.3/tests/test_cli.py +249 -0
- deepflow_openagent_cli-0.1.0/README.md +0 -48
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/setup.cfg +0 -0
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli/__main__.py +0 -0
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/dependency_links.txt +0 -0
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/entry_points.txt +0 -0
- {deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepflow-openagent-cli
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Command-line client for
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Command-line client for OpenAgent OpenAPI (agents, conversations, SSE chat, tools, channels, knowledge bases).
|
|
5
5
|
Author: DeepFlow AI
|
|
6
|
-
Project-URL: Repository, https://github.com/DeepFlowAI/
|
|
6
|
+
Project-URL: Repository, https://github.com/DeepFlowAI/OpenAgent
|
|
7
7
|
Keywords: deepflow,openagent,newagent,openapi,cli,sse,chat
|
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
|
9
9
|
Classifier: Environment :: Console
|
|
@@ -16,11 +16,12 @@ Requires-Python: >=3.11
|
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
Provides-Extra: dev
|
|
18
18
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
19
20
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
20
21
|
|
|
21
22
|
# deepflow-openagent-cli
|
|
22
23
|
|
|
23
|
-
Python command-line client for the
|
|
24
|
+
Python command-line client for the OpenAgent OpenAPI: agents, conversations, SSE chat, tools, channels, documents, and knowledge bases.
|
|
24
25
|
|
|
25
26
|
## Install
|
|
26
27
|
|
|
@@ -31,8 +32,8 @@ pip install deepflow-openagent-cli
|
|
|
31
32
|
## Usage
|
|
32
33
|
|
|
33
34
|
```bash
|
|
34
|
-
export
|
|
35
|
-
export
|
|
35
|
+
export OPENAGENT_HOST="https://your-api-host"
|
|
36
|
+
export OPENAGENT_API_KEY="sk-..."
|
|
36
37
|
deepflow_openagent_cli docs list
|
|
37
38
|
deepflow_openagent_cli agents list
|
|
38
39
|
```
|
|
@@ -47,15 +48,36 @@ python -m deepflow_openagent_cli docs list
|
|
|
47
48
|
|
|
48
49
|
| Method | Variable / flag |
|
|
49
50
|
|--------|------------------|
|
|
50
|
-
| Host | `
|
|
51
|
-
| API key | `
|
|
51
|
+
| Host | `OPENAGENT_HOST` or `--host` |
|
|
52
|
+
| API key | `OPENAGENT_API_KEY` or `--api-key` |
|
|
53
|
+
|
|
54
|
+
Legacy `NEWAGENT_HOST` and `NEWAGENT_API_KEY` are still read as fallbacks.
|
|
55
|
+
|
|
56
|
+
When using flags, put global flags before the command:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
deepflow_openagent_cli --host http://localhost:5001 --api-key sk-... agents list
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Common commands
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
deepflow_openagent_cli docs show chat.stream --json
|
|
66
|
+
deepflow_openagent_cli knowledge list --page 1 --per-page 10
|
|
67
|
+
deepflow_openagent_cli knowledge documents 1
|
|
68
|
+
deepflow_openagent_cli knowledge query-document 6670 --slice-id 512208 --line 1720
|
|
69
|
+
deepflow_openagent_cli chat 1 --message "Hello"
|
|
70
|
+
deepflow_openagent_cli steps 1 42
|
|
71
|
+
deepflow_openagent_cli steps get 1 42 100
|
|
72
|
+
```
|
|
52
73
|
|
|
53
74
|
## Development (build wheel/sdist locally)
|
|
54
75
|
|
|
55
76
|
From this directory:
|
|
56
77
|
|
|
57
78
|
```bash
|
|
58
|
-
pip install
|
|
79
|
+
pip install -e ".[dev]"
|
|
80
|
+
pytest
|
|
59
81
|
python -m build
|
|
60
82
|
```
|
|
61
83
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# deepflow-openagent-cli
|
|
2
|
+
|
|
3
|
+
Python command-line client for the OpenAgent OpenAPI: agents, conversations, SSE chat, tools, channels, documents, and knowledge bases.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install deepflow-openagent-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
export OPENAGENT_HOST="https://your-api-host"
|
|
15
|
+
export OPENAGENT_API_KEY="sk-..."
|
|
16
|
+
deepflow_openagent_cli docs list
|
|
17
|
+
deepflow_openagent_cli agents list
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Equivalent module invocation:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
python -m deepflow_openagent_cli docs list
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Configure API host and key
|
|
27
|
+
|
|
28
|
+
| Method | Variable / flag |
|
|
29
|
+
|--------|------------------|
|
|
30
|
+
| Host | `OPENAGENT_HOST` or `--host` |
|
|
31
|
+
| API key | `OPENAGENT_API_KEY` or `--api-key` |
|
|
32
|
+
|
|
33
|
+
Legacy `NEWAGENT_HOST` and `NEWAGENT_API_KEY` are still read as fallbacks.
|
|
34
|
+
|
|
35
|
+
When using flags, put global flags before the command:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
deepflow_openagent_cli --host http://localhost:5001 --api-key sk-... agents list
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Common commands
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
deepflow_openagent_cli docs show chat.stream --json
|
|
45
|
+
deepflow_openagent_cli knowledge list --page 1 --per-page 10
|
|
46
|
+
deepflow_openagent_cli knowledge documents 1
|
|
47
|
+
deepflow_openagent_cli knowledge query-document 6670 --slice-id 512208 --line 1720
|
|
48
|
+
deepflow_openagent_cli chat 1 --message "Hello"
|
|
49
|
+
deepflow_openagent_cli steps 1 42
|
|
50
|
+
deepflow_openagent_cli steps get 1 42 100
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Development (build wheel/sdist locally)
|
|
54
|
+
|
|
55
|
+
From this directory:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install -e ".[dev]"
|
|
59
|
+
pytest
|
|
60
|
+
python -m build
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Upload to PyPI (use a **new** API token; never commit tokens):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python -m twine upload dist/*
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
When prompted, username is `__token__` and password is the token value.
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepflow-openagent-cli"
|
|
7
|
-
version = "0.1.
|
|
8
|
-
description = "Command-line client for
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "Command-line client for OpenAgent OpenAPI (agents, conversations, SSE chat, tools, channels, knowledge bases)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
authors = [{ name = "DeepFlow AI" }]
|
|
@@ -23,10 +23,10 @@ classifiers = [
|
|
|
23
23
|
dependencies = []
|
|
24
24
|
|
|
25
25
|
[project.optional-dependencies]
|
|
26
|
-
dev = ["build>=1.0", "twine>=5.0"]
|
|
26
|
+
dev = ["build>=1.0", "pytest>=8.0", "twine>=5.0"]
|
|
27
27
|
|
|
28
28
|
[project.urls]
|
|
29
|
-
Repository = "https://github.com/DeepFlowAI/
|
|
29
|
+
Repository = "https://github.com/DeepFlowAI/OpenAgent"
|
|
30
30
|
|
|
31
31
|
[project.scripts]
|
|
32
32
|
deepflow_openagent_cli = "deepflow_openagent_cli.cli:main"
|
{deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli/cli.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
OpenAgent OpenAPI command line client.
|
|
3
3
|
|
|
4
4
|
Run with:
|
|
5
5
|
deepflow_openagent_cli docs list
|
|
@@ -20,8 +20,10 @@ from urllib.request import Request, urlopen
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
DEFAULT_HOST = "http://localhost:5001"
|
|
23
|
-
ENV_HOST = "
|
|
24
|
-
ENV_API_KEY = "
|
|
23
|
+
ENV_HOST = "OPENAGENT_HOST"
|
|
24
|
+
ENV_API_KEY = "OPENAGENT_API_KEY"
|
|
25
|
+
LEGACY_ENV_HOST = "NEWAGENT_HOST"
|
|
26
|
+
LEGACY_ENV_API_KEY = "NEWAGENT_API_KEY"
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
class CliError(Exception):
|
|
@@ -56,6 +58,20 @@ def _param(name: str, type_: str, required: bool, description: str) -> ParamDoc:
|
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
ENDPOINTS: tuple[EndpointDoc, ...] = (
|
|
61
|
+
EndpointDoc(
|
|
62
|
+
key="knowledge.list",
|
|
63
|
+
method="GET",
|
|
64
|
+
path="/api/v1/knowledge-bases",
|
|
65
|
+
scope="chat",
|
|
66
|
+
summary="List knowledge bases for the current tenant.",
|
|
67
|
+
query_params=[
|
|
68
|
+
_param("page", "integer", False, "Page number."),
|
|
69
|
+
_param("per_page", "integer", False, "Items per page, 1-100."),
|
|
70
|
+
],
|
|
71
|
+
response="Paginated list of public knowledge base fields.",
|
|
72
|
+
errors=["401 missing or invalid API key", "403 scope missing", "422 validation error"],
|
|
73
|
+
example="deepflow_openagent_cli knowledge list --page 1 --per-page 10",
|
|
74
|
+
),
|
|
59
75
|
EndpointDoc(
|
|
60
76
|
key="knowledge.search",
|
|
61
77
|
method="POST",
|
|
@@ -90,6 +106,36 @@ ENDPOINTS: tuple[EndpointDoc, ...] = (
|
|
|
90
106
|
errors=["401 missing or invalid API key", "404 document not found"],
|
|
91
107
|
example="deepflow_openagent_cli knowledge markdown 1 20 --raw",
|
|
92
108
|
),
|
|
109
|
+
EndpointDoc(
|
|
110
|
+
key="knowledge.documents",
|
|
111
|
+
method="GET",
|
|
112
|
+
path="/api/v1/knowledge-bases/{kb_id}/documents",
|
|
113
|
+
scope="chat",
|
|
114
|
+
summary="List documents in a knowledge base without embedding Markdown content.",
|
|
115
|
+
path_params=[_param("kb_id", "integer", True, "Knowledge base ID.")],
|
|
116
|
+
query_params=[
|
|
117
|
+
_param("page", "integer", False, "Page number."),
|
|
118
|
+
_param("per_page", "integer", False, "Items per page, 1-100."),
|
|
119
|
+
],
|
|
120
|
+
response="Paginated list with id, file_path, title, slice_count, updated_at, doc_meta, and markdown_url.",
|
|
121
|
+
errors=["401 missing or invalid API key", "403 scope missing", "404 knowledge base not found", "422 validation error"],
|
|
122
|
+
example="deepflow_openagent_cli knowledge documents 1 --page 1 --per-page 20",
|
|
123
|
+
),
|
|
124
|
+
EndpointDoc(
|
|
125
|
+
key="documents.query",
|
|
126
|
+
method="POST",
|
|
127
|
+
path="/api/v1/documents/query",
|
|
128
|
+
scope="chat",
|
|
129
|
+
summary="Resolve a document reference by doc_id with optional slice_id and line.",
|
|
130
|
+
body_fields=[
|
|
131
|
+
_param("doc_id", "integer", True, "Document ID, positive integer."),
|
|
132
|
+
_param("slice_id", "integer", False, "Optional slice ID, must belong to doc_id when provided."),
|
|
133
|
+
_param("line", "integer", False, "Optional Markdown source line number, starting at 1."),
|
|
134
|
+
],
|
|
135
|
+
response="Resolved document fields with optional slice and line details.",
|
|
136
|
+
errors=["401 missing or invalid API key", "403 scope missing", "422 validation error"],
|
|
137
|
+
example="deepflow_openagent_cli knowledge query-document 6670 --slice-id 512208 --line 1720",
|
|
138
|
+
),
|
|
93
139
|
EndpointDoc(
|
|
94
140
|
key="conversations.create",
|
|
95
141
|
method="POST",
|
|
@@ -195,6 +241,21 @@ ENDPOINTS: tuple[EndpointDoc, ...] = (
|
|
|
195
241
|
errors=["401 missing or invalid API key", "404 conversation not found"],
|
|
196
242
|
example="deepflow_openagent_cli steps 1 42",
|
|
197
243
|
),
|
|
244
|
+
EndpointDoc(
|
|
245
|
+
key="steps.get",
|
|
246
|
+
method="GET",
|
|
247
|
+
path="/api/v1/agents/{agent_id}/conversations/{conversation_id}/steps/{step_id}",
|
|
248
|
+
scope="chat",
|
|
249
|
+
summary="Get full execution step detail, including LLM request/response payload fields.",
|
|
250
|
+
path_params=[
|
|
251
|
+
_param("agent_id", "integer", True, "Agent ID."),
|
|
252
|
+
_param("conversation_id", "integer", True, "Conversation ID."),
|
|
253
|
+
_param("step_id", "integer", True, "Step ID."),
|
|
254
|
+
],
|
|
255
|
+
response="StepDetailResponse with request_messages, request_tools, request_params, response fields, and child tool calls.",
|
|
256
|
+
errors=["401 missing or invalid API key", "404 step not found"],
|
|
257
|
+
example="deepflow_openagent_cli steps get 1 42 100",
|
|
258
|
+
),
|
|
198
259
|
EndpointDoc(
|
|
199
260
|
key="agents.list",
|
|
200
261
|
method="GET",
|
|
@@ -270,7 +331,7 @@ ENDPOINTS: tuple[EndpointDoc, ...] = (
|
|
|
270
331
|
summary="Partially update system_prompt, model, selected_tool_ids, context, or pre_recall.",
|
|
271
332
|
path_params=[_param("agent_id", "integer", True, "Agent ID.")],
|
|
272
333
|
body_fields=[
|
|
273
|
-
_param("system_prompt", "string", False, "System prompt, max
|
|
334
|
+
_param("system_prompt", "string", False, "System prompt, max 30000 chars."),
|
|
274
335
|
_param("model", "object", False, "Model config."),
|
|
275
336
|
_param("selected_tool_ids", "array[integer]", False, "Enabled tool IDs."),
|
|
276
337
|
_param("context", "object", False, "Context policy."),
|
|
@@ -301,7 +362,7 @@ ENDPOINTS: tuple[EndpointDoc, ...] = (
|
|
|
301
362
|
body_fields=[
|
|
302
363
|
_param("name", "string", True, "Tool name, 1-128 chars."),
|
|
303
364
|
_param("description", "string", False, "Tool description."),
|
|
304
|
-
_param("tool_type", "string", True, "search, doc_query, notebook, tool_response_fetch, or python_code."),
|
|
365
|
+
_param("tool_type", "string", True, "search, doc_query, doc_grep, notebook, tool_response_fetch, or python_code."),
|
|
305
366
|
_param("config", "object", False, "Tool config."),
|
|
306
367
|
],
|
|
307
368
|
response="AgentToolResponse.",
|
|
@@ -475,7 +536,7 @@ ENDPOINT_BY_KEY = {endpoint.key: endpoint for endpoint in ENDPOINTS}
|
|
|
475
536
|
|
|
476
537
|
|
|
477
538
|
class OpenApiClient:
|
|
478
|
-
"""Small HTTP client for
|
|
539
|
+
"""Small HTTP client for OpenAgent OpenAPI endpoints."""
|
|
479
540
|
|
|
480
541
|
def __init__(self, host: str, api_key: str | None) -> None:
|
|
481
542
|
self.host = host.rstrip("/")
|
|
@@ -639,8 +700,8 @@ def handle_docs(args: argparse.Namespace) -> int:
|
|
|
639
700
|
|
|
640
701
|
|
|
641
702
|
def client_from_args(args: argparse.Namespace) -> OpenApiClient:
|
|
642
|
-
host = args.host or os.getenv(ENV_HOST) or DEFAULT_HOST
|
|
643
|
-
api_key = args.api_key or os.getenv(ENV_API_KEY)
|
|
703
|
+
host = args.host or os.getenv(ENV_HOST) or os.getenv(LEGACY_ENV_HOST) or DEFAULT_HOST
|
|
704
|
+
api_key = args.api_key or os.getenv(ENV_API_KEY) or os.getenv(LEGACY_ENV_API_KEY)
|
|
644
705
|
return OpenApiClient(host=host, api_key=api_key)
|
|
645
706
|
|
|
646
707
|
|
|
@@ -665,9 +726,28 @@ def run_request(
|
|
|
665
726
|
|
|
666
727
|
|
|
667
728
|
def handle_knowledge(args: argparse.Namespace) -> int:
|
|
729
|
+
if args.knowledge_action == "list":
|
|
730
|
+
return run_request(args, "knowledge.list", query={"page": args.page, "per_page": args.per_page})
|
|
668
731
|
if args.knowledge_action == "search":
|
|
669
732
|
body = merge_payload(args, {"query": args.query})
|
|
670
733
|
return run_request(args, "knowledge.search", {"kb_id": args.kb_id}, body=body)
|
|
734
|
+
if args.knowledge_action == "documents":
|
|
735
|
+
return run_request(
|
|
736
|
+
args,
|
|
737
|
+
"knowledge.documents",
|
|
738
|
+
{"kb_id": args.kb_id},
|
|
739
|
+
query={"page": args.page, "per_page": args.per_page},
|
|
740
|
+
)
|
|
741
|
+
if args.knowledge_action == "query-document":
|
|
742
|
+
return run_request(
|
|
743
|
+
args,
|
|
744
|
+
"documents.query",
|
|
745
|
+
body={
|
|
746
|
+
"doc_id": args.doc_id,
|
|
747
|
+
"slice_id": args.slice_id,
|
|
748
|
+
"line": args.line,
|
|
749
|
+
},
|
|
750
|
+
)
|
|
671
751
|
return run_request(args, "knowledge.markdown", {"kb_id": args.kb_id, "doc_id": args.doc_id})
|
|
672
752
|
|
|
673
753
|
|
|
@@ -720,10 +800,24 @@ def handle_chat(args: argparse.Namespace) -> int:
|
|
|
720
800
|
|
|
721
801
|
|
|
722
802
|
def handle_steps(args: argparse.Namespace) -> int:
|
|
803
|
+
action, values = parse_steps_args(args.steps_args)
|
|
804
|
+
if action == "get":
|
|
805
|
+
agent_id, conversation_id, step_id = values
|
|
806
|
+
return run_request(
|
|
807
|
+
args,
|
|
808
|
+
"steps.get",
|
|
809
|
+
{
|
|
810
|
+
"agent_id": agent_id,
|
|
811
|
+
"conversation_id": conversation_id,
|
|
812
|
+
"step_id": step_id,
|
|
813
|
+
},
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
agent_id, conversation_id = values
|
|
723
817
|
return run_request(
|
|
724
818
|
args,
|
|
725
819
|
"steps.list",
|
|
726
|
-
{"agent_id":
|
|
820
|
+
{"agent_id": agent_id, "conversation_id": conversation_id},
|
|
727
821
|
)
|
|
728
822
|
|
|
729
823
|
|
|
@@ -829,7 +923,7 @@ def add_common_args(parser: argparse.ArgumentParser) -> None:
|
|
|
829
923
|
|
|
830
924
|
|
|
831
925
|
def build_parser() -> argparse.ArgumentParser:
|
|
832
|
-
parser = argparse.ArgumentParser(description="
|
|
926
|
+
parser = argparse.ArgumentParser(description="OpenAgent OpenAPI CLI")
|
|
833
927
|
add_common_args(parser)
|
|
834
928
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
835
929
|
|
|
@@ -843,10 +937,21 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
843
937
|
|
|
844
938
|
knowledge = subparsers.add_parser("knowledge", help="Knowledge base endpoints.")
|
|
845
939
|
knowledge_sub = knowledge.add_subparsers(dest="knowledge_action", required=True)
|
|
940
|
+
knowledge_list = knowledge_sub.add_parser("list")
|
|
941
|
+
knowledge_list.add_argument("--page", type=int)
|
|
942
|
+
knowledge_list.add_argument("--per-page", type=int)
|
|
846
943
|
knowledge_search = knowledge_sub.add_parser("search")
|
|
847
944
|
knowledge_search.add_argument("kb_id", type=int)
|
|
848
945
|
knowledge_search.add_argument("--query", required=True)
|
|
849
946
|
add_json_args(knowledge_search)
|
|
947
|
+
knowledge_documents = knowledge_sub.add_parser("documents")
|
|
948
|
+
knowledge_documents.add_argument("kb_id", type=int)
|
|
949
|
+
knowledge_documents.add_argument("--page", type=int)
|
|
950
|
+
knowledge_documents.add_argument("--per-page", type=int)
|
|
951
|
+
knowledge_query_document = knowledge_sub.add_parser("query-document")
|
|
952
|
+
knowledge_query_document.add_argument("doc_id", type=int)
|
|
953
|
+
knowledge_query_document.add_argument("--slice-id", type=int)
|
|
954
|
+
knowledge_query_document.add_argument("--line", type=int)
|
|
850
955
|
knowledge_markdown = knowledge_sub.add_parser("markdown")
|
|
851
956
|
knowledge_markdown.add_argument("kb_id", type=int)
|
|
852
957
|
knowledge_markdown.add_argument("doc_id", type=int)
|
|
@@ -891,9 +996,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
891
996
|
add_json_args(chat)
|
|
892
997
|
chat.set_defaults(handler=handle_chat)
|
|
893
998
|
|
|
894
|
-
steps = subparsers.add_parser(
|
|
895
|
-
|
|
896
|
-
|
|
999
|
+
steps = subparsers.add_parser(
|
|
1000
|
+
"steps",
|
|
1001
|
+
help="List conversation execution steps or get full step detail.",
|
|
1002
|
+
description=(
|
|
1003
|
+
"List conversation execution steps or get full step detail. "
|
|
1004
|
+
"Forms: steps <agent_id> <conversation_id>; "
|
|
1005
|
+
"steps get <agent_id> <conversation_id> <step_id>."
|
|
1006
|
+
),
|
|
1007
|
+
)
|
|
1008
|
+
steps.add_argument("steps_args", nargs="+", metavar="ARGS")
|
|
897
1009
|
steps.set_defaults(handler=handle_steps)
|
|
898
1010
|
|
|
899
1011
|
agents = subparsers.add_parser("agents", help="Agent endpoints.")
|
|
@@ -929,7 +1041,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
929
1041
|
tool_create.add_argument("agent_id", type=int)
|
|
930
1042
|
tool_create.add_argument("--name", required=True)
|
|
931
1043
|
tool_create.add_argument("--description")
|
|
932
|
-
tool_create.add_argument("--tool-type", required=True, choices=["search", "doc_query", "notebook", "tool_response_fetch", "python_code"])
|
|
1044
|
+
tool_create.add_argument("--tool-type", required=True, choices=["search", "doc_query", "doc_grep", "notebook", "tool_response_fetch", "python_code"])
|
|
933
1045
|
add_json_args(tool_create)
|
|
934
1046
|
for name in ("get", "delete"):
|
|
935
1047
|
tool_item = tool_sub.add_parser(name)
|
|
@@ -987,6 +1099,30 @@ def parse_bool(value: str) -> bool:
|
|
|
987
1099
|
raise argparse.ArgumentTypeError("Expected boolean: true/false")
|
|
988
1100
|
|
|
989
1101
|
|
|
1102
|
+
def parse_steps_args(values: list[str]) -> tuple[str, tuple[int, ...]]:
|
|
1103
|
+
action = "list"
|
|
1104
|
+
raw_values = values
|
|
1105
|
+
if values[0] in {"list", "get", "detail"}:
|
|
1106
|
+
action = "get" if values[0] == "detail" else values[0]
|
|
1107
|
+
raw_values = values[1:]
|
|
1108
|
+
elif len(values) == 3:
|
|
1109
|
+
action = "get"
|
|
1110
|
+
|
|
1111
|
+
expected = 3 if action == "get" else 2
|
|
1112
|
+
if len(raw_values) != expected:
|
|
1113
|
+
raise CliError(
|
|
1114
|
+
"Usage: steps <agent_id> <conversation_id> or "
|
|
1115
|
+
"steps get <agent_id> <conversation_id> <step_id>."
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1118
|
+
try:
|
|
1119
|
+
parsed = tuple(int(value) for value in raw_values)
|
|
1120
|
+
except ValueError as exc:
|
|
1121
|
+
raise CliError("steps arguments must be integers.") from exc
|
|
1122
|
+
|
|
1123
|
+
return action, parsed
|
|
1124
|
+
|
|
1125
|
+
|
|
990
1126
|
def main(argv: list[str] | None = None) -> int:
|
|
991
1127
|
parser = build_parser()
|
|
992
1128
|
args = parser.parse_args(argv)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepflow-openagent-cli
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Command-line client for
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Command-line client for OpenAgent OpenAPI (agents, conversations, SSE chat, tools, channels, knowledge bases).
|
|
5
5
|
Author: DeepFlow AI
|
|
6
|
-
Project-URL: Repository, https://github.com/DeepFlowAI/
|
|
6
|
+
Project-URL: Repository, https://github.com/DeepFlowAI/OpenAgent
|
|
7
7
|
Keywords: deepflow,openagent,newagent,openapi,cli,sse,chat
|
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
|
9
9
|
Classifier: Environment :: Console
|
|
@@ -16,11 +16,12 @@ Requires-Python: >=3.11
|
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
Provides-Extra: dev
|
|
18
18
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
19
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
19
20
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
20
21
|
|
|
21
22
|
# deepflow-openagent-cli
|
|
22
23
|
|
|
23
|
-
Python command-line client for the
|
|
24
|
+
Python command-line client for the OpenAgent OpenAPI: agents, conversations, SSE chat, tools, channels, documents, and knowledge bases.
|
|
24
25
|
|
|
25
26
|
## Install
|
|
26
27
|
|
|
@@ -31,8 +32,8 @@ pip install deepflow-openagent-cli
|
|
|
31
32
|
## Usage
|
|
32
33
|
|
|
33
34
|
```bash
|
|
34
|
-
export
|
|
35
|
-
export
|
|
35
|
+
export OPENAGENT_HOST="https://your-api-host"
|
|
36
|
+
export OPENAGENT_API_KEY="sk-..."
|
|
36
37
|
deepflow_openagent_cli docs list
|
|
37
38
|
deepflow_openagent_cli agents list
|
|
38
39
|
```
|
|
@@ -47,15 +48,36 @@ python -m deepflow_openagent_cli docs list
|
|
|
47
48
|
|
|
48
49
|
| Method | Variable / flag |
|
|
49
50
|
|--------|------------------|
|
|
50
|
-
| Host | `
|
|
51
|
-
| API key | `
|
|
51
|
+
| Host | `OPENAGENT_HOST` or `--host` |
|
|
52
|
+
| API key | `OPENAGENT_API_KEY` or `--api-key` |
|
|
53
|
+
|
|
54
|
+
Legacy `NEWAGENT_HOST` and `NEWAGENT_API_KEY` are still read as fallbacks.
|
|
55
|
+
|
|
56
|
+
When using flags, put global flags before the command:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
deepflow_openagent_cli --host http://localhost:5001 --api-key sk-... agents list
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Common commands
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
deepflow_openagent_cli docs show chat.stream --json
|
|
66
|
+
deepflow_openagent_cli knowledge list --page 1 --per-page 10
|
|
67
|
+
deepflow_openagent_cli knowledge documents 1
|
|
68
|
+
deepflow_openagent_cli knowledge query-document 6670 --slice-id 512208 --line 1720
|
|
69
|
+
deepflow_openagent_cli chat 1 --message "Hello"
|
|
70
|
+
deepflow_openagent_cli steps 1 42
|
|
71
|
+
deepflow_openagent_cli steps get 1 42 100
|
|
72
|
+
```
|
|
52
73
|
|
|
53
74
|
## Development (build wheel/sdist locally)
|
|
54
75
|
|
|
55
76
|
From this directory:
|
|
56
77
|
|
|
57
78
|
```bash
|
|
58
|
-
pip install
|
|
79
|
+
pip install -e ".[dev]"
|
|
80
|
+
pytest
|
|
59
81
|
python -m build
|
|
60
82
|
```
|
|
61
83
|
|
|
@@ -8,4 +8,5 @@ src/deepflow_openagent_cli.egg-info/SOURCES.txt
|
|
|
8
8
|
src/deepflow_openagent_cli.egg-info/dependency_links.txt
|
|
9
9
|
src/deepflow_openagent_cli.egg-info/entry_points.txt
|
|
10
10
|
src/deepflow_openagent_cli.egg-info/requires.txt
|
|
11
|
-
src/deepflow_openagent_cli.egg-info/top_level.txt
|
|
11
|
+
src/deepflow_openagent_cli.egg-info/top_level.txt
|
|
12
|
+
tests/test_cli.py
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import tomllib
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from deepflow_openagent_cli import __version__
|
|
8
|
+
from deepflow_openagent_cli.cli import (
|
|
9
|
+
CliError,
|
|
10
|
+
ENDPOINTS,
|
|
11
|
+
OpenApiClient,
|
|
12
|
+
build_parser,
|
|
13
|
+
client_from_args,
|
|
14
|
+
get_endpoint,
|
|
15
|
+
load_json_payload,
|
|
16
|
+
main,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_version_matches_release() -> None:
|
|
21
|
+
pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
|
22
|
+
metadata = tomllib.loads(pyproject.read_text(encoding="utf-8"))
|
|
23
|
+
|
|
24
|
+
assert __version__ == metadata["project"]["version"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_catalog_has_stable_unique_keys() -> None:
|
|
28
|
+
keys = [endpoint.key for endpoint in ENDPOINTS]
|
|
29
|
+
|
|
30
|
+
assert len(keys) == len(set(keys))
|
|
31
|
+
assert "knowledge.list" in keys
|
|
32
|
+
assert "knowledge.documents" in keys
|
|
33
|
+
assert "documents.query" in keys
|
|
34
|
+
assert "chat.stream" in keys
|
|
35
|
+
assert "steps.get" in keys
|
|
36
|
+
assert "channels.secret_key" in keys
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_get_endpoint_unknown_key_raises_clear_error() -> None:
|
|
40
|
+
with pytest.raises(CliError, match="Unknown endpoint"):
|
|
41
|
+
get_endpoint("missing.endpoint")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_load_json_payload_rejects_non_object() -> None:
|
|
45
|
+
with pytest.raises(CliError, match="must be an object"):
|
|
46
|
+
load_json_payload("[1, 2, 3]", None)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_build_url_formats_path_and_query() -> None:
|
|
50
|
+
client = OpenApiClient("http://localhost:5001/", "sk-test")
|
|
51
|
+
endpoint = get_endpoint("knowledge.documents")
|
|
52
|
+
|
|
53
|
+
url = client._build_url(
|
|
54
|
+
endpoint,
|
|
55
|
+
{"kb_id": 1},
|
|
56
|
+
{"page": 2, "per_page": 20, "source": None},
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
assert url == "http://localhost:5001/api/v1/knowledge-bases/1/documents?page=2&per_page=20"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_client_from_args_reads_openagent_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
63
|
+
monkeypatch.setenv("OPENAGENT_HOST", "https://api.example.com")
|
|
64
|
+
monkeypatch.setenv("OPENAGENT_API_KEY", "sk-openagent")
|
|
65
|
+
args = build_parser().parse_args(["docs", "list"])
|
|
66
|
+
|
|
67
|
+
client = client_from_args(args)
|
|
68
|
+
|
|
69
|
+
assert client.host == "https://api.example.com"
|
|
70
|
+
assert client.api_key == "sk-openagent"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_client_from_args_reads_legacy_newagent_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
74
|
+
monkeypatch.delenv("OPENAGENT_HOST", raising=False)
|
|
75
|
+
monkeypatch.delenv("OPENAGENT_API_KEY", raising=False)
|
|
76
|
+
monkeypatch.setenv("NEWAGENT_HOST", "https://legacy.example.com")
|
|
77
|
+
monkeypatch.setenv("NEWAGENT_API_KEY", "sk-legacy")
|
|
78
|
+
args = build_parser().parse_args(["docs", "list"])
|
|
79
|
+
|
|
80
|
+
client = client_from_args(args)
|
|
81
|
+
|
|
82
|
+
assert client.host == "https://legacy.example.com"
|
|
83
|
+
assert client.api_key == "sk-legacy"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_docs_show_json_outputs_endpoint_detail(capsys: pytest.CaptureFixture[str]) -> None:
|
|
87
|
+
exit_code = main(["docs", "show", "documents.query", "--json"])
|
|
88
|
+
|
|
89
|
+
captured = capsys.readouterr()
|
|
90
|
+
assert exit_code == 0
|
|
91
|
+
payload = json.loads(captured.out)
|
|
92
|
+
assert payload["method"] == "POST"
|
|
93
|
+
assert payload["scope"] == "chat"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_query_document_command_posts_body(
|
|
97
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
98
|
+
capsys: pytest.CaptureFixture[str],
|
|
99
|
+
) -> None:
|
|
100
|
+
calls = []
|
|
101
|
+
|
|
102
|
+
def fake_request(self, endpoint_key, path_params=None, query=None, body=None, *, stream=False):
|
|
103
|
+
calls.append((endpoint_key, path_params, query, body, stream))
|
|
104
|
+
return b'{"ok": true}'
|
|
105
|
+
|
|
106
|
+
monkeypatch.setattr(OpenApiClient, "request", fake_request)
|
|
107
|
+
|
|
108
|
+
exit_code = main(
|
|
109
|
+
[
|
|
110
|
+
"--host",
|
|
111
|
+
"http://localhost:5001",
|
|
112
|
+
"--api-key",
|
|
113
|
+
"sk-test",
|
|
114
|
+
"knowledge",
|
|
115
|
+
"query-document",
|
|
116
|
+
"6670",
|
|
117
|
+
"--slice-id",
|
|
118
|
+
"512208",
|
|
119
|
+
"--line",
|
|
120
|
+
"1720",
|
|
121
|
+
]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
captured = capsys.readouterr()
|
|
125
|
+
assert exit_code == 0
|
|
126
|
+
assert json.loads(captured.out) == {"ok": True}
|
|
127
|
+
assert calls == [
|
|
128
|
+
(
|
|
129
|
+
"documents.query",
|
|
130
|
+
None,
|
|
131
|
+
None,
|
|
132
|
+
{"doc_id": 6670, "slice_id": 512208, "line": 1720},
|
|
133
|
+
False,
|
|
134
|
+
)
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_steps_list_keeps_legacy_short_form(
|
|
139
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
140
|
+
capsys: pytest.CaptureFixture[str],
|
|
141
|
+
) -> None:
|
|
142
|
+
calls = []
|
|
143
|
+
|
|
144
|
+
def fake_request(self, endpoint_key, path_params=None, query=None, body=None, *, stream=False):
|
|
145
|
+
calls.append((endpoint_key, path_params, query, body, stream))
|
|
146
|
+
return b'{"ok": true}'
|
|
147
|
+
|
|
148
|
+
monkeypatch.setattr(OpenApiClient, "request", fake_request)
|
|
149
|
+
|
|
150
|
+
exit_code = main(
|
|
151
|
+
[
|
|
152
|
+
"--host",
|
|
153
|
+
"http://localhost:5001",
|
|
154
|
+
"--api-key",
|
|
155
|
+
"sk-test",
|
|
156
|
+
"steps",
|
|
157
|
+
"1",
|
|
158
|
+
"42",
|
|
159
|
+
]
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
captured = capsys.readouterr()
|
|
163
|
+
assert exit_code == 0
|
|
164
|
+
assert json.loads(captured.out) == {"ok": True}
|
|
165
|
+
assert calls == [
|
|
166
|
+
(
|
|
167
|
+
"steps.list",
|
|
168
|
+
{"agent_id": 1, "conversation_id": 42},
|
|
169
|
+
None,
|
|
170
|
+
None,
|
|
171
|
+
False,
|
|
172
|
+
)
|
|
173
|
+
]
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_steps_get_fetches_full_step_detail(
|
|
177
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
178
|
+
capsys: pytest.CaptureFixture[str],
|
|
179
|
+
) -> None:
|
|
180
|
+
calls = []
|
|
181
|
+
|
|
182
|
+
def fake_request(self, endpoint_key, path_params=None, query=None, body=None, *, stream=False):
|
|
183
|
+
calls.append((endpoint_key, path_params, query, body, stream))
|
|
184
|
+
return b'{"ok": true}'
|
|
185
|
+
|
|
186
|
+
monkeypatch.setattr(OpenApiClient, "request", fake_request)
|
|
187
|
+
|
|
188
|
+
exit_code = main(
|
|
189
|
+
[
|
|
190
|
+
"--host",
|
|
191
|
+
"http://localhost:5001",
|
|
192
|
+
"--api-key",
|
|
193
|
+
"sk-test",
|
|
194
|
+
"steps",
|
|
195
|
+
"get",
|
|
196
|
+
"1",
|
|
197
|
+
"42",
|
|
198
|
+
"100",
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
captured = capsys.readouterr()
|
|
203
|
+
assert exit_code == 0
|
|
204
|
+
assert json.loads(captured.out) == {"ok": True}
|
|
205
|
+
assert calls == [
|
|
206
|
+
(
|
|
207
|
+
"steps.get",
|
|
208
|
+
{"agent_id": 1, "conversation_id": 42, "step_id": 100},
|
|
209
|
+
None,
|
|
210
|
+
None,
|
|
211
|
+
False,
|
|
212
|
+
)
|
|
213
|
+
]
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def test_tools_create_accepts_doc_grep(
|
|
217
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
218
|
+
capsys: pytest.CaptureFixture[str],
|
|
219
|
+
) -> None:
|
|
220
|
+
calls = []
|
|
221
|
+
|
|
222
|
+
def fake_request(self, endpoint_key, path_params=None, query=None, body=None, *, stream=False):
|
|
223
|
+
calls.append((endpoint_key, path_params, query, body, stream))
|
|
224
|
+
return b'{"ok": true}'
|
|
225
|
+
|
|
226
|
+
monkeypatch.setattr(OpenApiClient, "request", fake_request)
|
|
227
|
+
|
|
228
|
+
exit_code = main(
|
|
229
|
+
[
|
|
230
|
+
"--host",
|
|
231
|
+
"http://localhost:5001",
|
|
232
|
+
"--api-key",
|
|
233
|
+
"sk-test",
|
|
234
|
+
"tools",
|
|
235
|
+
"create",
|
|
236
|
+
"1",
|
|
237
|
+
"--name",
|
|
238
|
+
"Doc Grep",
|
|
239
|
+
"--tool-type",
|
|
240
|
+
"doc_grep",
|
|
241
|
+
]
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
captured = capsys.readouterr()
|
|
245
|
+
assert exit_code == 0
|
|
246
|
+
assert json.loads(captured.out) == {"ok": True}
|
|
247
|
+
assert calls[0][0] == "tools.create"
|
|
248
|
+
assert calls[0][1] == {"agent_id": 1}
|
|
249
|
+
assert calls[0][3]["tool_type"] == "doc_grep"
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# deepflow-openagent-cli
|
|
2
|
-
|
|
3
|
-
Python command-line client for the NewAgent OpenAPI: agents, conversations, SSE chat, tools, channels, and knowledge bases.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install deepflow-openagent-cli
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
export NEWAGENT_HOST="https://your-api-host"
|
|
15
|
-
export NEWAGENT_API_KEY="sk-..."
|
|
16
|
-
deepflow_openagent_cli docs list
|
|
17
|
-
deepflow_openagent_cli agents list
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Equivalent module invocation:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
python -m deepflow_openagent_cli docs list
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Configure API host and key
|
|
27
|
-
|
|
28
|
-
| Method | Variable / flag |
|
|
29
|
-
|--------|------------------|
|
|
30
|
-
| Host | `NEWAGENT_HOST` or `--host` |
|
|
31
|
-
| API key | `NEWAGENT_API_KEY` or `--api-key` |
|
|
32
|
-
|
|
33
|
-
## Development (build wheel/sdist locally)
|
|
34
|
-
|
|
35
|
-
From this directory:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
pip install build twine
|
|
39
|
-
python -m build
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Upload to PyPI (use a **new** API token; never commit tokens):
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
python -m twine upload dist/*
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
When prompted, username is `__token__` and password is the token value.
|
|
File without changes
|
{deepflow_openagent_cli-0.1.0 → deepflow_openagent_cli-0.1.3}/src/deepflow_openagent_cli/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|