@shulex/cxclawctl 0.1.2 → 0.1.3
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.
- package/README.md +25 -22
- package/dist/cli.js +2202 -127
- package/dist/cli.js.map +1 -1
- package/package.json +19 -6
- package/capabilities.lock.json +0 -898
- package/requirements-cli.txt +0 -2
- package/skills/__lib__/__init__.py +0 -0
- package/skills/__lib__/skill-runtime/bootstrap.py +0 -134
- package/skills/__lib__/solvea-api/__init__.py +0 -0
- package/skills/__lib__/solvea-api/client.py +0 -1944
- package/skills/__lib__/solvea-api/dashboard.py +0 -100
- package/skills/__lib__/solvea-api/solvea_api.py +0 -1341
- package/skills/agent-analytics/SKILL.md +0 -74
- package/skills/agent-analytics/references/chat-report-fields.md +0 -36
- package/skills/agent-analytics/references/report-fields.md +0 -130
- package/skills/agent-analytics/references/transcript.md +0 -110
- package/skills/agent-builder/SKILL.md +0 -42
- package/skills/agent-builder/interfaces/fallback-chatflow.md +0 -47
- package/skills/agent-builder/references/chatflow/graph-spec.md +0 -259
- package/skills/agent-builder/references/chatflow/node-selection.md +0 -89
- package/skills/agent-builder/references/chatflow/nodes/agent.md +0 -350
- package/skills/agent-builder/references/chatflow/nodes/business-track.md +0 -43
- package/skills/agent-builder/references/chatflow/nodes/code.md +0 -157
- package/skills/agent-builder/references/chatflow/nodes/collect-order.md +0 -47
- package/skills/agent-builder/references/chatflow/nodes/finish.md +0 -34
- package/skills/agent-builder/references/chatflow/nodes/human-review.md +0 -60
- package/skills/agent-builder/references/chatflow/nodes/if-else.md +0 -100
- package/skills/agent-builder/references/chatflow/nodes/intent.md +0 -79
- package/skills/agent-builder/references/chatflow/nodes/knowledge-reply.md +0 -43
- package/skills/agent-builder/references/chatflow/nodes/llm.md +0 -117
- package/skills/agent-builder/references/chatflow/nodes/note.md +0 -38
- package/skills/agent-builder/references/chatflow/nodes/question.md +0 -97
- package/skills/agent-builder/references/chatflow/nodes/rag-reply.md +0 -68
- package/skills/agent-builder/references/chatflow/nodes/reply.md +0 -97
- package/skills/agent-builder/references/chatflow/nodes/start.md +0 -35
- package/skills/agent-builder/references/chatflow/nodes/sub-graph.md +0 -48
- package/skills/agent-builder/references/chatflow/nodes/tool.md +0 -138
- package/skills/agent-builder/references/chatflow/nodes/transfer-to-human.md +0 -63
- package/skills/agent-builder/references/chatflow/nodes/variable-assignment.md +0 -52
- package/skills/agent-builder/references/chatflow/nodes/variable-extract.md +0 -50
- package/skills/agent-builder/references/chatflow/nodes/variable-process.md +0 -70
- package/skills/agent-builder/references/chatflow/overview.md +0 -53
- package/skills/agent-builder/references/chatflow/visual-translation.md +0 -64
- package/skills/agent-builder/references/chatflow/workflow.md +0 -134
- package/skills/agent-builder/references/multi-agent/create-update.md +0 -185
- package/skills/agent-builder/references/multi-agent/graph-spec.md +0 -246
- package/skills/agent-builder/references/multi-agent/graph-structure.md +0 -12
- package/skills/agent-builder/references/multi-agent/migrate-to-chatflow.md +0 -13
- package/skills/agent-builder/references/multi-agent/migration/large.md +0 -554
- package/skills/agent-builder/references/multi-agent/migration/principles.md +0 -446
- package/skills/agent-builder/references/multi-agent/migration/small.md +0 -225
- package/skills/agent-builder/references/multi-agent/orchestration.md +0 -11
- package/skills/agent-builder/references/multi-agent/overview.md +0 -48
- package/skills/agent-builder/references/multi-agent/update.md +0 -128
- package/skills/agent-builder/references/multi-agent/workflow.md +0 -87
- package/skills/agent-builder/references/single-agent/overview.md +0 -48
- package/skills/agent-builder/references/single-agent/prompt.md +0 -16
- package/skills/agent-builder/references/single-agent/tools.md +0 -36
- package/skills/agent-builder/references/single-agent/voice.md +0 -46
- package/skills/agent-builder/references/tools/http-tool.md +0 -315
- package/skills/agent-builder/references/tools/mock-tool.md +0 -279
- package/skills/agent-builder/references/tools/overview.md +0 -46
- package/skills/agent-builder/references/tools/tool-config.md +0 -43
- package/skills/agent-builder/references/tools/x-token.md +0 -34
- package/skills/agent-builder/scripts/chatflow/chatflow_builder.py +0 -3458
- package/skills/agent-builder/scripts/chatflow/validate_graph.py +0 -1697
- package/skills/agent-builder/scripts/copy_marketplace_agent.py +0 -61
- package/skills/agent-builder/scripts/multi-agent/legacy_graph_analyzer.py +0 -5974
- package/skills/agent-builder/scripts/multi-agent/replay_compare.py +0 -679
- package/skills/agent-builder/scripts/patch_agent_tools.py +0 -135
- package/skills/agent-builder/scripts/tools/validate_tool_config.py +0 -384
- package/skills/agent-tester/SKILL.md +0 -35
- package/skills/agent-tester/batch-test/overview.md +0 -86
- package/skills/agent-tester/scripts/batch_test_sheet.py +0 -213
- package/skills/agent-tester/single-test/badcase-retest.md +0 -85
- package/skills/agent-tester/single-test/direct-test.md +0 -24
- package/skills/agent-tester/single-test/overview.md +0 -142
- package/skills/delivery/SKILL.md +0 -112
- package/skills/delivery/interfaces/classify.md +0 -38
- package/skills/delivery/interfaces/create-agents.md +0 -89
- package/skills/delivery/interfaces/delivery-test.md +0 -67
- package/skills/delivery/references/flow.md +0 -40
- package/skills/delivery/references/validation.md +0 -15
- package/skills/delivery/scripts/batch_test.py +0 -704
- package/skills/delivery/scripts/classify.py +0 -22
- package/skills/delivery/scripts/create_agents.py +0 -695
- package/skills/delivery/scripts/gen_delivery_report.py +0 -335
- package/skills/delivery/scripts/gen_excel.py +0 -234
- package/skills/delivery/scripts/gen_report.py +0 -208
- package/skills/delivery/scripts/plan.py +0 -163
- package/skills/delivery/scripts/render.py +0 -713
- package/skills/delivery/scripts/render_summary.py +0 -38
- package/skills/delivery/scripts/sample_history_cases.py +0 -109
- package/skills/kb-builder/SKILL.md +0 -80
- package/skills/kb-builder/interfaces/qa-upload.md +0 -55
- package/skills/kb-builder/interfaces/web-kb.md +0 -84
- package/skills/kb-builder/references/directory.md +0 -373
- package/skills/kb-builder/references/export.md +0 -282
- package/skills/kb-builder/references/isolation-keywords.md +0 -113
- package/skills/kb-builder/references/knowledge.md +0 -153
- package/skills/kb-builder/references/product.md +0 -52
- package/skills/kb-builder/references/qa-from-help-center.md +0 -58
- package/skills/kb-builder/references/qa-from-pdf.md +0 -94
- package/skills/kb-builder/references/qa-from-tickets.md +0 -168
- package/skills/kb-builder/references/qa-from-web.md +0 -98
- package/skills/kb-builder/references/qa-quality.md +0 -73
- package/skills/kb-builder/references/reply-template.md +0 -237
- package/skills/kb-builder/references/tag-isolation-migration.md +0 -61
- package/skills/kb-builder/references/tags.md +0 -45
- package/skills/kb-builder/references/upload.md +0 -130
- package/skills/kb-builder/scripts/batch_extract_ticket_qa.py +0 -333
- package/skills/kb-builder/scripts/build_directory_plan.py +0 -144
- package/skills/kb-builder/scripts/crawl_site.py +0 -433
- package/skills/kb-builder/scripts/create_dirs.py +0 -146
- package/skills/kb-builder/scripts/export_knowledge.py +0 -454
- package/skills/kb-builder/scripts/extract_ticket_qa.py +0 -441
- package/skills/kb-builder/scripts/extract_web_qa.py +0 -118
- package/skills/kb-builder/scripts/import_qa.py +0 -219
- package/skills/kb-builder/scripts/import_source_documents.py +0 -143
- package/skills/kb-builder/scripts/import_templates.py +0 -409
- package/skills/poc/SKILL.md +0 -125
- package/skills/poc/assets/default_manual.css +0 -279
- package/skills/poc/assets/notice_escalate.png +0 -0
- package/skills/poc/assets/notice_escalate2.png +0 -0
- package/skills/poc/assets/notice_new_chat.png +0 -0
- package/skills/poc/assets/poc_test_template.html +0 -645
- package/skills/poc/assets/poc_test_template.md +0 -104
- package/skills/poc/assets/step3_preview.png +0 -0
- package/skills/poc/assets/step4_order_note.png +0 -0
- package/skills/poc/interfaces/classify.md +0 -38
- package/skills/poc/interfaces/create-agents.md +0 -108
- package/skills/poc/interfaces/poc-test.md +0 -94
- package/skills/poc/references/flow.md +0 -47
- package/skills/poc/references/kb-directory.md +0 -22
- package/skills/poc/references/validation.md +0 -17
- package/skills/poc/scripts/classify.py +0 -22
- package/skills/poc/scripts/create_agents.py +0 -818
- package/skills/poc/scripts/gen_excel.py +0 -234
- package/skills/poc/scripts/gen_poc_manual.py +0 -249
- package/skills/poc/scripts/gen_report.py +0 -208
- package/skills/poc/scripts/inspect_chatflow.py +0 -209
- package/skills/poc/scripts/plan.py +0 -178
- package/skills/poc/scripts/poc_test.py +0 -495
- package/skills/poc/scripts/render.py +0 -713
- package/skills/poc/scripts/render_summary.py +0 -41
- package/skills/runtime-inspector/SKILL.md +0 -51
- package/skills/runtime-inspector/references/frontend-rendering.md +0 -126
- package/skills/runtime-inspector/references/model.md +0 -59
- package/skills/runtime-inspector/references/sandbox.md +0 -131
- package/skills/runtime-inspector/scripts/model_inspect.py +0 -68
- package/skills/runtime-inspector/scripts/prepare.py +0 -98
- package/skills/runtime-inspector/scripts/process.py +0 -84
- package/skills/runtime-inspector/scripts/read_state.py +0 -32
- package/skills/runtime-inspector/scripts/sandbox_inspect.py +0 -463
- package/skills/runtime-inspector/scripts/test_claude_proxy.py +0 -49
- package/skills/runtime-inspector/scripts/test_openai_proxy.py +0 -41
- package/skills/runtime-inspector/scripts/verify_persistence.py +0 -101
- package/skills/runtime-inspector/scripts/write_test.py +0 -41
- package/skills/setup/SKILL.md +0 -17
- package/skills/shulex-support/SKILL.md +0 -39
- package/skills/shulex-support/references/badcase-analysis/overview.md +0 -34
- package/skills/shulex-support/references/badcase-analysis/text/conversation-record.md +0 -105
- package/skills/shulex-support/references/badcase-analysis/text/core-flow.md +0 -89
- package/skills/shulex-support/references/badcase-analysis/text/log-query-rules.md +0 -36
- package/skills/shulex-support/references/badcase-analysis/text/m1-entry.md +0 -53
- package/skills/shulex-support/references/badcase-analysis/text/m10-chatflow-service.md +0 -259
- package/skills/shulex-support/references/badcase-analysis/text/m11-algorithm-service.md +0 -148
- package/skills/shulex-support/references/badcase-analysis/text/m12-quality-inspection.md +0 -57
- package/skills/shulex-support/references/badcase-analysis/text/m2-intent.md +0 -120
- package/skills/shulex-support/references/badcase-analysis/text/m3-strategy.md +0 -126
- package/skills/shulex-support/references/badcase-analysis/text/m4-aifield.md +0 -121
- package/skills/shulex-support/references/badcase-analysis/text/m5-agent.md +0 -208
- package/skills/shulex-support/references/badcase-analysis/text/m6-tool.md +0 -115
- package/skills/shulex-support/references/badcase-analysis/text/m7-reply.md +0 -72
- package/skills/shulex-support/references/badcase-analysis/text/m8-error.md +0 -92
- package/skills/shulex-support/references/badcase-analysis/text/m9-knowledge-search.md +0 -147
- package/skills/shulex-support/references/badcase-analysis/text/sls-query.md +0 -283
- package/skills/shulex-support/references/badcase-analysis/voice/core-flow.md +0 -77
- package/skills/shulex-support/references/badcase-analysis/voice/dependencies.md +0 -19
- package/skills/shulex-support/references/badcase-analysis/voice/platform-api.md +0 -23
- package/skills/shulex-support/references/badcase-analysis/voice/sls-playbook.md +0 -31
- package/skills/shulex-support/references/product-docs.md +0 -70
- package/skills/shulex-support/references/tickets.md +0 -184
- package/skills/shulex-support/scripts/support.py +0 -427
- package/skills/solvea-desk/SKILL.md +0 -39
- package/skills/solvea-desk/references/report/fields.md +0 -82
- package/skills/solvea-desk/references/report/report-design.md +0 -200
- package/skills/solvea-desk/references/report/report-template.html +0 -44
- package/skills/solvea-desk/references/report/report.css +0 -517
- package/skills/solvea-desk/references/report/workflow.md +0 -464
- package/skills/solvea-desk/references/tickets/query.md +0 -103
- package/skills/solvea-desk/references/tickets/tags.md +0 -83
- package/skills/solvea-desk/scripts/report/fetch_sources.py +0 -580
- package/skills/solvea-desk/scripts/report/render_report.py +0 -763
- package/skills/solvea-desk/scripts/tickets/desk_api.py +0 -73
- package/skills/solvea-desk/scripts/tickets/fetch_tickets.py +0 -403
- package/skills/solvea-desk/scripts/tickets/ticket_tags.py +0 -305
- package/skills/solvea-kit/SKILL.md +0 -84
- package/skills/solvea-kit/references/agent.md +0 -145
- package/skills/solvea-kit/references/chat.md +0 -244
- package/skills/solvea-kit/references/intent.md +0 -69
- package/skills/solvea-kit/references/plugin.md +0 -53
- package/skills/solvea-kit/references/quality-inspection.md +0 -75
- package/skills/solvea-kit/references/strategy.md +0 -62
- package/skills/solvea-kit/references/tagging.md +0 -231
- package/skills/solvea-kit/references/variables.md +0 -53
- package/skills/solvea-kit/scripts/generate_label_import_file.py +0 -151
- package/skills/solvea-kit/scripts/intent_classify.py +0 -843
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Query and safely mutate Tars ticket tags."""
|
|
3
|
-
|
|
4
|
-
import os
|
|
5
|
-
import sys
|
|
6
|
-
sys.path.insert(0, os.path.join(os.environ["SOLVEA_LIB_DIR"], "skill-runtime"))
|
|
7
|
-
from bootstrap import SOLVEA_ENV # noqa: E402,F401
|
|
8
|
-
|
|
9
|
-
import argparse
|
|
10
|
-
import json
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from typing import Any
|
|
13
|
-
|
|
14
|
-
import httpx
|
|
15
|
-
|
|
16
|
-
from desk_api import DeskApiConfig, request_json, resolve_desk_api_config
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
TAG_LIST_PATH = "/api_v2/tars/api/tags/list"
|
|
20
|
-
TICKET_TAGS_PATH = "/api_v2/tars/api/tags/ticket_tags"
|
|
21
|
-
BATCH_TICKET_TAGS_PATH = "/api_v2/tars/api/tags/new/getTags"
|
|
22
|
-
TAG_SEARCH_PATH = "/api_v2/tars/api/tags/new/find"
|
|
23
|
-
BIND_TAGS_PATH = "/api_v2/tars/api/tags/manual/binding"
|
|
24
|
-
UNBIND_TAGS_PATH = "/api_v2/tars/api/tags/manual/unbinding"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class TagVerificationError(RuntimeError):
|
|
28
|
-
def __init__(
|
|
29
|
-
self,
|
|
30
|
-
*,
|
|
31
|
-
before: dict[str, Any],
|
|
32
|
-
requested: dict[str, Any],
|
|
33
|
-
after: dict[str, Any],
|
|
34
|
-
operation: str,
|
|
35
|
-
) -> None:
|
|
36
|
-
super().__init__(f"{operation} tag verification failed")
|
|
37
|
-
self.evidence = {
|
|
38
|
-
"operation": operation,
|
|
39
|
-
"before": before,
|
|
40
|
-
"requested": requested,
|
|
41
|
-
"after": after,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def list_tags(client: httpx.Client, config: DeskApiConfig) -> Any:
|
|
46
|
-
return request_json(client, config, "GET", TAG_LIST_PATH).get("data", [])
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def get_ticket_tags(
|
|
50
|
-
client: httpx.Client,
|
|
51
|
-
config: DeskApiConfig,
|
|
52
|
-
ticket_number: str,
|
|
53
|
-
) -> dict[str, Any]:
|
|
54
|
-
normalized = ticket_number.strip()
|
|
55
|
-
if not normalized:
|
|
56
|
-
raise ValueError("ticket number cannot be empty")
|
|
57
|
-
data = request_json(
|
|
58
|
-
client,
|
|
59
|
-
config,
|
|
60
|
-
"GET",
|
|
61
|
-
TICKET_TAGS_PATH,
|
|
62
|
-
params={"ticketNum": normalized},
|
|
63
|
-
).get("data", {})
|
|
64
|
-
if not isinstance(data, dict):
|
|
65
|
-
raise ValueError("ticket tag response data must be an object")
|
|
66
|
-
return data
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def batch_get_ticket_tags(
|
|
70
|
-
client: httpx.Client,
|
|
71
|
-
config: DeskApiConfig,
|
|
72
|
-
ticket_ids: list[int],
|
|
73
|
-
) -> list[Any]:
|
|
74
|
-
if not ticket_ids or any(
|
|
75
|
-
isinstance(value, bool) or not isinstance(value, int) for value in ticket_ids
|
|
76
|
-
):
|
|
77
|
-
raise ValueError("ticketIdList must be a non-empty integer list")
|
|
78
|
-
data = request_json(
|
|
79
|
-
client,
|
|
80
|
-
config,
|
|
81
|
-
"POST",
|
|
82
|
-
BATCH_TICKET_TAGS_PATH,
|
|
83
|
-
json_body={"ticketIdList": ticket_ids},
|
|
84
|
-
).get("data", [])
|
|
85
|
-
if not isinstance(data, list):
|
|
86
|
-
raise ValueError("batch ticket tag response data must be a list")
|
|
87
|
-
return data
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def search_tags(
|
|
91
|
-
client: httpx.Client,
|
|
92
|
-
config: DeskApiConfig,
|
|
93
|
-
name: str,
|
|
94
|
-
) -> list[Any]:
|
|
95
|
-
normalized = name.strip()
|
|
96
|
-
if not normalized:
|
|
97
|
-
raise ValueError("tag name cannot be empty")
|
|
98
|
-
data = request_json(
|
|
99
|
-
client,
|
|
100
|
-
config,
|
|
101
|
-
"GET",
|
|
102
|
-
TAG_SEARCH_PATH,
|
|
103
|
-
params={"tagName": normalized},
|
|
104
|
-
).get("data", [])
|
|
105
|
-
if not isinstance(data, list):
|
|
106
|
-
raise ValueError("tag search response data must be a list")
|
|
107
|
-
return data
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def load_ticket_ids_file(path: str | Path) -> list[int]:
|
|
111
|
-
payload = json.loads(Path(path).read_text(encoding="utf-8"))
|
|
112
|
-
ticket_ids = payload.get("ticketIdList") if isinstance(payload, dict) else None
|
|
113
|
-
if not isinstance(ticket_ids, list) or not ticket_ids or any(
|
|
114
|
-
isinstance(value, bool) or not isinstance(value, int) for value in ticket_ids
|
|
115
|
-
):
|
|
116
|
-
raise ValueError("ticketIdList must be a non-empty integer list")
|
|
117
|
-
return ticket_ids
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def load_tags_file(path: str | Path) -> list[dict[str, int | str]]:
|
|
121
|
-
payload = json.loads(Path(path).read_text(encoding="utf-8"))
|
|
122
|
-
tags = payload.get("tags") if isinstance(payload, dict) else None
|
|
123
|
-
return _normalize_tags(tags)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def _normalize_tags(tags: Any) -> list[dict[str, int | str]]:
|
|
127
|
-
if not isinstance(tags, list) or not tags:
|
|
128
|
-
raise ValueError("tags must be a non-empty list")
|
|
129
|
-
normalized = []
|
|
130
|
-
for tag in tags:
|
|
131
|
-
if (
|
|
132
|
-
not isinstance(tag, dict)
|
|
133
|
-
or isinstance(tag.get("id"), bool)
|
|
134
|
-
or not isinstance(tag.get("id"), int)
|
|
135
|
-
):
|
|
136
|
-
raise ValueError("each tag id must be an integer")
|
|
137
|
-
if not isinstance(tag.get("name"), str) or not tag["name"].strip():
|
|
138
|
-
raise ValueError("each tag name must be non-empty")
|
|
139
|
-
normalized.append({"id": tag["id"], "name": tag["name"].strip()})
|
|
140
|
-
return normalized
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def _user_tag_ids(tag_state: dict[str, Any]) -> set[int]:
|
|
144
|
-
values = tag_state.get("userTags", [])
|
|
145
|
-
if not isinstance(values, list):
|
|
146
|
-
return set()
|
|
147
|
-
result = set()
|
|
148
|
-
for tag in values:
|
|
149
|
-
if not isinstance(tag, dict) or isinstance(tag.get("id"), bool):
|
|
150
|
-
continue
|
|
151
|
-
try:
|
|
152
|
-
result.add(int(tag["id"]))
|
|
153
|
-
except (KeyError, TypeError, ValueError):
|
|
154
|
-
continue
|
|
155
|
-
return result
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def change_tags(
|
|
159
|
-
client: httpx.Client,
|
|
160
|
-
config: DeskApiConfig,
|
|
161
|
-
*,
|
|
162
|
-
operation: str,
|
|
163
|
-
ticket_number: str,
|
|
164
|
-
tags: list[dict[str, int | str]],
|
|
165
|
-
confirmed: bool,
|
|
166
|
-
) -> dict[str, Any]:
|
|
167
|
-
if operation not in {"bind", "unbind"}:
|
|
168
|
-
raise ValueError("operation must be bind or unbind")
|
|
169
|
-
normalized_ticket_number = ticket_number.strip()
|
|
170
|
-
if not normalized_ticket_number:
|
|
171
|
-
raise ValueError("ticket number cannot be empty")
|
|
172
|
-
normalized_tags = _normalize_tags(tags)
|
|
173
|
-
before = get_ticket_tags(client, config, normalized_ticket_number)
|
|
174
|
-
requested = {"ticketNum": normalized_ticket_number, "tags": normalized_tags}
|
|
175
|
-
if not confirmed:
|
|
176
|
-
return {
|
|
177
|
-
"ok": False,
|
|
178
|
-
"status": "confirmation_required",
|
|
179
|
-
"operation": operation,
|
|
180
|
-
"before": before,
|
|
181
|
-
"requested": requested,
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
path = BIND_TAGS_PATH if operation == "bind" else UNBIND_TAGS_PATH
|
|
185
|
-
server_payload = request_json(client, config, "POST", path, json_body=requested)
|
|
186
|
-
after = get_ticket_tags(client, config, normalized_ticket_number)
|
|
187
|
-
requested_ids = {int(tag["id"]) for tag in normalized_tags}
|
|
188
|
-
after_user_ids = _user_tag_ids(after)
|
|
189
|
-
verified = (
|
|
190
|
-
requested_ids <= after_user_ids
|
|
191
|
-
if operation == "bind"
|
|
192
|
-
else requested_ids.isdisjoint(after_user_ids)
|
|
193
|
-
)
|
|
194
|
-
if not verified:
|
|
195
|
-
raise TagVerificationError(
|
|
196
|
-
before=before,
|
|
197
|
-
requested=requested,
|
|
198
|
-
after=after,
|
|
199
|
-
operation=operation,
|
|
200
|
-
)
|
|
201
|
-
return {
|
|
202
|
-
"ok": True,
|
|
203
|
-
"operation": operation,
|
|
204
|
-
"verified": True,
|
|
205
|
-
"before": before,
|
|
206
|
-
"requested": requested,
|
|
207
|
-
"after": after,
|
|
208
|
-
"server_result": server_payload.get("data"),
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
213
|
-
parser = argparse.ArgumentParser(description="Query and manage Shulex Desk ticket tags")
|
|
214
|
-
subparsers = parser.add_subparsers(dest="operation", required=True)
|
|
215
|
-
subparsers.add_parser("list-tags", help="Return the complete Tars tag tree")
|
|
216
|
-
|
|
217
|
-
get_parser = subparsers.add_parser("get-ticket-tags", help="Get one ticket's tags")
|
|
218
|
-
get_parser.add_argument("--ticket-number", required=True)
|
|
219
|
-
|
|
220
|
-
batch_parser = subparsers.add_parser(
|
|
221
|
-
"batch-get-ticket-tags", help="Get tags for internal ticket IDs"
|
|
222
|
-
)
|
|
223
|
-
batch_parser.add_argument("--ticket-ids-file", required=True)
|
|
224
|
-
|
|
225
|
-
search_parser = subparsers.add_parser("search-tags", help="Search tag paths by node name")
|
|
226
|
-
search_parser.add_argument("--name", required=True)
|
|
227
|
-
|
|
228
|
-
for operation in ("bind-tags", "unbind-tags"):
|
|
229
|
-
write_parser = subparsers.add_parser(
|
|
230
|
-
operation,
|
|
231
|
-
help="Bind tags to a ticket" if operation == "bind-tags" else "Unbind tags from a ticket",
|
|
232
|
-
)
|
|
233
|
-
write_parser.add_argument("--ticket-number", required=True)
|
|
234
|
-
write_parser.add_argument("--tags-file", required=True)
|
|
235
|
-
write_parser.add_argument(
|
|
236
|
-
"--confirm",
|
|
237
|
-
action="store_true",
|
|
238
|
-
help="Send the write request after the user explicitly confirms the preview",
|
|
239
|
-
)
|
|
240
|
-
return parser
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def main() -> int:
|
|
244
|
-
parser = build_parser()
|
|
245
|
-
args = parser.parse_args()
|
|
246
|
-
config = resolve_desk_api_config()
|
|
247
|
-
if not config.token:
|
|
248
|
-
print(json.dumps({
|
|
249
|
-
"ok": False,
|
|
250
|
-
"operation": args.operation,
|
|
251
|
-
"error": "desk_runtime_not_configured",
|
|
252
|
-
"message": "Check SOLVEA_ENV and the corresponding Solvea token environment variable.",
|
|
253
|
-
}, ensure_ascii=False, indent=2))
|
|
254
|
-
return 2
|
|
255
|
-
|
|
256
|
-
try:
|
|
257
|
-
with httpx.Client(timeout=60.0) as client:
|
|
258
|
-
if args.operation == "list-tags":
|
|
259
|
-
data = list_tags(client, config)
|
|
260
|
-
elif args.operation == "get-ticket-tags":
|
|
261
|
-
data = get_ticket_tags(client, config, args.ticket_number)
|
|
262
|
-
elif args.operation == "batch-get-ticket-tags":
|
|
263
|
-
data = batch_get_ticket_tags(
|
|
264
|
-
client, config, load_ticket_ids_file(args.ticket_ids_file)
|
|
265
|
-
)
|
|
266
|
-
elif args.operation == "search-tags":
|
|
267
|
-
data = search_tags(client, config, args.name)
|
|
268
|
-
else:
|
|
269
|
-
data = change_tags(
|
|
270
|
-
client,
|
|
271
|
-
config,
|
|
272
|
-
operation="bind" if args.operation == "bind-tags" else "unbind",
|
|
273
|
-
ticket_number=args.ticket_number,
|
|
274
|
-
tags=load_tags_file(args.tags_file),
|
|
275
|
-
confirmed=args.confirm,
|
|
276
|
-
)
|
|
277
|
-
except TagVerificationError as exc:
|
|
278
|
-
print(json.dumps({
|
|
279
|
-
"ok": False,
|
|
280
|
-
"operation": args.operation,
|
|
281
|
-
"error": type(exc).__name__,
|
|
282
|
-
"message": str(exc),
|
|
283
|
-
**exc.evidence,
|
|
284
|
-
}, ensure_ascii=False, indent=2))
|
|
285
|
-
return 3
|
|
286
|
-
except (OSError, ValueError, RuntimeError, json.JSONDecodeError, httpx.HTTPError) as exc:
|
|
287
|
-
print(json.dumps({
|
|
288
|
-
"ok": False,
|
|
289
|
-
"operation": args.operation,
|
|
290
|
-
"error": type(exc).__name__,
|
|
291
|
-
"message": str(exc),
|
|
292
|
-
}, ensure_ascii=False, indent=2))
|
|
293
|
-
return 1
|
|
294
|
-
|
|
295
|
-
result = data if args.operation in {"bind-tags", "unbind-tags"} else {
|
|
296
|
-
"ok": True,
|
|
297
|
-
"operation": args.operation,
|
|
298
|
-
"data": data,
|
|
299
|
-
}
|
|
300
|
-
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
301
|
-
return 0
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if __name__ == "__main__":
|
|
305
|
-
raise SystemExit(main())
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: solvea-kit
|
|
3
|
-
description: Shulex 路由与运营配置工具包。用于意图、策略、变量系统、AI 质检和标签树的查询与管理;也负责将 Agent/工具/CHAT_FLOW/知识库/测试/数据分析等需求分流到对应 skill。
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Solvea Kit
|
|
7
|
-
|
|
8
|
-
Solvea Kit 保留路由与运营相关配置:意图、策略、变量系统、AI 质检和标签树。Agent、工具、CHAT_FLOW、测试、知识库和分析类需求按下方分流。
|
|
9
|
-
|
|
10
|
-
## Solvea API CLI
|
|
11
|
-
|
|
12
|
-
所有查询与写入操作,均使用 `/skill-lib/solvea-api/solvea_api.py`:
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npx --yes @shulex/cxclawctl@latest api <command> --pretty
|
|
16
|
-
# 例如:
|
|
17
|
-
npx --yes @shulex/cxclawctl@latest api list-agents --pretty
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## 能力分流
|
|
21
|
-
|
|
22
|
-
| 用户诉求 | 去哪里 |
|
|
23
|
-
|---|---|
|
|
24
|
-
| 通用意图分类实现(供 POC / Delivery 调用) | 本 skill:`scripts/intent_classify.py` |
|
|
25
|
-
| 意图创建、查询、更新、启停 | 本 skill:`references/intent.md` |
|
|
26
|
-
| 策略创建、查询、更新、启停、entity condition | 本 skill:`references/strategy.md` |
|
|
27
|
-
| 变量系统字段查询、初始化、创建、更新、删除、启停 | 本 skill:`references/variables.md` |
|
|
28
|
-
| AI 质检开关、规则、自定义规则、预警 | 本 skill:`references/quality-inspection.md` |
|
|
29
|
-
| 标签树 / 标签组 / 标签节点 / 批量导入 | 本 skill:`references/tagging.md` |
|
|
30
|
-
| SINGLE_AGENT / 语音 Agent / MULTI_AGENT / CHAT_FLOW / 工具配置 | `agent-builder` |
|
|
31
|
-
| CHAT_FLOW 图构建、校验、迁移 | `agent-builder` |
|
|
32
|
-
| 售前 POC 流程、POC 测试手册 | `poc` |
|
|
33
|
-
| 正式交付流程、交付回归 | `delivery` |
|
|
34
|
-
| 知识库内容、目录、QA、隔离关键词、回复模板库 | `kb-builder` |
|
|
35
|
-
| badcase、异常回复、失败节点,或按 ChatId / External ID 定位会话 | `shulex-support`(优先级高于所有数据分析入口,进入 Agent 会话诊断场景) |
|
|
36
|
-
| Agent 运营数据、指标、趋势、原始会话列表下钻(不要求解释异常根因) | `agent-analytics` |
|
|
37
|
-
| Shulex Desk 工单查询、报表和标签操作 | `solvea-desk` |
|
|
38
|
-
| 售后咨询、创建/查询/追加售后工单 | `shulex-support` |
|
|
39
|
-
|
|
40
|
-
## 核心约束(必须遵守,不用查文档也要记住)
|
|
41
|
-
|
|
42
|
-
1. **统一走 CLI** — 所有查询与写入都通过文档指定的 CLI;鉴权和调用目标由工程逻辑处理,agent 不读取、不切换、不解释底层配置。
|
|
43
|
-
2. **先查后改** — 更新任何资源前必须先 get 或 list 确认现状
|
|
44
|
-
3. **写入配置落 state** — 大 JSON 或待用户确认的配置写 `/workspace/state/solvea-kit/`,不要写 `/workspace/tmp/`
|
|
45
|
-
4. **写入操作需确认** — 修改线上数据前必须与用户确认
|
|
46
|
-
|
|
47
|
-
## 模块文档(按需读取)
|
|
48
|
-
|
|
49
|
-
遇到具体问题时,用 `read_file` 读取对应模块文档:
|
|
50
|
-
|
|
51
|
-
| 文档 | 内容 | 何时读 |
|
|
52
|
-
|-------------------------------------------------------|------|--------|
|
|
53
|
-
| `/skills/solvea-kit/references/intent.md` | 意图管理 | 创建、更新、启用、禁用意图 |
|
|
54
|
-
| `/skills/solvea-kit/references/strategy.md` | 策略管理 | 创建、更新、启用、禁用策略;查看 entity condition |
|
|
55
|
-
| `/skills/solvea-kit/references/variables.md` | 变量系统管理 | 查询、初始化、创建、更新、删除、启停及使用边界 |
|
|
56
|
-
| `/skills/solvea-kit/references/quality-inspection.md` | AI 质检管理 | 查看质检、管理规则/自定义规则/预警 |
|
|
57
|
-
| `/skills/solvea-kit/references/tagging.md` | 标签树管理 | 标签组、标签节点、模板下载、批量导入 |
|
|
58
|
-
|
|
59
|
-
## 目录结构
|
|
60
|
-
|
|
61
|
-
```text
|
|
62
|
-
solvea-kit/
|
|
63
|
-
├── SKILL.md
|
|
64
|
-
├── scripts/
|
|
65
|
-
│ ├── generate_label_import_file.py # 根据标签 JSON 生成标签树导入 xlsx
|
|
66
|
-
│ └── intent_classify.py # 通用意图分类实现,POC/Delivery 通过 wrapper 调用
|
|
67
|
-
└── references/
|
|
68
|
-
├── intent.md
|
|
69
|
-
├── strategy.md
|
|
70
|
-
├── variables.md # 变量系统管理
|
|
71
|
-
├── quality-inspection.md # AI 质检管理
|
|
72
|
-
├── tagging.md # 标签树管理
|
|
73
|
-
├── agent.md # 历史兼容,不作新入口
|
|
74
|
-
├── plugin.md # 历史兼容,不作新入口
|
|
75
|
-
└── chat.md # 历史兼容,不作新入口
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## 过时文档
|
|
79
|
-
|
|
80
|
-
以下文档暂时保留用于历史兼容,不作为新任务入口:
|
|
81
|
-
|
|
82
|
-
- `/skills/solvea-kit/references/agent.md`:已迁入 `agent-builder`
|
|
83
|
-
- `/skills/solvea-kit/references/plugin.md`:工具能力已迁入 `agent-builder`
|
|
84
|
-
- `/skills/solvea-kit/references/chat.md`:测试和会话分析已拆到 `poc` / `delivery` / `agent-analytics` / `shulex-support`
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# Agent 管理
|
|
2
|
-
|
|
3
|
-
> 已过时:Agent 构建、修改、复制、语音 Agent、CHAT_FLOW 和工具绑定已迁入 `agent-builder`。本文件仅保留历史兼容,不作为新任务入口。
|
|
4
|
-
|
|
5
|
-
## 能力概览
|
|
6
|
-
|
|
7
|
-
| 类型 | 适用场景 | 何时选用 |
|
|
8
|
-
|------|---------|---------|
|
|
9
|
-
| SINGLE_AGENT | 单一目标:FAQ问答、查询、生成 | 任务目标明确、不超过3个流程分支、一个 Prompt 能说清职责边界 |
|
|
10
|
-
| CHAT_FLOW | 多分支流程:意图分类、条件路由、多步骤处理 | 需要条件分支、人工审批、超过3个流程节点,Prompt 无法涵盖 |
|
|
11
|
-
| Voice Agent | 语音对话 | 同上,但 category=voice |
|
|
12
|
-
|
|
13
|
-
CHAT_FLOW 图构建、修改、校验和发布由 `chatflow` skill 维护,本文件不展开节点规则。
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## SINGLE_AGENT
|
|
18
|
-
|
|
19
|
-
### 能力
|
|
20
|
-
|
|
21
|
-
用户输入 → [Prompt + Tools] → LLM 自主推理(可多轮工具调用) → 输出
|
|
22
|
-
|
|
23
|
-
适用条件:
|
|
24
|
-
- 任务目标单一明确(问答、查询、生成)
|
|
25
|
-
- 不需要条件分支或人工审批
|
|
26
|
-
- 一个 Prompt 能说清职责边界
|
|
27
|
-
- 客服FAQ问答、预约助手、数据查询
|
|
28
|
-
- 流程不超过3个分支;超过时改用 CHAT_FLOW,太长的 prompt 难以维护
|
|
29
|
-
|
|
30
|
-
### API
|
|
31
|
-
|
|
32
|
-
| 操作 | 方法 | 路径 | 说明 |
|
|
33
|
-
|------|------|------|------|
|
|
34
|
-
| 列表/详情 | POST | `/api_v2/gpt/ap/queryAgent` | 不返回 chatFlowGraph |
|
|
35
|
-
| 创建 | POST | `/api_v2/gpt/ap/createAgent` | |
|
|
36
|
-
| 更新 | POST | `/api_v2/gpt/ap/updateAgent` | 必须提交完整对象 |
|
|
37
|
-
|
|
38
|
-
### CLI
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npx --yes @shulex/cxclawctl@latest api list-agents --pretty
|
|
42
|
-
npx --yes @shulex/cxclawctl@latest api get-agent --id <agent_id> --pretty
|
|
43
|
-
npx --yes @shulex/cxclawctl@latest api create-agent \
|
|
44
|
-
--data '{"name":"FAQ_Bot","type":"SINGLE_AGENT","prompt":"...","displayPrompt":"..."}' --pretty
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 原则
|
|
48
|
-
|
|
49
|
-
- 更新前必须先 `get-agent` 获取完整对象,`update-agent` 不支持 partial patch
|
|
50
|
-
- `prompt` 和 `displayPrompt` 必须同步更新,两者不一致导致执行与展示不符
|
|
51
|
-
- `agentId` 字段必须等于 `id`,否则更新失败
|
|
52
|
-
|
|
53
|
-
## Voice Agent
|
|
54
|
-
|
|
55
|
-
语音 Agent 与文本 Agent **共用** `POST /api_v2/gpt/ap/createAgent` / `updateAgent` 接口。后端按 `meta.category == "voice"` 分流到语音处理逻辑。语音对话记录走独立 internal API。
|
|
56
|
-
|
|
57
|
-
### 创建示例
|
|
58
|
-
|
|
59
|
-
```json
|
|
60
|
-
{
|
|
61
|
-
"projectId": 103,
|
|
62
|
-
"name": "Voice_Support",
|
|
63
|
-
"description": "客服语音助手",
|
|
64
|
-
"type": "SINGLE_AGENT",
|
|
65
|
-
"source": "MANUAL",
|
|
66
|
-
"prompt": "你是一个语音客服助手。用简短的口语化句子回答,避免列表和 markdown。涉及专业术语时附上通俗解释。",
|
|
67
|
-
"displayPrompt": "你是一个语音客服助手。用简短的口语化句子回答,避免列表和 markdown。涉及专业术语时附上通俗解释。",
|
|
68
|
-
"meta": {
|
|
69
|
-
"category": "voice",
|
|
70
|
-
"version": "v1",
|
|
71
|
-
"assistant": {
|
|
72
|
-
"callType": "INBOUND_PHONE_CALL",
|
|
73
|
-
"firstMessage": "您好,请问有什么可以帮您?",
|
|
74
|
-
"language": "zh-CN"
|
|
75
|
-
},
|
|
76
|
-
"knowledgeAiReplyPlugin": {
|
|
77
|
-
"type": "KNOWLEDGE_AI_REPLY",
|
|
78
|
-
"meta": {
|
|
79
|
-
"knowledgeAiReplyConfig": {
|
|
80
|
-
"enable": true,
|
|
81
|
-
"directoryIds": [32254, 32255],
|
|
82
|
-
"useAgentPrompt": true
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### 字段说明
|
|
91
|
-
|
|
92
|
-
| 字段 | 必填 | 说明 |
|
|
93
|
-
|---|---|---|
|
|
94
|
-
| `projectId` | ✅ | 当前租户 project ID |
|
|
95
|
-
| `name` | ✅ | 长度 ≤ 40 |
|
|
96
|
-
| `type` | ✅ | 固定 `SINGLE_AGENT`(MULTI_AGENT 后端会拒) |
|
|
97
|
-
| `source` | 推荐 | `MANUAL` 区分手动创建;`SYSTEM` 系统自动生成 |
|
|
98
|
-
| `prompt` | 可选 | agent 角色/语气/策略。**和 `displayPrompt` 文本必须一致**(不一致执行与展示分裂) |
|
|
99
|
-
| `displayPrompt` | 可选 | 同 `prompt`;不传则后端按 `meta.version` 自动用默认模板 |
|
|
100
|
-
| `description` | 可选 | agent 描述 |
|
|
101
|
-
| `meta.category` | ✅ | 固定 `"voice"`。**必须放 `meta` 里**,顶层不走语音分流 |
|
|
102
|
-
| `meta.version` | 推荐 | `"v1"` 走新版默认 prompt(KB_Reply + Transfer_To_Agent 工具引用) |
|
|
103
|
-
| `meta.assistant` | ✅ | 整个对象不能为 null,否则 400 `"Assistant config cannot be empty"` |
|
|
104
|
-
| `meta.assistant.callType` | ✅ | 枚举:`INBOUND_PHONE_CALL`(入呼)/ `OUTBOUND_PHONE_CALL`(出呼)/ `WEB_CALL`(网页语音) |
|
|
105
|
-
| `meta.assistant.firstMessage` | 可选 | 接通后第一句话 |
|
|
106
|
-
| `meta.assistant.language` | 可选 | 语言代码,如 `zh-CN` / `ja-JP` / `en-US`,决定语音识别和合成 |
|
|
107
|
-
| `meta.assistant.specials[]` | 可选 | 绑定真实电话号码:`[{phoneNumberId, language}]`。`phoneNumberId` 必须存在且未被其它 agent 绑定 |
|
|
108
|
-
| `meta.assistant.voiceTone` | 看场景 | 音色配置。**create 不传**(后端不强制);**update 必传**(含 `voiceId` / `voiceProvider`) |
|
|
109
|
-
| `meta.knowledgeAiReplyPlugin` | 可选 | 覆盖后端默认注入的 KB_Reply 内置工具,绑到指定知识库目录 |
|
|
110
|
-
| `...knowledgeAiReplyConfig.directoryIds` | 绑 KB 时必填 | 知识库目录 ID 数组(用 `list-directories` 查) |
|
|
111
|
-
| `...knowledgeAiReplyConfig.enable` | 绑 KB 时必填 | `true` 启用 KB 检索 |
|
|
112
|
-
| `...knowledgeAiReplyConfig.useAgentPrompt` | 推荐 | `true` 让 KB 检索结果用 agent 的 prompt 改写(语气一致) |
|
|
113
|
-
|
|
114
|
-
> ⚠️ **上表是完整 schema,没列的字段一律不要发明**。出现 400 优先回看上表,**不要靠改字段组合反复试**(见 rules.md §4 调试预算)。
|
|
115
|
-
|
|
116
|
-
### API 端点
|
|
117
|
-
|
|
118
|
-
| 操作 | 方法 | 路径 | 说明 |
|
|
119
|
-
|------|------|------|------|
|
|
120
|
-
| 列表 | POST | `/api_v2/gpt/ap/queryAgent` | `category=voice` 作为顶层过滤参数 |
|
|
121
|
-
| 创建 / 更新 | POST | `/api_v2/gpt/ap/createAgent` 或 `updateAgent` | |
|
|
122
|
-
| 对话记录分页 | POST | `/api_v2/as_bot/voice-report/transcript-page` | internal.shulex.com |
|
|
123
|
-
| 对话详情 | GET | `/api_v2/gpt/voice/transcript/projectId/{pid}/history/{hid}` | internal.shulex.com |
|
|
124
|
-
|
|
125
|
-
### CLI
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
npx --yes @shulex/cxclawctl@latest api list-voice-agents --pretty
|
|
129
|
-
|
|
130
|
-
# 创建:payload 存成 json 文件,避免 shell 转义出问题(多语言 prompt 尤其推荐)
|
|
131
|
-
npx --yes @shulex/cxclawctl@latest api create-agent \
|
|
132
|
-
--data-file /workspace/tmp/voice_agent_payload.json --pretty
|
|
133
|
-
|
|
134
|
-
npx --yes @shulex/cxclawctl@latest api list-voice-transcripts --pretty
|
|
135
|
-
npx --yes @shulex/cxclawctl@latest api get-voice-transcript \
|
|
136
|
-
--history-id 019d4dac-aa36-744d-8c5d-d54bc3f7e528 --pretty
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### 注意事项
|
|
140
|
-
|
|
141
|
-
- **接口说明**:对话记录接口由 CLI 内部处理域名与鉴权
|
|
142
|
-
- **额外 header**:`x-language: cn` + `x-token-domain: .shulex.com`
|
|
143
|
-
- **时间戳**:`beginTimestamp` / `endTimestamp` 毫秒级
|
|
144
|
-
- 音色 ID 从 `/api_v2/gpt/ap/voiceConfig` 查询,可选条件 gender / language / provider
|
|
145
|
-
- `list-voice-agents` 等价于 `list-agents --category voice`
|