@pippit-dev/cli 1.0.24 → 1.0.25

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.
@@ -1,162 +0,0 @@
1
- """小云雀 agent-im OpenAPI 公共模块:查询会话(鉴权为 Authorization: Bearer <access_key>)"""
2
-
3
- import json
4
- import os
5
- import sys
6
- import urllib.request
7
- import urllib.error
8
- import urllib.parse
9
-
10
- # Credentials may only be sent to the fixed production HTTPS origin.
11
- XYQ_BASE = "https://xyq.jianying.com"
12
- ACCESS_KEY = os.environ.get("XYQ_ACCESS_KEY", "")
13
-
14
- # API 路径常量
15
- GET_THREAD_PATH = "/api/biz/v1/skill/get_thread"
16
- HTTP_TIMEOUT_SECONDS = 30 * 60
17
-
18
-
19
- class _NoRedirect(urllib.request.HTTPRedirectHandler):
20
- def redirect_request(self, req, fp, code, msg, headers, newurl):
21
- # Never forward credentials or request bodies through a redirect.
22
- raise urllib.error.HTTPError(req.full_url, code, "API 重定向已拒绝", headers, fp)
23
-
24
-
25
- def authenticated_open(req):
26
- target = urllib.parse.urlsplit(req.full_url)
27
- if (target.scheme != "https" or target.hostname != "xyq.jianying.com"
28
- or target.port not in (None, 443) or target.username is not None
29
- or target.password is not None):
30
- raise urllib.error.URLError("仅允许小云雀生产 HTTPS 地址")
31
- return urllib.request.build_opener(_NoRedirect()).open(req, timeout=HTTP_TIMEOUT_SECONDS)
32
-
33
-
34
- def redact_error(value):
35
- text = str(value)
36
- return text.replace(ACCESS_KEY, "[REDACTED]") if ACCESS_KEY else text
37
-
38
-
39
- def _headers():
40
- if not ACCESS_KEY:
41
- print("错误:请设置 XYQ_ACCESS_KEY 环境变量", file=sys.stderr)
42
- sys.exit(1)
43
- return {
44
- "Authorization": f"Bearer {ACCESS_KEY}",
45
- "Content-Type": "application/json",
46
- }
47
-
48
-
49
- def api_post(path: str, body: dict) -> dict:
50
- """POST 请求 agent-im OpenAPI"""
51
- url = f"{XYQ_BASE.rstrip('/')}{path}"
52
- data = json.dumps(body).encode("utf-8")
53
- req = urllib.request.Request(
54
- url,
55
- data=data,
56
- method="POST",
57
- headers=_headers(),
58
- )
59
- try:
60
- with authenticated_open(req) as resp:
61
- return json.loads(resp.read().decode("utf-8"))
62
- except urllib.error.HTTPError as e:
63
- err_body = e.read().decode("utf-8") if e.fp else ""
64
- print(f"API 错误 {e.code}: {redact_error(err_body)}", file=sys.stderr)
65
- sys.exit(1)
66
- except urllib.error.URLError as e:
67
- print(f"网络错误: {redact_error(e.reason)}", file=sys.stderr)
68
- sys.exit(1)
69
-
70
-
71
- def api_get(path: str) -> dict:
72
- """GET 请求 agent-im OpenAPI"""
73
- url = f"{XYQ_BASE.rstrip('/')}{path}"
74
- req = urllib.request.Request(url, method="GET", headers=_headers())
75
- try:
76
- with authenticated_open(req) as resp:
77
- return json.loads(resp.read().decode("utf-8"))
78
- except urllib.error.HTTPError as e:
79
- err_body = e.read().decode("utf-8") if e.fp else ""
80
- print(f"API 错误 {e.code}: {redact_error(err_body)}", file=sys.stderr)
81
- sys.exit(1)
82
- except urllib.error.URLError as e:
83
- print(f"网络错误: {redact_error(e.reason)}", file=sys.stderr)
84
- sys.exit(1)
85
-
86
-
87
- def parse_response(resp: dict) -> dict:
88
- """
89
- 分析 API 响应。
90
- 响应结构:{"ret":"0","errmsg":"","data":{}}
91
- 如果 ret 不是 "0",打印错误信息并退出;否则返回 data。
92
- """
93
- ret = resp.get("ret", "")
94
- if ret != "0":
95
- errmsg = resp.get("errmsg", "未知错误")
96
- print(f"错误码: {redact_error(ret)}, 错误信息: {redact_error(errmsg)}", file=sys.stderr)
97
- sys.exit(1)
98
- return resp.get("data", {})
99
-
100
-
101
- def get_thread(thread_id: str, run_id: str = "", after_seq: int = 0) -> dict:
102
- """
103
- 查询会话消息列表。
104
- 返回 data: { messages: [...] }。
105
- """
106
- body = {}
107
- if thread_id:
108
- body["thread_id"] = thread_id
109
- if run_id:
110
- body["run_id"] = run_id
111
- body["after_seq"] = after_seq
112
- resp = api_post(GET_THREAD_PATH, body)
113
- resp = parse_response(resp)
114
- thread = resp.get("thread", {})
115
- run_list = thread.get("run_list", [])
116
- if len(run_list) == 0:
117
- print("错误:未返回 run_list", file=sys.stderr)
118
- sys.exit(1)
119
- run = run_list[0]
120
- run_state = run.get("state", "")
121
-
122
- # 判断 run_state
123
- if run_state == 3:
124
- # 成功
125
- print("成功:本次创作已完成", file=sys.stderr)
126
- return run
127
- elif run_state == 4:
128
- # 失败
129
- fail_reason = run.get("fail_reason", "未知失败原因")
130
- print(f"错误:{redact_error(fail_reason)}", file=sys.stderr)
131
- sys.exit(1)
132
- elif run_state == 5:
133
- # 取消
134
- print("错误:本次创作已被终止", file=sys.stderr)
135
- sys.exit(1)
136
- else:
137
- print("本次创作进行中", file=sys.stdout)
138
- return run
139
-
140
-
141
- def extract_entries_from_run(run: dict) -> list:
142
- """
143
- 从 Run 的 EntryList 中提取符合条件的 entry。
144
- """
145
- matched = []
146
- for entry in run.get("entry_list") or []:
147
- e = {}
148
- message = entry.get("message")
149
- artifact = entry.get("artifact")
150
- if message:
151
- e["id"] = message.get("message_id", "")
152
- e["role"] = message.get("role", "")
153
- e["content"] = message.get("content", [])
154
- client_tool_calls = message.get("client_tool_calls", [])
155
- if len(client_tool_calls) > 0:
156
- e["content"].extend(client_tool_calls)
157
- if artifact:
158
- e["id"] = artifact.get("artifact_id", "")
159
- e["role"] = artifact.get("role", "")
160
- e["content"] = artifact.get("content", [])
161
- matched.append(e)
162
- return matched