@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,409 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Import an Excel/CSV file into Solvea template library.
|
|
4
|
-
|
|
5
|
-
Required columns:
|
|
6
|
-
- name
|
|
7
|
-
- content
|
|
8
|
-
|
|
9
|
-
Optional columns:
|
|
10
|
-
- status: defaults to ENABLED
|
|
11
|
-
- scene: empty/default for normal templates, voice_sms for SMS templates
|
|
12
|
-
- AUTO, ENGLISH, CHINESE, JAPANESE, FRENCH, GERMAN, SPANISH, ARABIC,
|
|
13
|
-
RUSSIAN, PORTUGUESE, ITALIAN, KOREAN, DUTCH, INDONESIAN, TURKISH,
|
|
14
|
-
ROMANIAN, POLISH, PHILIPPINES
|
|
15
|
-
|
|
16
|
-
Usage:
|
|
17
|
-
python3 /skills/kb-builder/scripts/import_templates.py --xlsx /mounted/chat-files/user/templates.xlsx --dry-run
|
|
18
|
-
python3 /skills/kb-builder/scripts/import_templates.py --xlsx /mounted/chat-files/user/templates.xlsx --name-col "Topic" --content-col "Message" --dry-run
|
|
19
|
-
python3 /skills/kb-builder/scripts/import_templates.py --xlsx /mounted/chat-files/user/templates.xlsx --skip-duplicates --dry-run
|
|
20
|
-
python3 /skills/kb-builder/scripts/import_templates.py --plan-file /workspace/outputs/kb-builder/template_import_plan_<ts>.json
|
|
21
|
-
python3 /skills/kb-builder/scripts/import_templates.py --xlsx /mounted/chat-files/user/templates.xlsx
|
|
22
|
-
"""
|
|
23
|
-
from __future__ import annotations
|
|
24
|
-
|
|
25
|
-
import argparse
|
|
26
|
-
import csv
|
|
27
|
-
import html
|
|
28
|
-
import json
|
|
29
|
-
import os
|
|
30
|
-
import sys
|
|
31
|
-
from pathlib import Path
|
|
32
|
-
from typing import Any
|
|
33
|
-
|
|
34
|
-
sys.path.insert(0, os.path.join(os.environ.get("SOLVEA_LIB_DIR", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "__lib__"))), "skill-runtime"))
|
|
35
|
-
from bootstrap import * # noqa: F403
|
|
36
|
-
|
|
37
|
-
from client import SolveaClient
|
|
38
|
-
|
|
39
|
-
try:
|
|
40
|
-
from openpyxl import load_workbook
|
|
41
|
-
except ImportError: # pragma: no cover - runtime image should include openpyxl in sandbox deps
|
|
42
|
-
load_workbook = None
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
HEADER_ALIASES = {
|
|
46
|
-
"name": {
|
|
47
|
-
"name",
|
|
48
|
-
"title",
|
|
49
|
-
"topic",
|
|
50
|
-
"template",
|
|
51
|
-
"template_name",
|
|
52
|
-
"template name",
|
|
53
|
-
"template title",
|
|
54
|
-
"模板名称",
|
|
55
|
-
"模板名",
|
|
56
|
-
"模版名称",
|
|
57
|
-
"模版名",
|
|
58
|
-
"名称",
|
|
59
|
-
"标题",
|
|
60
|
-
"主题",
|
|
61
|
-
},
|
|
62
|
-
"content": {
|
|
63
|
-
"content",
|
|
64
|
-
"message",
|
|
65
|
-
"body",
|
|
66
|
-
"reply",
|
|
67
|
-
"answer",
|
|
68
|
-
"response",
|
|
69
|
-
"template_content",
|
|
70
|
-
"template content",
|
|
71
|
-
"reply text",
|
|
72
|
-
"模板内容",
|
|
73
|
-
"模板回复",
|
|
74
|
-
"模版内容",
|
|
75
|
-
"模版回复",
|
|
76
|
-
"回复内容",
|
|
77
|
-
"回复话术",
|
|
78
|
-
"话术",
|
|
79
|
-
"答案",
|
|
80
|
-
"内容",
|
|
81
|
-
},
|
|
82
|
-
"status": {"status", "state", "状态", "发布状态"},
|
|
83
|
-
"scene": {"scene", "usage", "scenario", "场景", "适用场景"},
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
LANGUAGE_COLUMNS = {
|
|
87
|
-
"AUTO",
|
|
88
|
-
"ENGLISH",
|
|
89
|
-
"CHINESE",
|
|
90
|
-
"JAPANESE",
|
|
91
|
-
"FRENCH",
|
|
92
|
-
"GERMAN",
|
|
93
|
-
"SPANISH",
|
|
94
|
-
"ARABIC",
|
|
95
|
-
"RUSSIAN",
|
|
96
|
-
"PORTUGUESE",
|
|
97
|
-
"ITALIAN",
|
|
98
|
-
"KOREAN",
|
|
99
|
-
"DUTCH",
|
|
100
|
-
"INDONESIAN",
|
|
101
|
-
"TURKISH",
|
|
102
|
-
"ROMANIAN",
|
|
103
|
-
"POLISH",
|
|
104
|
-
"PHILIPPINES",
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def normalize_header(value: Any) -> str:
|
|
109
|
-
return str(value or "").strip().lower().replace("-", "_")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def normalize_cell(value: Any) -> str:
|
|
113
|
-
if value is None:
|
|
114
|
-
return ""
|
|
115
|
-
return html.unescape(str(value).strip())
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def canonical_header(header: Any) -> str:
|
|
119
|
-
raw = str(header or "").strip()
|
|
120
|
-
normalized = normalize_header(raw)
|
|
121
|
-
for canonical, aliases in HEADER_ALIASES.items():
|
|
122
|
-
if normalized in {normalize_header(alias) for alias in aliases}:
|
|
123
|
-
return canonical
|
|
124
|
-
upper = raw.upper().strip()
|
|
125
|
-
if upper in LANGUAGE_COLUMNS:
|
|
126
|
-
return upper
|
|
127
|
-
return normalized
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def load_templates_from_excel(
|
|
131
|
-
path: str | Path,
|
|
132
|
-
sheet: str | None = None,
|
|
133
|
-
*,
|
|
134
|
-
name_col: str | None = None,
|
|
135
|
-
content_col: str | None = None,
|
|
136
|
-
status_col: str | None = None,
|
|
137
|
-
scene_col: str | None = None,
|
|
138
|
-
lang_cols: dict[str, str] | None = None,
|
|
139
|
-
skip_duplicates: bool = False,
|
|
140
|
-
include_stats: bool = False,
|
|
141
|
-
) -> list[dict[str, Any]] | tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
|
142
|
-
path = Path(path)
|
|
143
|
-
rows = _load_rows(path, sheet)
|
|
144
|
-
if not rows:
|
|
145
|
-
if include_stats:
|
|
146
|
-
return [], []
|
|
147
|
-
return []
|
|
148
|
-
|
|
149
|
-
raw_headers = [normalize_cell(cell) for cell in rows[0]]
|
|
150
|
-
headers = resolve_headers(
|
|
151
|
-
raw_headers,
|
|
152
|
-
name_col=name_col,
|
|
153
|
-
content_col=content_col,
|
|
154
|
-
status_col=status_col,
|
|
155
|
-
scene_col=scene_col,
|
|
156
|
-
lang_cols=lang_cols,
|
|
157
|
-
)
|
|
158
|
-
templates: list[dict[str, Any]] = []
|
|
159
|
-
seen_names: set[str] = set()
|
|
160
|
-
skipped_duplicates: list[dict[str, Any]] = []
|
|
161
|
-
for row_idx, row in enumerate(rows[1:], start=2):
|
|
162
|
-
values = {
|
|
163
|
-
headers[idx]: normalize_cell(row[idx]) if idx < len(row) else ""
|
|
164
|
-
for idx in range(len(headers))
|
|
165
|
-
if headers[idx]
|
|
166
|
-
}
|
|
167
|
-
name = values.get("name", "")
|
|
168
|
-
content = values.get("content", "")
|
|
169
|
-
if not name and not content:
|
|
170
|
-
continue
|
|
171
|
-
if not name or not content:
|
|
172
|
-
raise ValueError(f"row {row_idx}: name and content are required")
|
|
173
|
-
if name in seen_names:
|
|
174
|
-
if skip_duplicates:
|
|
175
|
-
skipped_duplicates.append({"row": row_idx, "name": name})
|
|
176
|
-
continue
|
|
177
|
-
raise ValueError(f"row {row_idx}: duplicate template name in file: {name}")
|
|
178
|
-
seen_names.add(name)
|
|
179
|
-
|
|
180
|
-
multi_content = {"AUTO": values.get("AUTO") or content}
|
|
181
|
-
for language in sorted(LANGUAGE_COLUMNS - {"AUTO"}):
|
|
182
|
-
if values.get(language):
|
|
183
|
-
multi_content[language] = values[language]
|
|
184
|
-
|
|
185
|
-
templates.append({
|
|
186
|
-
"name": name,
|
|
187
|
-
"content": content,
|
|
188
|
-
"status": values.get("status") or "ENABLED",
|
|
189
|
-
"scene": values.get("scene") or None,
|
|
190
|
-
"multiContent": multi_content,
|
|
191
|
-
})
|
|
192
|
-
if include_stats:
|
|
193
|
-
return templates, skipped_duplicates
|
|
194
|
-
return templates
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def resolve_headers(
|
|
198
|
-
raw_headers: list[str],
|
|
199
|
-
*,
|
|
200
|
-
name_col: str | None = None,
|
|
201
|
-
content_col: str | None = None,
|
|
202
|
-
status_col: str | None = None,
|
|
203
|
-
scene_col: str | None = None,
|
|
204
|
-
lang_cols: dict[str, str] | None = None,
|
|
205
|
-
) -> list[str]:
|
|
206
|
-
headers = [canonical_header(cell) for cell in raw_headers]
|
|
207
|
-
|
|
208
|
-
overrides = {
|
|
209
|
-
"name": name_col,
|
|
210
|
-
"content": content_col,
|
|
211
|
-
"status": status_col,
|
|
212
|
-
"scene": scene_col,
|
|
213
|
-
}
|
|
214
|
-
for canonical, requested_col in overrides.items():
|
|
215
|
-
if requested_col:
|
|
216
|
-
headers[_require_raw_header(raw_headers, requested_col, f"--{canonical.replace('_', '-')}-col")] = canonical
|
|
217
|
-
|
|
218
|
-
for language, requested_col in (lang_cols or {}).items():
|
|
219
|
-
language = language.upper()
|
|
220
|
-
if language not in LANGUAGE_COLUMNS:
|
|
221
|
-
raise ValueError(f"Unsupported language '{language}'. Supported languages: {sorted(LANGUAGE_COLUMNS)}")
|
|
222
|
-
headers[_require_raw_header(raw_headers, requested_col, f"--lang-col {language}")] = language
|
|
223
|
-
|
|
224
|
-
if "name" not in headers or "content" not in headers:
|
|
225
|
-
raise ValueError(
|
|
226
|
-
"Cannot detect template name/content columns. "
|
|
227
|
-
"Use --name-col and --content-col after inspecting the uploaded file header. "
|
|
228
|
-
f"Available columns: {raw_headers}"
|
|
229
|
-
)
|
|
230
|
-
return headers
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
def _require_raw_header(raw_headers: list[str], requested_col: str, arg_name: str) -> int:
|
|
234
|
-
requested = normalize_header(requested_col)
|
|
235
|
-
for idx, header in enumerate(raw_headers):
|
|
236
|
-
if normalize_header(header) == requested:
|
|
237
|
-
return idx
|
|
238
|
-
raise ValueError(f"{arg_name} '{requested_col}' not found. Available columns: {raw_headers}")
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
def _load_rows(path: Path, sheet: str | None) -> list[list[Any]]:
|
|
242
|
-
suffix = path.suffix.lower()
|
|
243
|
-
if suffix == ".csv":
|
|
244
|
-
with path.open(newline="", encoding="utf-8-sig") as f:
|
|
245
|
-
return list(csv.reader(f))
|
|
246
|
-
if suffix not in {".xlsx", ".xlsm"}:
|
|
247
|
-
raise ValueError("Only .xlsx, .xlsm, and .csv files are supported")
|
|
248
|
-
if load_workbook is None:
|
|
249
|
-
raise RuntimeError("openpyxl is required to read Excel files")
|
|
250
|
-
wb = load_workbook(path, read_only=True, data_only=True)
|
|
251
|
-
ws = wb[sheet] if sheet else wb.active
|
|
252
|
-
return [list(row) for row in ws.iter_rows(values_only=True)]
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
def import_templates(
|
|
256
|
-
client: SolveaClient,
|
|
257
|
-
*,
|
|
258
|
-
xlsx_path: str | Path | None = None,
|
|
259
|
-
plan_file: str | Path | None = None,
|
|
260
|
-
dry_run: bool,
|
|
261
|
-
sheet: str | None = None,
|
|
262
|
-
name_col: str | None = None,
|
|
263
|
-
content_col: str | None = None,
|
|
264
|
-
status_col: str | None = None,
|
|
265
|
-
scene_col: str | None = None,
|
|
266
|
-
lang_cols: dict[str, str] | None = None,
|
|
267
|
-
skip_duplicates: bool = False,
|
|
268
|
-
) -> dict[str, Any]:
|
|
269
|
-
if bool(xlsx_path) == bool(plan_file):
|
|
270
|
-
raise ValueError("Exactly one of xlsx_path or plan_file is required")
|
|
271
|
-
if plan_file:
|
|
272
|
-
templates = load_templates_from_plan(plan_file)
|
|
273
|
-
skipped_duplicates: list[dict[str, Any]] = []
|
|
274
|
-
source_path = str(plan_file)
|
|
275
|
-
else:
|
|
276
|
-
templates, skipped_duplicates = load_templates_from_excel(
|
|
277
|
-
xlsx_path,
|
|
278
|
-
sheet=sheet,
|
|
279
|
-
name_col=name_col,
|
|
280
|
-
content_col=content_col,
|
|
281
|
-
status_col=status_col,
|
|
282
|
-
scene_col=scene_col,
|
|
283
|
-
lang_cols=lang_cols,
|
|
284
|
-
skip_duplicates=skip_duplicates,
|
|
285
|
-
include_stats=True,
|
|
286
|
-
)
|
|
287
|
-
source_path = str(xlsx_path)
|
|
288
|
-
OUTPUTS_DIR.mkdir(parents=True, exist_ok=True) # noqa: F405
|
|
289
|
-
plan_path: Path | None = None
|
|
290
|
-
if dry_run:
|
|
291
|
-
plan_path = OUTPUTS_DIR / f"template_import_plan_{timestamp()}.json" # noqa: F405
|
|
292
|
-
plan_path.write_text(json.dumps(templates, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
293
|
-
|
|
294
|
-
created = 0
|
|
295
|
-
failed = 0
|
|
296
|
-
created_items: list[dict[str, Any]] = []
|
|
297
|
-
errors: list[dict[str, str]] = []
|
|
298
|
-
if not dry_run:
|
|
299
|
-
for item in templates:
|
|
300
|
-
try:
|
|
301
|
-
response = client.create_template(item)
|
|
302
|
-
template_id = extract_template_id(response)
|
|
303
|
-
created += 1
|
|
304
|
-
created_items.append({"id": template_id, "name": item["name"]})
|
|
305
|
-
suffix = f" id={template_id}" if template_id is not None else ""
|
|
306
|
-
print(f" [OK] {item['name']}{suffix}")
|
|
307
|
-
except Exception as exc:
|
|
308
|
-
failed += 1
|
|
309
|
-
errors.append({"name": item["name"], "error": str(exc)})
|
|
310
|
-
print(f" [FAIL] {item['name']}: {exc}", file=sys.stderr)
|
|
311
|
-
|
|
312
|
-
result_path: Path | None = None
|
|
313
|
-
if not dry_run:
|
|
314
|
-
result_path = OUTPUTS_DIR / f"template_import_result_{timestamp()}.json" # noqa: F405
|
|
315
|
-
|
|
316
|
-
result = {
|
|
317
|
-
"input": len(templates),
|
|
318
|
-
"created": created,
|
|
319
|
-
"failed": failed,
|
|
320
|
-
"source_path": source_path,
|
|
321
|
-
"plan_path": str(plan_path) if plan_path else None,
|
|
322
|
-
"result_path": str(result_path) if result_path else None,
|
|
323
|
-
"created_items": created_items,
|
|
324
|
-
"skipped_duplicates": skipped_duplicates,
|
|
325
|
-
"errors": errors,
|
|
326
|
-
}
|
|
327
|
-
if result_path:
|
|
328
|
-
result_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
329
|
-
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
330
|
-
return result
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def extract_template_id(response: Any) -> Any:
|
|
334
|
-
if not isinstance(response, dict):
|
|
335
|
-
return None
|
|
336
|
-
if response.get("id") is not None:
|
|
337
|
-
return response.get("id")
|
|
338
|
-
data = response.get("data")
|
|
339
|
-
if isinstance(data, dict):
|
|
340
|
-
return data.get("id")
|
|
341
|
-
return None
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
def load_templates_from_plan(plan_file: str | Path) -> list[dict[str, Any]]:
|
|
345
|
-
path = Path(plan_file)
|
|
346
|
-
data = json.loads(path.read_text(encoding="utf-8"))
|
|
347
|
-
if not isinstance(data, list):
|
|
348
|
-
raise ValueError("template import plan must be a JSON array")
|
|
349
|
-
for idx, item in enumerate(data, start=1):
|
|
350
|
-
if not isinstance(item, dict) or not item.get("name") or not item.get("content"):
|
|
351
|
-
raise ValueError(f"invalid template import plan item at index {idx}")
|
|
352
|
-
return data
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
def main() -> None:
|
|
356
|
-
parser = argparse.ArgumentParser(description="Import Excel/CSV templates into Solvea template library")
|
|
357
|
-
source = parser.add_mutually_exclusive_group(required=True)
|
|
358
|
-
source.add_argument("--xlsx", default=None, help="Excel/CSV file path")
|
|
359
|
-
source.add_argument("--plan-file", default=None, help="Import from a dry-run template_import_plan JSON file")
|
|
360
|
-
parser.add_argument("--sheet", default=None, help="Optional Excel sheet name")
|
|
361
|
-
parser.add_argument("--name-col", default=None, help="Column containing template name")
|
|
362
|
-
parser.add_argument("--content-col", default=None, help="Column containing default template content")
|
|
363
|
-
parser.add_argument("--status-col", default=None, help="Optional status column")
|
|
364
|
-
parser.add_argument("--scene-col", default=None, help="Optional scene column")
|
|
365
|
-
parser.add_argument(
|
|
366
|
-
"--lang-col",
|
|
367
|
-
action="append",
|
|
368
|
-
default=[],
|
|
369
|
-
help="Optional language column mapping, e.g. CHINESE=中文话术. Can be repeated.",
|
|
370
|
-
)
|
|
371
|
-
parser.add_argument("--dry-run", action="store_true", help="Parse and write plan without creating templates")
|
|
372
|
-
parser.add_argument(
|
|
373
|
-
"--skip-duplicates",
|
|
374
|
-
action="store_true",
|
|
375
|
-
help="Keep the first row for duplicate template names and skip later duplicates",
|
|
376
|
-
)
|
|
377
|
-
args = parser.parse_args()
|
|
378
|
-
|
|
379
|
-
import_templates(
|
|
380
|
-
SolveaClient(),
|
|
381
|
-
xlsx_path=args.xlsx,
|
|
382
|
-
plan_file=args.plan_file,
|
|
383
|
-
sheet=args.sheet,
|
|
384
|
-
dry_run=args.dry_run,
|
|
385
|
-
name_col=args.name_col,
|
|
386
|
-
content_col=args.content_col,
|
|
387
|
-
status_col=args.status_col,
|
|
388
|
-
scene_col=args.scene_col,
|
|
389
|
-
lang_cols=parse_lang_cols(args.lang_col),
|
|
390
|
-
skip_duplicates=args.skip_duplicates,
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
def parse_lang_cols(values: list[str]) -> dict[str, str]:
|
|
395
|
-
result: dict[str, str] = {}
|
|
396
|
-
for value in values:
|
|
397
|
-
if "=" not in value:
|
|
398
|
-
raise ValueError(f"--lang-col must use LANGUAGE=COLUMN format, got: {value}")
|
|
399
|
-
language, column = value.split("=", 1)
|
|
400
|
-
language = language.strip().upper()
|
|
401
|
-
column = column.strip()
|
|
402
|
-
if not language or not column:
|
|
403
|
-
raise ValueError(f"--lang-col must use LANGUAGE=COLUMN format, got: {value}")
|
|
404
|
-
result[language] = column
|
|
405
|
-
return result
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if __name__ == "__main__":
|
|
409
|
-
main()
|
package/skills/poc/SKILL.md
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: poc
|
|
3
|
-
description: 售前 POC 业务编排。只负责阶段推进、用户确认和交付物汇总;具体意图、Agent、KB、批测能力通过其他 skill 的 interfaces 调用。
|
|
4
|
-
requires:
|
|
5
|
-
skills: [agent-builder, kb-builder]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# POC
|
|
9
|
-
|
|
10
|
-
售前 POC 编排 skill。职责是把现有原子能力串成业务流程,不复制其他 skill 的内部职责。
|
|
11
|
-
|
|
12
|
-
## 边界原则
|
|
13
|
-
|
|
14
|
-
- 只调用其他 skill 暴露的 `interfaces/` 能力,不读取或复述其他 skill 的完整内部流程。
|
|
15
|
-
- 不在本 skill 维护 intent 创建、chatflow graph、KB crawl、QA 上传、批测 runner 的实现细节。
|
|
16
|
-
- 顶层状态只保存跨阶段引用,不复制底层 skill 的完整 state。
|
|
17
|
-
- 每个会产生外部写入或业务结果变化的阶段完成后,先向用户确认,再进入下一阶段。
|
|
18
|
-
|
|
19
|
-
## 必读文件
|
|
20
|
-
|
|
21
|
-
按需读取以下 interface:
|
|
22
|
-
|
|
23
|
-
| 阶段 | Interface |
|
|
24
|
-
|---|---|
|
|
25
|
-
| 意图分类 | `/skills/poc/interfaces/classify.md` |
|
|
26
|
-
| POC agent / 策略创建 | `/skills/poc/interfaces/create-agents.md` |
|
|
27
|
-
| 兜底 chatflow agent | `/skills/agent-builder/interfaces/fallback-chatflow.md` |
|
|
28
|
-
| 知识库,可选 | `/skills/kb-builder/interfaces/web-kb.md` / `/skills/kb-builder/interfaces/qa-upload.md` |
|
|
29
|
-
| POC 标准 KB 目录规范 | `/skills/poc/references/kb-directory.md` |
|
|
30
|
-
| POC 批测与手册 | `/skills/poc/interfaces/poc-test.md` |
|
|
31
|
-
|
|
32
|
-
## 顶层状态
|
|
33
|
-
|
|
34
|
-
状态文件:`/workspace/state/poc/progress.json`。
|
|
35
|
-
|
|
36
|
-
每次开始处理 POC 前,先运行:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npx --yes @shulex/cxclawctl@latest script skills/poc/scripts/plan.py --init
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
阶段完成后用 `plan.py` 更新顶层状态,例如:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npx --yes @shulex/cxclawctl@latest script skills/poc/scripts/plan.py \
|
|
46
|
-
--status business_agents_created \
|
|
47
|
-
--set intent.created_log_path=/workspace/outputs/poc/created_<ts>.json
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
需要汇总当前交付物时运行:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npx --yes @shulex/cxclawctl@latest script skills/poc/scripts/render_summary.py
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
状态只记录跨阶段引用:
|
|
57
|
-
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"status": "empty | classified | business_agents_created | fallback_agent_created | fallback_strategy_linked | kb_done | cases_ready | test_done | done",
|
|
61
|
-
"tenant": "",
|
|
62
|
-
"brand_name": "",
|
|
63
|
-
"brand_website": "",
|
|
64
|
-
"intent": {
|
|
65
|
-
"progress_path": "/workspace/state/poc/progress.json",
|
|
66
|
-
"created_log_path": "",
|
|
67
|
-
"classification_report_path": "",
|
|
68
|
-
"classification_excel_path": ""
|
|
69
|
-
},
|
|
70
|
-
"fallback_agent": {
|
|
71
|
-
"agent_id": "",
|
|
72
|
-
"agent_name": "",
|
|
73
|
-
"created": false
|
|
74
|
-
},
|
|
75
|
-
"kb": {
|
|
76
|
-
"enabled": false,
|
|
77
|
-
"source_url": "",
|
|
78
|
-
"directory_plan_path": "",
|
|
79
|
-
"qa_plan_path": "",
|
|
80
|
-
"upload_result_path": ""
|
|
81
|
-
},
|
|
82
|
-
"test": {
|
|
83
|
-
"agents": [],
|
|
84
|
-
"cases_json_path": "",
|
|
85
|
-
"results_path": "",
|
|
86
|
-
"manual_path": ""
|
|
87
|
-
},
|
|
88
|
-
"updated_at": ""
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## 起点判断
|
|
93
|
-
|
|
94
|
-
按用户消息判断起点,命中即跳;都没命中时询问用户从哪个阶段开始。
|
|
95
|
-
|
|
96
|
-
| 用户消息含 | 起点 |
|
|
97
|
-
|---|---|
|
|
98
|
-
| 「指定 agent / 用现有 agent / 跳过意图 / 直接测试」 | 批测与手册 |
|
|
99
|
-
| 「补充知识 / 提取 QA / 加进 KB」+ 知识源附件 | 知识库 |
|
|
100
|
-
| 「建知识库目录 / 搭知识库」+ 网站/知识来源 URL | 知识库 |
|
|
101
|
-
| 「上传 qa_plan.json」 | 知识库上传 |
|
|
102
|
-
| 给了 xlsx 路径 | 意图分类 |
|
|
103
|
-
| 「接着上次」 | 读 `/workspace/state/poc/progress.json`,缺失时再看底层状态引用 |
|
|
104
|
-
|
|
105
|
-
如果只输入 `/poc` 或信息不足,询问:
|
|
106
|
-
|
|
107
|
-
```text
|
|
108
|
-
您想从哪个阶段开始?
|
|
109
|
-
|
|
110
|
-
1. 阶段一:意图分类与场景创建
|
|
111
|
-
2. 阶段二:知识库搭建(可选)
|
|
112
|
-
3. 阶段三:批量测试 + POC 手册
|
|
113
|
-
|
|
114
|
-
请告诉我从哪一步开始以及已有素材路径。
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## 流程
|
|
118
|
-
|
|
119
|
-
详见 `/skills/poc/references/flow.md`。
|
|
120
|
-
|
|
121
|
-
## 可恢复缺口
|
|
122
|
-
|
|
123
|
-
POC 的预置业务 agent 只是默认来源,不是硬阻塞。执行创建脚本后如果 state 或 created log 出现
|
|
124
|
-
`preset_agent_missing` / `preset_agent_errors`,必须向用户说明缺失项,并询问是从零新建 CHAT_FLOW 业务
|
|
125
|
-
agent,还是使用其他现有 agent 替代;不要直接报告“预置 Agent 不存在,必须开发修复后才能继续”。
|