tinet-agent-cli 0.1.0.dev36__py3-none-any.whl
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.
- taco/__init__.py +1 -0
- taco/agent_openapi/__init__.py +1 -0
- taco/agent_openapi/catalog.py +198 -0
- taco/agent_openapi/models.py +47 -0
- taco/agent_openapi/parameters.py +111 -0
- taco/agent_openapi/service.py +73 -0
- taco/aikb/__init__.py +4 -0
- taco/aikb/catalog.py +380 -0
- taco/aikb/executors.py +157 -0
- taco/aikb/file_input.py +55 -0
- taco/aikb/models.py +42 -0
- taco/aikb/parameters.py +135 -0
- taco/aikb/service.py +68 -0
- taco/assets/__init__.py +1 -0
- taco/assets/agent_openapi/catalog.json +14 -0
- taco/assets/agent_openapi/operations/conversation/list-conversations.json +67 -0
- taco/assets/agent_openapi/operations/message/list-conversation-messages.json +80 -0
- taco/assets/agent_openapi/operations/trace/list-message-traces.json +72 -0
- taco/assets/aikb/catalog.json +41 -0
- taco/assets/aikb/operations/conversation/chat-conversation-on-open.json +99 -0
- taco/assets/aikb/operations/directory/delete-directory.json +81 -0
- taco/assets/aikb/operations/directory/edit-directory.json +97 -0
- taco/assets/aikb/operations/directory/list-directory-tree.json +106 -0
- taco/assets/aikb/operations/directory/save-directory.json +109 -0
- taco/assets/aikb/operations/faq/create-faq.json +193 -0
- taco/assets/aikb/operations/faq/delete-faq.json +81 -0
- taco/assets/aikb/operations/faq/describe-faq.json +82 -0
- taco/assets/aikb/operations/faq/edit-faq.json +193 -0
- taco/assets/aikb/operations/faq/list-faqs.json +136 -0
- taco/assets/aikb/operations/file/create-file.json +145 -0
- taco/assets/aikb/operations/file/delete-files.json +110 -0
- taco/assets/aikb/operations/file/describe-file.json +82 -0
- taco/assets/aikb/operations/file/get-file-upload-url.json +154 -0
- taco/assets/aikb/operations/file/list-files.json +146 -0
- taco/assets/aikb/operations/media/describe-faq-media-url.json +98 -0
- taco/assets/aikb/operations/media/describe-file-media-url.json +90 -0
- taco/assets/aikb/operations/oss/signature-for-upload.json +85 -0
- taco/assets/aikb/operations/recycle-bin/list-recycled-items.json +151 -0
- taco/assets/aikb/operations/repository/describe-bot-repository.json +71 -0
- taco/assets/aikb/operations/repository/list-private-repositories.json +75 -0
- taco/assets/aikb/operations/repository/list-public-repositories.json +75 -0
- taco/assets/aikb/operations/search/search-knowledge-on-open.json +180 -0
- taco/assets/examples/README.md +3 -0
- taco/assets/examples/agent-basic.json +16 -0
- taco/assets/examples/agent-builtin-tool.json +28 -0
- taco/assets/examples/agent-workflow-tool.json +30 -0
- taco/assets/examples/chatflow-basic.json +24 -0
- taco/assets/examples/workflow-http.json +34 -0
- taco/assets/manifest.json +12 -0
- taco/assets/scenarios/README.md +3 -0
- taco/assets/scenarios/agent-basic.json +80 -0
- taco/assets/scenarios/agent-builtin-tool.json +116 -0
- taco/assets/scenarios/agent-workflow-tool.json +277 -0
- taco/assets/schemas/README.md +3 -0
- taco/assets/schemas/agent-tool.json +71 -0
- taco/assets/schemas/agent.json +199 -0
- taco/assets/schemas/chatflow.json +1048 -0
- taco/assets/schemas/workflow.http.json +1052 -0
- taco/assets/schemas/workflow.json +1052 -0
- taco/assets/skills/README.md +3 -0
- taco/assets/skills/taco/SKILL.md +68 -0
- taco/assets/skills/taco/manifest.json +10 -0
- taco/cli.py +127 -0
- taco/commands/__init__.py +1 -0
- taco/commands/agent.py +760 -0
- taco/commands/aikb.py +132 -0
- taco/commands/app.py +151 -0
- taco/commands/category.py +37 -0
- taco/commands/chatflow.py +183 -0
- taco/commands/credential.py +222 -0
- taco/commands/discovery.py +409 -0
- taco/commands/model.py +55 -0
- taco/commands/profile.py +124 -0
- taco/commands/tool.py +61 -0
- taco/commands/workflow.py +714 -0
- taco/core/__init__.py +1 -0
- taco/core/access_token_manager.py +98 -0
- taco/core/api_client.py +263 -0
- taco/core/assets.py +81 -0
- taco/core/config_store.py +209 -0
- taco/core/context.py +19 -0
- taco/core/developer_center_client.py +165 -0
- taco/core/errors.py +19 -0
- taco/core/file_lock.py +80 -0
- taco/core/http_headers.py +21 -0
- taco/core/openapi_signer.py +221 -0
- taco/core/output.py +72 -0
- taco/core/profile_manager.py +217 -0
- taco/core/profile_resolver.py +151 -0
- taco/core/secure_file.py +76 -0
- taco/release.py +363 -0
- taco/services/__init__.py +1 -0
- taco/services/agent_service.py +314 -0
- taco/services/app_service.py +153 -0
- taco/services/category_service.py +57 -0
- taco/services/model_service.py +117 -0
- taco/services/tool_service.py +482 -0
- taco/services/workflow_compiler.py +1665 -0
- taco/services/workflow_service.py +652 -0
- taco/services/workflow_tool_service.py +439 -0
- tinet_agent_cli-0.1.0.dev36.dist-info/METADATA +158 -0
- tinet_agent_cli-0.1.0.dev36.dist-info/RECORD +104 -0
- tinet_agent_cli-0.1.0.dev36.dist-info/WHEEL +4 -0
- tinet_agent_cli-0.1.0.dev36.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from taco.core.api_client import ApiClient
|
|
7
|
+
from taco.core.errors import TacoError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
_FINAL_IMPORT_STATUSES = {"completed", "completed-with-warnings"}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AppService:
|
|
14
|
+
def __init__(self, api_client: ApiClient | None = None) -> None:
|
|
15
|
+
self.api_client = api_client or ApiClient()
|
|
16
|
+
|
|
17
|
+
def list_apps(
|
|
18
|
+
self,
|
|
19
|
+
*,
|
|
20
|
+
page: int = 1,
|
|
21
|
+
limit: int = 20,
|
|
22
|
+
name: str | None = None,
|
|
23
|
+
mode: str | None = None,
|
|
24
|
+
tag_ids: list[str] | None = None,
|
|
25
|
+
profile: str | None = None,
|
|
26
|
+
) -> Any:
|
|
27
|
+
params: dict[str, Any] = {"page": page, "limit": limit, "compact": True}
|
|
28
|
+
if name:
|
|
29
|
+
params["name"] = name
|
|
30
|
+
if mode:
|
|
31
|
+
params["mode"] = mode
|
|
32
|
+
normalized_tag_ids = _normalize_tag_ids(tag_ids)
|
|
33
|
+
if normalized_tag_ids:
|
|
34
|
+
params["tag_ids"] = ",".join(normalized_tag_ids)
|
|
35
|
+
return self.api_client.get(
|
|
36
|
+
"/apps",
|
|
37
|
+
params=params,
|
|
38
|
+
profile=profile,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def list_tags(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
keyword: str | None = None,
|
|
45
|
+
profile: str | None = None,
|
|
46
|
+
) -> Any:
|
|
47
|
+
params = {"type": "app"}
|
|
48
|
+
if keyword:
|
|
49
|
+
params["keyword"] = keyword
|
|
50
|
+
return self.api_client.get(
|
|
51
|
+
"/tags",
|
|
52
|
+
params=params,
|
|
53
|
+
profile=profile,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def get_app(self, app_id: str, *, profile: str | None = None) -> Any:
|
|
57
|
+
return self.api_client.get(
|
|
58
|
+
f"/apps/{app_id}",
|
|
59
|
+
profile=profile,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def create_app(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
name: str,
|
|
66
|
+
mode: str,
|
|
67
|
+
profile: str | None = None,
|
|
68
|
+
) -> Any:
|
|
69
|
+
return self.api_client.post(
|
|
70
|
+
"/apps",
|
|
71
|
+
json={"name": name, "mode": mode},
|
|
72
|
+
profile=profile,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def list_templates(
|
|
76
|
+
self,
|
|
77
|
+
*,
|
|
78
|
+
language: str | None = None,
|
|
79
|
+
profile: str | None = None,
|
|
80
|
+
) -> Any:
|
|
81
|
+
params = {"language": language} if language else None
|
|
82
|
+
return self.api_client.get(
|
|
83
|
+
"/explore/apps",
|
|
84
|
+
params=params,
|
|
85
|
+
profile=profile,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def create_app_from_template(
|
|
89
|
+
self,
|
|
90
|
+
template_app_id: str,
|
|
91
|
+
*,
|
|
92
|
+
name: str | None = None,
|
|
93
|
+
profile: str | None = None,
|
|
94
|
+
) -> Any:
|
|
95
|
+
detail = self.api_client.get(
|
|
96
|
+
f"/explore/apps/{template_app_id}",
|
|
97
|
+
profile=profile,
|
|
98
|
+
)
|
|
99
|
+
export_data = detail.get("export_data") if isinstance(detail, dict) else None
|
|
100
|
+
if not isinstance(export_data, str) or not export_data.strip():
|
|
101
|
+
raise TacoError(
|
|
102
|
+
code="APP_TEMPLATE_DETAIL_INVALID",
|
|
103
|
+
message="应用模板详情缺少有效 export_data。",
|
|
104
|
+
exit_code=4,
|
|
105
|
+
hint="请重新获取模板列表并确认模板应用 ID。",
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
payload = {"mode": "yaml-content", "yaml_content": export_data}
|
|
109
|
+
if name:
|
|
110
|
+
payload["name"] = name
|
|
111
|
+
result = self.api_client.post(
|
|
112
|
+
"/apps/imports",
|
|
113
|
+
json=payload,
|
|
114
|
+
profile=profile,
|
|
115
|
+
)
|
|
116
|
+
status = result.get("status") if isinstance(result, dict) else None
|
|
117
|
+
if status == "pending":
|
|
118
|
+
import_id = result.get("id")
|
|
119
|
+
if not isinstance(import_id, str) or not import_id.strip():
|
|
120
|
+
raise _invalid_template_import_response()
|
|
121
|
+
result = self.api_client.post(
|
|
122
|
+
f"/apps/imports/{import_id}/confirm",
|
|
123
|
+
profile=profile,
|
|
124
|
+
)
|
|
125
|
+
status = result.get("status") if isinstance(result, dict) else None
|
|
126
|
+
|
|
127
|
+
if status not in _FINAL_IMPORT_STATUSES:
|
|
128
|
+
raise _invalid_template_import_response()
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _normalize_tag_ids(tag_ids: list[str] | None) -> list[str]:
|
|
133
|
+
normalized = []
|
|
134
|
+
for tag_id in tag_ids or []:
|
|
135
|
+
try:
|
|
136
|
+
normalized.append(str(UUID(tag_id.strip())))
|
|
137
|
+
except (AttributeError, ValueError):
|
|
138
|
+
raise TacoError(
|
|
139
|
+
code="APP_LIST_TAG_ID_INVALID",
|
|
140
|
+
message=f"标签 ID 不是有效的 UUID:{tag_id}",
|
|
141
|
+
exit_code=2,
|
|
142
|
+
hint="请通过 --tag-id 传入有效的标签 UUID。",
|
|
143
|
+
) from None
|
|
144
|
+
return normalized
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _invalid_template_import_response() -> TacoError:
|
|
148
|
+
return TacoError(
|
|
149
|
+
code="APP_TEMPLATE_IMPORT_RESPONSE_INVALID",
|
|
150
|
+
message="应用模板导入响应缺少有效的完成状态。",
|
|
151
|
+
exit_code=4,
|
|
152
|
+
hint="请检查模板兼容性和 Console API 响应。",
|
|
153
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from taco.core.api_client import ApiClient
|
|
6
|
+
from taco.core.errors import TacoError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CategoryService:
|
|
10
|
+
def __init__(self, api_client: ApiClient | None = None) -> None:
|
|
11
|
+
self.api_client = api_client or ApiClient()
|
|
12
|
+
|
|
13
|
+
def list_categories(self, *, profile: str | None = None) -> list[dict[str, Any]]:
|
|
14
|
+
payload = self.api_client.get("/tinet/app/categories", profile=profile)
|
|
15
|
+
if not isinstance(payload, list) or any(
|
|
16
|
+
not isinstance(item, dict) for item in payload
|
|
17
|
+
):
|
|
18
|
+
raise TacoError(
|
|
19
|
+
code="CATEGORY_RESPONSE_INVALID",
|
|
20
|
+
message="分类接口返回结构不合法。",
|
|
21
|
+
exit_code=4,
|
|
22
|
+
)
|
|
23
|
+
return payload
|
|
24
|
+
|
|
25
|
+
def get_category(
|
|
26
|
+
self,
|
|
27
|
+
code: str,
|
|
28
|
+
*,
|
|
29
|
+
profile: str | None = None,
|
|
30
|
+
) -> dict[str, Any]:
|
|
31
|
+
category = _find_category(self.list_categories(profile=profile), code)
|
|
32
|
+
if category is None:
|
|
33
|
+
raise TacoError(
|
|
34
|
+
code="CATEGORY_NOT_FOUND",
|
|
35
|
+
message=f"未找到智能体分类:{code}",
|
|
36
|
+
exit_code=6,
|
|
37
|
+
hint="请先执行 taco category list,不要猜测分类 code。",
|
|
38
|
+
)
|
|
39
|
+
return category
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _find_category(
|
|
43
|
+
categories: list[dict[str, Any]],
|
|
44
|
+
code: str,
|
|
45
|
+
) -> dict[str, Any] | None:
|
|
46
|
+
for category in categories:
|
|
47
|
+
if category.get("code") == code:
|
|
48
|
+
return category
|
|
49
|
+
children = category.get("children")
|
|
50
|
+
if isinstance(children, list):
|
|
51
|
+
child = _find_category(
|
|
52
|
+
[item for item in children if isinstance(item, dict)],
|
|
53
|
+
code,
|
|
54
|
+
)
|
|
55
|
+
if child is not None:
|
|
56
|
+
return child
|
|
57
|
+
return None
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
from urllib.parse import quote
|
|
5
|
+
|
|
6
|
+
from taco.core.api_client import ApiClient
|
|
7
|
+
from taco.core.errors import TacoError
|
|
8
|
+
from taco.services.category_service import CategoryService
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ModelService:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
api_client: ApiClient | None = None,
|
|
15
|
+
*,
|
|
16
|
+
category_service: CategoryService | None = None,
|
|
17
|
+
) -> None:
|
|
18
|
+
self.api_client = api_client or ApiClient()
|
|
19
|
+
self.category_service = category_service or CategoryService(
|
|
20
|
+
api_client=self.api_client
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def list_models(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
category: str | None = None,
|
|
27
|
+
profile: str | None = None,
|
|
28
|
+
) -> dict[str, Any]:
|
|
29
|
+
if category is not None:
|
|
30
|
+
self.category_service.get_category(category, profile=profile)
|
|
31
|
+
payload = self.api_client.get(
|
|
32
|
+
"/workspaces/current/models/model-types/llm",
|
|
33
|
+
profile=profile,
|
|
34
|
+
)
|
|
35
|
+
providers = payload.get("data") if isinstance(payload, dict) else None
|
|
36
|
+
if not isinstance(providers, list):
|
|
37
|
+
raise _invalid_model_response()
|
|
38
|
+
|
|
39
|
+
items: list[dict[str, Any]] = []
|
|
40
|
+
for provider in providers:
|
|
41
|
+
if not isinstance(provider, dict):
|
|
42
|
+
raise _invalid_model_response()
|
|
43
|
+
provider_id = provider.get("provider")
|
|
44
|
+
models = provider.get("models")
|
|
45
|
+
if not isinstance(provider_id, str) or not isinstance(models, list):
|
|
46
|
+
continue
|
|
47
|
+
for model in models:
|
|
48
|
+
if not isinstance(model, dict) or not isinstance(
|
|
49
|
+
model.get("model"),
|
|
50
|
+
str,
|
|
51
|
+
):
|
|
52
|
+
continue
|
|
53
|
+
categories = model.get("t_categories")
|
|
54
|
+
if (
|
|
55
|
+
category
|
|
56
|
+
and isinstance(categories, list)
|
|
57
|
+
and category not in categories
|
|
58
|
+
):
|
|
59
|
+
continue
|
|
60
|
+
items.append(
|
|
61
|
+
{
|
|
62
|
+
**model,
|
|
63
|
+
"provider": provider_id,
|
|
64
|
+
"provider_label": provider.get("label"),
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
return {"category": category, "items": items}
|
|
68
|
+
|
|
69
|
+
def describe_model(
|
|
70
|
+
self,
|
|
71
|
+
*,
|
|
72
|
+
provider: str,
|
|
73
|
+
model: str,
|
|
74
|
+
category: str | None = None,
|
|
75
|
+
profile: str | None = None,
|
|
76
|
+
) -> dict[str, Any]:
|
|
77
|
+
models = self.list_models(category=category, profile=profile)["items"]
|
|
78
|
+
item = next(
|
|
79
|
+
(
|
|
80
|
+
candidate
|
|
81
|
+
for candidate in models
|
|
82
|
+
if candidate.get("provider") == provider
|
|
83
|
+
and candidate.get("model") == model
|
|
84
|
+
),
|
|
85
|
+
None,
|
|
86
|
+
)
|
|
87
|
+
if item is None:
|
|
88
|
+
raise TacoError(
|
|
89
|
+
code="MODEL_NOT_FOUND",
|
|
90
|
+
message=f"未找到分类可用模型:{provider}/{model}",
|
|
91
|
+
exit_code=6,
|
|
92
|
+
hint="请先执行 taco model list --category <code>。",
|
|
93
|
+
)
|
|
94
|
+
rules_payload = self.api_client.get(
|
|
95
|
+
(
|
|
96
|
+
"/workspaces/current/model-providers/"
|
|
97
|
+
f"{quote(provider, safe='')}/models/parameter-rules"
|
|
98
|
+
),
|
|
99
|
+
params={"model": model},
|
|
100
|
+
profile=profile,
|
|
101
|
+
)
|
|
102
|
+
rules = (
|
|
103
|
+
rules_payload.get("data")
|
|
104
|
+
if isinstance(rules_payload, dict)
|
|
105
|
+
else None
|
|
106
|
+
)
|
|
107
|
+
if not isinstance(rules, list):
|
|
108
|
+
raise _invalid_model_response()
|
|
109
|
+
return {**item, "parameter_rules": rules}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _invalid_model_response() -> TacoError:
|
|
113
|
+
return TacoError(
|
|
114
|
+
code="MODEL_RESPONSE_INVALID",
|
|
115
|
+
message="模型接口返回结构不合法。",
|
|
116
|
+
exit_code=4,
|
|
117
|
+
)
|