zenava 0.3.0__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.
- cli_anything/cticloud/__init__.py +4 -0
- cli_anything/cticloud/__main__.py +4 -0
- cli_anything/cticloud/core/agent_action_api.py +460 -0
- cli_anything/cticloud/core/agent_analysis_config_api.py +88 -0
- cli_anything/cticloud/core/agent_analysis_config_params.py +168 -0
- cli_anything/cticloud/core/agent_data_api.py +206 -0
- cli_anything/cticloud/core/agent_login_api.py +58 -0
- cli_anything/cticloud/core/agent_manage_api.py +187 -0
- cli_anything/cticloud/core/agent_report_api.py +74 -0
- cli_anything/cticloud/core/agent_status_api.py +70 -0
- cli_anything/cticloud/core/agent_tel_api.py +37 -0
- cli_anything/cticloud/core/area_code_api.py +73 -0
- cli_anything/cticloud/core/asr_api.py +52 -0
- cli_anything/cticloud/core/auth.py +161 -0
- cli_anything/cticloud/core/cdr.py +115 -0
- cli_anything/cticloud/core/cdr_cc_common.py +222 -0
- cli_anything/cticloud/core/cdr_ib_api.py +189 -0
- cli_anything/cticloud/core/cdr_ib_cc_api.py +40 -0
- cli_anything/cticloud/core/cdr_ib_cc_query.py +48 -0
- cli_anything/cticloud/core/cdr_intelligent_agent_cc_api.py +46 -0
- cli_anything/cticloud/core/cdr_intelligent_agent_cc_query.py +33 -0
- cli_anything/cticloud/core/cdr_interface_common.py +79 -0
- cli_anything/cticloud/core/cdr_ob_api.py +137 -0
- cli_anything/cticloud/core/cdr_ob_cc_api.py +26 -0
- cli_anything/cticloud/core/cdr_ob_cc_query.py +33 -0
- cli_anything/cticloud/core/cdr_ob_internal_cc_api.py +41 -0
- cli_anything/cticloud/core/cdr_ob_internal_cc_query.py +88 -0
- cli_anything/cticloud/core/cdr_predictive_api.py +86 -0
- cli_anything/cticloud/core/cdr_query.py +232 -0
- cli_anything/cticloud/core/cdr_sip_api.py +66 -0
- cli_anything/cticloud/core/cdr_webcall_api.py +84 -0
- cli_anything/cticloud/core/cdr_webcall_cc_api.py +21 -0
- cli_anything/cticloud/core/cdr_webcall_cc_query.py +23 -0
- cli_anything/cticloud/core/client.py +635 -0
- cli_anything/cticloud/core/command_context.py +34 -0
- cli_anything/cticloud/core/config.py +292 -0
- cli_anything/cticloud/core/crn_api.py +40 -0
- cli_anything/cticloud/core/crn_query.py +30 -0
- cli_anything/cticloud/core/data_manager_api.py +59 -0
- cli_anything/cticloud/core/dry_run_registry.py +94 -0
- cli_anything/cticloud/core/enterprise_api.py +20 -0
- cli_anything/cticloud/core/enterprise_hotline_api.py +73 -0
- cli_anything/cticloud/core/enterprise_setting_api.py +96 -0
- cli_anything/cticloud/core/enterprise_voice_api.py +67 -0
- cli_anything/cticloud/core/export_record_api.py +274 -0
- cli_anything/cticloud/core/exten_api.py +188 -0
- cli_anything/cticloud/core/feedback.py +167 -0
- cli_anything/cticloud/core/file_log.py +172 -0
- cli_anything/cticloud/core/home_paths.py +32 -0
- cli_anything/cticloud/core/hybrid_group_api.py +20 -0
- cli_anything/cticloud/core/investigation_api.py +51 -0
- cli_anything/cticloud/core/ivr_profile.py +193 -0
- cli_anything/cticloud/core/ivr_router_api.py +20 -0
- cli_anything/cticloud/core/monitor_api.py +212 -0
- cli_anything/cticloud/core/otel_headers.py +102 -0
- cli_anything/cticloud/core/outbound_report_api.py +93 -0
- cli_anything/cticloud/core/params_util.py +98 -0
- cli_anything/cticloud/core/platform_guard.py +64 -0
- cli_anything/cticloud/core/preview_outcall_api.py +105 -0
- cli_anything/cticloud/core/rasr_api.py +37 -0
- cli_anything/cticloud/core/record.py +134 -0
- cli_anything/cticloud/core/record_query.py +59 -0
- cli_anything/cticloud/core/record_url_api.py +128 -0
- cli_anything/cticloud/core/skill_api.py +49 -0
- cli_anything/cticloud/core/stat_display_number_api.py +122 -0
- cli_anything/cticloud/core/statistics_api.py +132 -0
- cli_anything/cticloud/core/task.py +434 -0
- cli_anything/cticloud/core/task_create.py +164 -0
- cli_anything/cticloud/core/task_fields.py +14 -0
- cli_anything/cticloud/core/task_file.py +132 -0
- cli_anything/cticloud/core/task_lifecycle.py +94 -0
- cli_anything/cticloud/core/task_monitor.py +108 -0
- cli_anything/cticloud/core/task_query.py +79 -0
- cli_anything/cticloud/core/task_template.py +165 -0
- cli_anything/cticloud/core/task_template_params.py +205 -0
- cli_anything/cticloud/core/task_update.py +91 -0
- cli_anything/cticloud/core/webcall_api.py +122 -0
- cli_anything/cticloud/cticloud_cli.py +4839 -0
- cli_anything/cticloud/utils/agent_analysis_config_cli_options.py +117 -0
- cli_anything/cticloud/utils/agent_analysis_config_platform_paths.py +22 -0
- cli_anything/cticloud/utils/agent_cli_options.py +63 -0
- cli_anything/cticloud/utils/agent_manage_cli_options.py +212 -0
- cli_anything/cticloud/utils/agent_summary.py +73 -0
- cli_anything/cticloud/utils/cdr_cc_common_options.py +204 -0
- cli_anything/cticloud/utils/cdr_cc_option_factory.py +69 -0
- cli_anything/cticloud/utils/cdr_cli_options.py +327 -0
- cli_anything/cticloud/utils/cdr_ib_cc_cli_options.py +24 -0
- cli_anything/cticloud/utils/cdr_intelligent_agent_cc_cli_options.py +21 -0
- cli_anything/cticloud/utils/cdr_interface_cli_options.py +239 -0
- cli_anything/cticloud/utils/cdr_interface_summary.py +68 -0
- cli_anything/cticloud/utils/cdr_ob_cc_cli_options.py +19 -0
- cli_anything/cticloud/utils/cdr_ob_internal_cc_cli_options.py +66 -0
- cli_anything/cticloud/utils/cdr_webcall_cc_cli_options.py +10 -0
- cli_anything/cticloud/utils/crn_platform_paths.py +20 -0
- cli_anything/cticloud/utils/csv_importer.py +54 -0
- cli_anything/cticloud/utils/dry_run_guard.py +57 -0
- cli_anything/cticloud/utils/dry_run_output.py +51 -0
- cli_anything/cticloud/utils/enterprise_config_cli_options.py +353 -0
- cli_anything/cticloud/utils/enterprise_config_summary.py +119 -0
- cli_anything/cticloud/utils/export_record_cli_options.py +77 -0
- cli_anything/cticloud/utils/ivr_profile_platform_paths.py +29 -0
- cli_anything/cticloud/utils/monitor_cli_options.py +15 -0
- cli_anything/cticloud/utils/monitor_summary.py +39 -0
- cli_anything/cticloud/utils/output.py +71 -0
- cli_anything/cticloud/utils/preview_webcall_summary.py +74 -0
- cli_anything/cticloud/utils/task_create_cli_options.py +44 -0
- cli_anything/cticloud/utils/task_field_cli_options.py +99 -0
- cli_anything/cticloud/utils/task_platform_paths.py +29 -0
- cli_anything/cticloud/utils/task_template_cli_options.py +154 -0
- cli_anything/cticloud/utils/task_template_platform_paths.py +27 -0
- cli_anything/cticloud/utils/task_update_cli_options.py +25 -0
- zenava-0.3.0.dist-info/METADATA +279 -0
- zenava-0.3.0.dist-info/RECORD +116 -0
- zenava-0.3.0.dist-info/WHEEL +5 -0
- zenava-0.3.0.dist-info/entry_points.txt +2 -0
- zenava-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""Wiki-aligned models and HTTP for agent Action APIs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Dict, Optional
|
|
8
|
+
|
|
9
|
+
from cli_anything.cticloud.core.client import CtiApiError, CtiCloudInterfaceClient
|
|
10
|
+
from cli_anything.cticloud.core.config import CtiConfig
|
|
11
|
+
|
|
12
|
+
MAX_REFUSE_DESCRIPTION_LEN = 20
|
|
13
|
+
VALID_PAUSE_TYPES = {1, 2, 3}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _omit_empty(params: Dict[str, Any]) -> Dict[str, Any]:
|
|
17
|
+
"""Drop None and empty string values."""
|
|
18
|
+
return {k: v for k, v in params.items() if v is not None and v != ""}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _check_result(resp: dict, default_msg: str) -> dict:
|
|
22
|
+
"""Raise CtiApiError when platform result is not success."""
|
|
23
|
+
if str(resp.get("result")) != "0":
|
|
24
|
+
raise CtiApiError(resp.get("description", default_msg), resp)
|
|
25
|
+
return resp
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def validate_cno(cno: str) -> None:
|
|
29
|
+
"""Validate agent id is non-empty."""
|
|
30
|
+
if not cno or not str(cno).strip():
|
|
31
|
+
raise ValueError("cno 不能为空")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def validate_json_array_string(value: str, field: str) -> None:
|
|
35
|
+
"""Validate value is a JSON array string."""
|
|
36
|
+
try:
|
|
37
|
+
parsed = json.loads(value)
|
|
38
|
+
except json.JSONDecodeError as exc:
|
|
39
|
+
raise ValueError(f"{field} 须为合法 JSON 数组") from exc
|
|
40
|
+
if not isinstance(parsed, list):
|
|
41
|
+
raise ValueError(f"{field} 须为 JSON 数组")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class AgentLoginParams:
|
|
46
|
+
"""Parameters for GET /agent/login."""
|
|
47
|
+
|
|
48
|
+
cno: str
|
|
49
|
+
bind_tel: str
|
|
50
|
+
bind_type: int
|
|
51
|
+
login_status: int = 1
|
|
52
|
+
pause_description: Optional[str] = None
|
|
53
|
+
|
|
54
|
+
def __post_init__(self) -> None:
|
|
55
|
+
validate_cno(self.cno)
|
|
56
|
+
if not self.bind_tel or not str(self.bind_tel).strip():
|
|
57
|
+
raise ValueError("bindTel 不能为空")
|
|
58
|
+
|
|
59
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
60
|
+
"""Build camelCase query; loginStatus default always sent."""
|
|
61
|
+
raw: Dict[str, Any] = {
|
|
62
|
+
"cno": self.cno,
|
|
63
|
+
"bindTel": self.bind_tel,
|
|
64
|
+
"bindType": str(self.bind_type),
|
|
65
|
+
"loginStatus": str(self.login_status),
|
|
66
|
+
}
|
|
67
|
+
if self.pause_description:
|
|
68
|
+
raw["pauseDescription"] = self.pause_description
|
|
69
|
+
return raw
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class AgentLogoutParams:
|
|
74
|
+
"""Parameters for GET /agent/logout."""
|
|
75
|
+
|
|
76
|
+
cno: str
|
|
77
|
+
remove_binding: int = 0
|
|
78
|
+
is_kickout: int = 1
|
|
79
|
+
ignore_offline: int = 0
|
|
80
|
+
|
|
81
|
+
def __post_init__(self) -> None:
|
|
82
|
+
validate_cno(self.cno)
|
|
83
|
+
|
|
84
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
85
|
+
return {
|
|
86
|
+
"cno": self.cno,
|
|
87
|
+
"removeBinding": str(self.remove_binding),
|
|
88
|
+
"isKickout": str(self.is_kickout),
|
|
89
|
+
"ignoreOffline": str(self.ignore_offline),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@dataclass
|
|
94
|
+
class AgentPauseParams:
|
|
95
|
+
"""Parameters for GET /agent/pause."""
|
|
96
|
+
|
|
97
|
+
cno: str
|
|
98
|
+
type: int
|
|
99
|
+
description: str
|
|
100
|
+
|
|
101
|
+
def __post_init__(self) -> None:
|
|
102
|
+
validate_cno(self.cno)
|
|
103
|
+
if self.type not in VALID_PAUSE_TYPES:
|
|
104
|
+
raise ValueError("type 取值不正确")
|
|
105
|
+
if not self.description or not str(self.description).strip():
|
|
106
|
+
raise ValueError("description 不能为空")
|
|
107
|
+
|
|
108
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
109
|
+
return {
|
|
110
|
+
"cno": self.cno,
|
|
111
|
+
"type": str(self.type),
|
|
112
|
+
"description": self.description,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class AgentUnpauseParams:
|
|
118
|
+
"""Parameters for GET /agent/unpause."""
|
|
119
|
+
|
|
120
|
+
cno: str
|
|
121
|
+
|
|
122
|
+
def __post_init__(self) -> None:
|
|
123
|
+
validate_cno(self.cno)
|
|
124
|
+
|
|
125
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
126
|
+
return {"cno": self.cno}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@dataclass
|
|
130
|
+
class AgentChangeBindTelParams:
|
|
131
|
+
"""Parameters for GET /agent/changeBindTel."""
|
|
132
|
+
|
|
133
|
+
cno: str
|
|
134
|
+
bind_tel: str
|
|
135
|
+
bind_type: int
|
|
136
|
+
is_verify: int = 1
|
|
137
|
+
|
|
138
|
+
def __post_init__(self) -> None:
|
|
139
|
+
validate_cno(self.cno)
|
|
140
|
+
if not self.bind_tel:
|
|
141
|
+
raise ValueError("bindTel 不能为空")
|
|
142
|
+
|
|
143
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
144
|
+
return {
|
|
145
|
+
"cno": self.cno,
|
|
146
|
+
"bindTel": self.bind_tel,
|
|
147
|
+
"bindType": str(self.bind_type),
|
|
148
|
+
"isVerify": str(self.is_verify),
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@dataclass
|
|
153
|
+
class AgentUnbindTelParams:
|
|
154
|
+
"""Parameters for GET /agent/unbindAgentTel."""
|
|
155
|
+
|
|
156
|
+
cno: str
|
|
157
|
+
|
|
158
|
+
def __post_init__(self) -> None:
|
|
159
|
+
validate_cno(self.cno)
|
|
160
|
+
|
|
161
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
162
|
+
return {"cno": self.cno}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class AgentConsultParams:
|
|
167
|
+
"""Parameters for GET /agent/consult."""
|
|
168
|
+
|
|
169
|
+
cno: str
|
|
170
|
+
object_type: int
|
|
171
|
+
consult_object: str
|
|
172
|
+
consult_variables: Optional[str] = None
|
|
173
|
+
hold_music_class: Optional[str] = None
|
|
174
|
+
|
|
175
|
+
def __post_init__(self) -> None:
|
|
176
|
+
validate_cno(self.cno)
|
|
177
|
+
if not self.consult_object:
|
|
178
|
+
raise ValueError("consultObject 不能为空")
|
|
179
|
+
if self.consult_variables:
|
|
180
|
+
validate_json_array_string(self.consult_variables, "consultVariables")
|
|
181
|
+
|
|
182
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
183
|
+
raw: Dict[str, Any] = {
|
|
184
|
+
"cno": self.cno,
|
|
185
|
+
"objectType": str(self.object_type),
|
|
186
|
+
"consultObject": self.consult_object,
|
|
187
|
+
}
|
|
188
|
+
optional = {
|
|
189
|
+
"consultVariables": self.consult_variables,
|
|
190
|
+
"holdMusicClass": self.hold_music_class,
|
|
191
|
+
}
|
|
192
|
+
raw.update(optional)
|
|
193
|
+
return _omit_empty(raw)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass
|
|
197
|
+
class AgentConsultTransferParams:
|
|
198
|
+
"""Parameters for GET /agent/consultTransfer."""
|
|
199
|
+
|
|
200
|
+
cno: str
|
|
201
|
+
limit_time_second: Optional[int] = None
|
|
202
|
+
limit_time_alert_second: Optional[int] = None
|
|
203
|
+
limit_time_file: Optional[str] = None
|
|
204
|
+
is_investigation: Optional[int] = None
|
|
205
|
+
|
|
206
|
+
def __post_init__(self) -> None:
|
|
207
|
+
validate_cno(self.cno)
|
|
208
|
+
|
|
209
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
210
|
+
raw: Dict[str, Any] = {"cno": self.cno}
|
|
211
|
+
optional = {
|
|
212
|
+
"limitTimeSecond": (
|
|
213
|
+
str(self.limit_time_second) if self.limit_time_second is not None else None
|
|
214
|
+
),
|
|
215
|
+
"limitTimeAlertSecond": (
|
|
216
|
+
str(self.limit_time_alert_second)
|
|
217
|
+
if self.limit_time_alert_second is not None
|
|
218
|
+
else None
|
|
219
|
+
),
|
|
220
|
+
"limitTimeFile": self.limit_time_file,
|
|
221
|
+
"isInvestigation": (
|
|
222
|
+
str(self.is_investigation) if self.is_investigation is not None else None
|
|
223
|
+
),
|
|
224
|
+
}
|
|
225
|
+
raw.update(optional)
|
|
226
|
+
return _omit_empty(raw)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class AgentInvolveThreewayParams:
|
|
231
|
+
"""Parameters for GET /agent/involveThreeway."""
|
|
232
|
+
|
|
233
|
+
unique_id: str
|
|
234
|
+
object_type: int
|
|
235
|
+
involve_object: Optional[str] = None
|
|
236
|
+
dial_timeout: Optional[int] = None
|
|
237
|
+
dial_strategy: Optional[int] = None
|
|
238
|
+
conference_mode: int = 0
|
|
239
|
+
barge_on_answer: int = 0
|
|
240
|
+
involve_variables: Optional[str] = None
|
|
241
|
+
|
|
242
|
+
def __post_init__(self) -> None:
|
|
243
|
+
validate_involve_threeway_params(self)
|
|
244
|
+
|
|
245
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
246
|
+
raw: Dict[str, Any] = {
|
|
247
|
+
"uniqueId": self.unique_id,
|
|
248
|
+
"objectType": str(self.object_type),
|
|
249
|
+
"conferenceMode": str(self.conference_mode),
|
|
250
|
+
"bargeOnAnswer": str(self.barge_on_answer),
|
|
251
|
+
}
|
|
252
|
+
optional = {
|
|
253
|
+
"involveObject": self.involve_object,
|
|
254
|
+
"dialTimeout": str(self.dial_timeout) if self.dial_timeout is not None else None,
|
|
255
|
+
"dialStrategy": (
|
|
256
|
+
str(self.dial_strategy) if self.dial_strategy is not None else None
|
|
257
|
+
),
|
|
258
|
+
"involveVariables": self.involve_variables,
|
|
259
|
+
}
|
|
260
|
+
raw.update(optional)
|
|
261
|
+
return _omit_empty(raw)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@dataclass
|
|
265
|
+
class AgentRefuseParams:
|
|
266
|
+
"""Parameters for GET /agent/refuse."""
|
|
267
|
+
|
|
268
|
+
cno: str
|
|
269
|
+
description: Optional[str] = None
|
|
270
|
+
|
|
271
|
+
def __post_init__(self) -> None:
|
|
272
|
+
validate_refuse_params(self)
|
|
273
|
+
|
|
274
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
275
|
+
raw: Dict[str, Any] = {"cno": self.cno}
|
|
276
|
+
if self.description:
|
|
277
|
+
raw["description"] = self.description
|
|
278
|
+
return raw
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@dataclass
|
|
282
|
+
class AgentUnlinkParams:
|
|
283
|
+
"""Parameters for GET /agent/unlink."""
|
|
284
|
+
|
|
285
|
+
cno: Optional[str] = None
|
|
286
|
+
unique_id: Optional[str] = None
|
|
287
|
+
request_unique_id: Optional[str] = None
|
|
288
|
+
side: int = 1
|
|
289
|
+
|
|
290
|
+
def __post_init__(self) -> None:
|
|
291
|
+
validate_unlink_params(self)
|
|
292
|
+
|
|
293
|
+
def to_api_params(self) -> Dict[str, Any]:
|
|
294
|
+
raw: Dict[str, Any] = {"side": str(self.side)}
|
|
295
|
+
if self.cno:
|
|
296
|
+
raw["cno"] = self.cno
|
|
297
|
+
if self.unique_id:
|
|
298
|
+
raw["uniqueId"] = self.unique_id
|
|
299
|
+
if self.request_unique_id:
|
|
300
|
+
raw["requestUniqueId"] = self.request_unique_id
|
|
301
|
+
return raw
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def validate_unlink_params(params: AgentUnlinkParams) -> None:
|
|
305
|
+
"""Exactly one of cno, uniqueId, requestUniqueId must be set."""
|
|
306
|
+
ids = [params.cno, params.unique_id, params.request_unique_id]
|
|
307
|
+
set_count = sum(1 for x in ids if x and str(x).strip())
|
|
308
|
+
if set_count != 1:
|
|
309
|
+
raise ValueError("cno、uniqueId、requestUniqueId 须恰好指定一个")
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def validate_involve_threeway_params(params: AgentInvolveThreewayParams) -> None:
|
|
313
|
+
"""Validate involve threeway conditional fields."""
|
|
314
|
+
if not params.unique_id:
|
|
315
|
+
raise ValueError("uniqueId 不能为空")
|
|
316
|
+
if params.object_type in (1, 2) and not params.involve_object:
|
|
317
|
+
raise ValueError("objectType 为 1 或 2 时 involveObject 不能为空")
|
|
318
|
+
if params.dial_timeout is not None and not (2 < params.dial_timeout <= 60):
|
|
319
|
+
raise ValueError("dialTimeout 须在 2–60 之间")
|
|
320
|
+
if params.involve_variables:
|
|
321
|
+
validate_json_array_string(params.involve_variables, "involveVariables")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def validate_refuse_params(params: AgentRefuseParams) -> None:
|
|
325
|
+
"""Validate refuse description length."""
|
|
326
|
+
validate_cno(params.cno)
|
|
327
|
+
if params.description and len(params.description) >= MAX_REFUSE_DESCRIPTION_LEN:
|
|
328
|
+
raise ValueError(f"description 长度须小于 {MAX_REFUSE_DESCRIPTION_LEN}")
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def agent_login(
|
|
332
|
+
config: CtiConfig,
|
|
333
|
+
params: AgentLoginParams,
|
|
334
|
+
*,
|
|
335
|
+
verbose: bool = False,
|
|
336
|
+
) -> Dict[str, Any]:
|
|
337
|
+
"""Agent login (GET /agent/login)."""
|
|
338
|
+
client = CtiCloudInterfaceClient(config)
|
|
339
|
+
resp = client.get("/agent/login", params.to_api_params(), verbose=verbose)
|
|
340
|
+
return _check_result(resp, "座席上线失败")
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def agent_logout(
|
|
344
|
+
config: CtiConfig,
|
|
345
|
+
params: AgentLogoutParams,
|
|
346
|
+
*,
|
|
347
|
+
verbose: bool = False,
|
|
348
|
+
) -> Dict[str, Any]:
|
|
349
|
+
"""Agent logout (GET /agent/logout)."""
|
|
350
|
+
client = CtiCloudInterfaceClient(config)
|
|
351
|
+
resp = client.get("/agent/logout", params.to_api_params(), verbose=verbose)
|
|
352
|
+
return _check_result(resp, "座席下线失败")
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def agent_pause(
|
|
356
|
+
config: CtiConfig,
|
|
357
|
+
params: AgentPauseParams,
|
|
358
|
+
*,
|
|
359
|
+
verbose: bool = False,
|
|
360
|
+
) -> Dict[str, Any]:
|
|
361
|
+
"""Agent pause (GET /agent/pause)."""
|
|
362
|
+
client = CtiCloudInterfaceClient(config)
|
|
363
|
+
resp = client.get("/agent/pause", params.to_api_params(), verbose=verbose)
|
|
364
|
+
return _check_result(resp, "座席置忙失败")
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def agent_unpause(
|
|
368
|
+
config: CtiConfig,
|
|
369
|
+
params: AgentUnpauseParams,
|
|
370
|
+
*,
|
|
371
|
+
verbose: bool = False,
|
|
372
|
+
) -> Dict[str, Any]:
|
|
373
|
+
"""Agent unpause (GET /agent/unpause)."""
|
|
374
|
+
client = CtiCloudInterfaceClient(config)
|
|
375
|
+
resp = client.get("/agent/unpause", params.to_api_params(), verbose=verbose)
|
|
376
|
+
return _check_result(resp, "座席置闲失败")
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def agent_change_bind_tel(
|
|
380
|
+
config: CtiConfig,
|
|
381
|
+
params: AgentChangeBindTelParams,
|
|
382
|
+
*,
|
|
383
|
+
verbose: bool = False,
|
|
384
|
+
) -> Dict[str, Any]:
|
|
385
|
+
"""Change bind tel (GET /agent/changeBindTel)."""
|
|
386
|
+
client = CtiCloudInterfaceClient(config)
|
|
387
|
+
resp = client.get("/agent/changeBindTel", params.to_api_params(), verbose=verbose)
|
|
388
|
+
return _check_result(resp, "修改绑定电话失败")
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def agent_unbind_agent_tel(
|
|
392
|
+
config: CtiConfig,
|
|
393
|
+
params: AgentUnbindTelParams,
|
|
394
|
+
*,
|
|
395
|
+
verbose: bool = False,
|
|
396
|
+
) -> Dict[str, Any]:
|
|
397
|
+
"""Unbind agent tel (GET /agent/unbindAgentTel)."""
|
|
398
|
+
client = CtiCloudInterfaceClient(config)
|
|
399
|
+
resp = client.get("/agent/unbindAgentTel", params.to_api_params(), verbose=verbose)
|
|
400
|
+
return _check_result(resp, "解除绑定电话失败")
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def agent_consult(
|
|
404
|
+
config: CtiConfig,
|
|
405
|
+
params: AgentConsultParams,
|
|
406
|
+
*,
|
|
407
|
+
verbose: bool = False,
|
|
408
|
+
) -> Dict[str, Any]:
|
|
409
|
+
"""Agent consult (GET /agent/consult)."""
|
|
410
|
+
client = CtiCloudInterfaceClient(config)
|
|
411
|
+
resp = client.get("/agent/consult", params.to_api_params(), verbose=verbose)
|
|
412
|
+
return _check_result(resp, "座席咨询失败")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def agent_consult_transfer(
|
|
416
|
+
config: CtiConfig,
|
|
417
|
+
params: AgentConsultTransferParams,
|
|
418
|
+
*,
|
|
419
|
+
verbose: bool = False,
|
|
420
|
+
) -> Dict[str, Any]:
|
|
421
|
+
"""Consult transfer (GET /agent/consultTransfer)."""
|
|
422
|
+
client = CtiCloudInterfaceClient(config)
|
|
423
|
+
resp = client.get("/agent/consultTransfer", params.to_api_params(), verbose=verbose)
|
|
424
|
+
return _check_result(resp, "座席咨询转移失败")
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def agent_involve_threeway(
|
|
428
|
+
config: CtiConfig,
|
|
429
|
+
params: AgentInvolveThreewayParams,
|
|
430
|
+
*,
|
|
431
|
+
verbose: bool = False,
|
|
432
|
+
) -> Dict[str, Any]:
|
|
433
|
+
"""Involve threeway (GET /agent/involveThreeway)."""
|
|
434
|
+
client = CtiCloudInterfaceClient(config)
|
|
435
|
+
resp = client.get("/agent/involveThreeway", params.to_api_params(), verbose=verbose)
|
|
436
|
+
return _check_result(resp, "邀请三方失败")
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def agent_refuse(
|
|
440
|
+
config: CtiConfig,
|
|
441
|
+
params: AgentRefuseParams,
|
|
442
|
+
*,
|
|
443
|
+
verbose: bool = False,
|
|
444
|
+
) -> Dict[str, Any]:
|
|
445
|
+
"""Agent refuse (GET /agent/refuse)."""
|
|
446
|
+
client = CtiCloudInterfaceClient(config)
|
|
447
|
+
resp = client.get("/agent/refuse", params.to_api_params(), verbose=verbose)
|
|
448
|
+
return _check_result(resp, "座席拒接失败")
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def agent_unlink(
|
|
452
|
+
config: CtiConfig,
|
|
453
|
+
params: AgentUnlinkParams,
|
|
454
|
+
*,
|
|
455
|
+
verbose: bool = False,
|
|
456
|
+
) -> Dict[str, Any]:
|
|
457
|
+
"""Agent unlink/hangup (GET /agent/unlink)."""
|
|
458
|
+
client = CtiCloudInterfaceClient(config)
|
|
459
|
+
resp = client.get("/agent/unlink", params.to_api_params(), verbose=verbose)
|
|
460
|
+
return _check_result(resp, "座席挂机失败")
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""智能体话后分析配置:/cc 融合 OpenAPI 四操作(两平台共用路径,鉴权按平台切换)。"""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Any, Dict
|
|
5
|
+
|
|
6
|
+
from cli_anything.cticloud.core.agent_analysis_config_params import AgentAnalysisConfigParams
|
|
7
|
+
from cli_anything.cticloud.core.client import CtiApiError, make_cc_client
|
|
8
|
+
from cli_anything.cticloud.core.config import CtiConfig
|
|
9
|
+
from cli_anything.cticloud.core.platform_guard import ensure_command_allowed
|
|
10
|
+
|
|
11
|
+
# 文档成功形态:delete 返回 result="success";其余响应无 result 码或为 "0"。
|
|
12
|
+
_SUCCESS_VALUES = {"0", "success"}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _raise_on_error(resp: Dict[str, Any]) -> Dict[str, Any]:
|
|
16
|
+
"""响应含 result 非 0/success,或含 error 对象时抛业务错误;否则原样返回(D9)。
|
|
17
|
+
|
|
18
|
+
error 对象形态:{"error": {"code": "InvalidParameter", "message": "…"}}(live-qa 2026-08-18 记录缺口,
|
|
19
|
+
0.2.8 起判为业务失败 → exit 1)。错误文案取 code+message,不含任何密钥字段(D15)。
|
|
20
|
+
"""
|
|
21
|
+
if isinstance(resp, dict):
|
|
22
|
+
error = resp.get("error")
|
|
23
|
+
if isinstance(error, dict) and error.get("code") is not None and str(error.get("code")) != "success":
|
|
24
|
+
code = str(error.get("code"))
|
|
25
|
+
msg = error.get("message") or "业务失败"
|
|
26
|
+
raise CtiApiError(f"{code}: {msg}", resp)
|
|
27
|
+
if "result" in resp and str(resp.get("result")) not in _SUCCESS_VALUES:
|
|
28
|
+
raise CtiApiError(
|
|
29
|
+
resp.get("description") or resp.get("message") or f"业务失败: {resp.get('result')}", resp
|
|
30
|
+
)
|
|
31
|
+
return resp
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_agent_analysis_config(config: CtiConfig, agent_id: str, *, verbose: bool = False) -> Dict[str, Any]:
|
|
35
|
+
"""按 agentId 查询话后分析配置(GET,agentId 走 Query)。
|
|
36
|
+
|
|
37
|
+
agentId 不存在时服务端返回 InvalidParameter(error 对象),0.2.8 起判为业务失败(D9)。
|
|
38
|
+
"""
|
|
39
|
+
ensure_command_allowed(config, "callcenter agent-analysis-config get")
|
|
40
|
+
if agent_id is None or str(agent_id).strip() == "":
|
|
41
|
+
raise ValueError("agentId 必填")
|
|
42
|
+
return _raise_on_error(
|
|
43
|
+
make_cc_client(config).get(
|
|
44
|
+
"get_intelligent_agent_analysis_config", {"agentId": agent_id}, verbose=verbose
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def create_agent_analysis_config(
|
|
50
|
+
config: CtiConfig, params: AgentAnalysisConfigParams, *, verbose: bool = False
|
|
51
|
+
) -> Dict[str, Any]:
|
|
52
|
+
"""整包写入话后分析配置(POST JSON Body,D3)。
|
|
53
|
+
|
|
54
|
+
服务端行为:未提供的 Active 按 0、列表按 [];记录不存在时新建配置行、
|
|
55
|
+
已存在则整包覆盖;不创建、不绑定 IVR。仅用于首次创建或整体替换。
|
|
56
|
+
botType/category 仅在 create 路径写入(include_toplevel_meta=True)。
|
|
57
|
+
"""
|
|
58
|
+
ensure_command_allowed(config, "callcenter agent-analysis-config create")
|
|
59
|
+
body = params.to_api_body()
|
|
60
|
+
return _raise_on_error(
|
|
61
|
+
make_cc_client(config).post_json("create_intelligent_agent_analysis_config", body, verbose=verbose)
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def update_agent_analysis_config(
|
|
66
|
+
config: CtiConfig, params: AgentAnalysisConfigParams, *, verbose: bool = False
|
|
67
|
+
) -> Dict[str, Any]:
|
|
68
|
+
"""按 JSON 字段是否出现做局部更新(POST JSON Body,D2)。
|
|
69
|
+
|
|
70
|
+
未出现的字段保持库内原值;记录必须已存在,不隐式新建。
|
|
71
|
+
调用方以 include_toplevel_meta=False 构建 body,botType/category 不写入(服务端忽略)。
|
|
72
|
+
"""
|
|
73
|
+
ensure_command_allowed(config, "callcenter agent-analysis-config update")
|
|
74
|
+
body = params.to_api_body(include_toplevel_meta=False)
|
|
75
|
+
return _raise_on_error(
|
|
76
|
+
make_cc_client(config).post_json("update_intelligent_agent_analysis_config", body, verbose=verbose)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def delete_agent_analysis_config(config: CtiConfig, agent_id: str, *, verbose: bool = False) -> Dict[str, Any]:
|
|
81
|
+
"""整包清空话后分析配置(POST JSON Body 仅 agentId,不删智能体)。"""
|
|
82
|
+
ensure_command_allowed(config, "callcenter agent-analysis-config delete")
|
|
83
|
+
if agent_id is None or str(agent_id).strip() == "":
|
|
84
|
+
raise ValueError("agentId 必填")
|
|
85
|
+
return _raise_on_error(
|
|
86
|
+
make_cc_client(config).post_json("delete_intelligent_agent_analysis_config",
|
|
87
|
+
{"agentId": agent_id}, verbose=verbose)
|
|
88
|
+
)
|