coze_lab 0.1.24 → 0.1.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.
package/README.md CHANGED
@@ -74,6 +74,8 @@ In cloud mode, trace verification and hook uploads prefer
74
74
  `COZELOOP_API_TOKEN` and fall back to `COZE_API_TOKEN`. The selfcheck result is
75
75
  authoritative: if the token does not have trace ingest permission, onboard still
76
76
  writes the hook configuration but reports `verify=fail` with `token_source`.
77
+ For Python SDK uploads, `OTEL_ENDPOINT` is not used as the SDK base URL; set
78
+ `COZELOOP_API_BASE_URL` only when the SDK ingest endpoint should be overridden.
77
79
 
78
80
  **At hook execution time** (Claude Code / Codex), the Python hook script automatically:
79
81
  1. Reads `~/.cozeloop/credentials.json`
package/index.js CHANGED
@@ -4706,6 +4706,10 @@ function normalizeTraceAgentIds(ids) {
4706
4706
 
4707
4707
  function getCloudCozeloopApiBaseUrl() {
4708
4708
  const raw = process.env.COZELOOP_API_BASE_URL || process.env.OTEL_ENDPOINT || '';
4709
+ return normalizeCozeloopApiBaseUrl(raw);
4710
+ }
4711
+
4712
+ function normalizeCozeloopApiBaseUrl(raw) {
4709
4713
  const base = raw.trim().replace(/\/+$/, '');
4710
4714
  if (!base) return '';
4711
4715
  if (base.endsWith('/v1/loop/opentelemetry/v1/traces')) {
@@ -4730,6 +4734,14 @@ function getCozeloopApiBaseUrl(cloud) {
4730
4734
  return cloud ? (getCloudCozeloopApiBaseUrl() || COZE_API) : COZE_API;
4731
4735
  }
4732
4736
 
4737
+ function getCloudCozeloopSdkApiBaseUrl() {
4738
+ return normalizeCozeloopApiBaseUrl(process.env.COZELOOP_API_BASE_URL || '');
4739
+ }
4740
+
4741
+ function getCozeloopSdkApiBaseUrl(cloud) {
4742
+ return cloud ? (getCloudCozeloopSdkApiBaseUrl() || COZE_API) : COZE_API;
4743
+ }
4744
+
4733
4745
  function getOtelEndpointBase(cloud) {
4734
4746
  return `${getCozeloopApiBaseUrl(cloud).replace(/\/+$/, '')}/v1/loop/opentelemetry`;
4735
4747
  }
@@ -4935,11 +4947,13 @@ function runCommand(input) {
4935
4947
 
4936
4948
  async function verifyTraceReportViaSdk(token, workspaceId, pairCode, pythonCmd, tokenSource) {
4937
4949
  const pair = pairCode || crypto.randomBytes(6).toString('hex');
4938
- const apiBase = getCozeloopApiBaseUrl(true);
4950
+ const apiBase = getCozeloopSdkApiBaseUrl(true);
4939
4951
  const script = `
4940
4952
  import json
4941
4953
  import os
4942
4954
  import sys
4955
+ import urllib.error
4956
+ import urllib.request
4943
4957
 
4944
4958
  events = []
4945
4959
 
@@ -4947,6 +4961,51 @@ def finish_event(info):
4947
4961
  if getattr(info, "is_event_fail", False):
4948
4962
  events.append(getattr(info, "detail_msg", "") or "trace export failed")
4949
4963
 
4964
+ def extract_logid(text):
4965
+ if not text:
4966
+ return ""
4967
+ marker = "logid="
4968
+ idx = text.find(marker)
4969
+ if idx >= 0:
4970
+ out = []
4971
+ for ch in text[idx + len(marker):]:
4972
+ if ch.isalnum():
4973
+ out.append(ch)
4974
+ else:
4975
+ break
4976
+ return "".join(out)
4977
+ for marker in ('"logid":"', '"log_id":"', '"Logid":"'):
4978
+ idx = text.find(marker)
4979
+ if idx >= 0:
4980
+ rest = text[idx + len(marker):]
4981
+ return rest.split('"', 1)[0]
4982
+ return ""
4983
+
4984
+ def http_diag():
4985
+ base = os.environ.get("COZELOOP_API_BASE_URL", "").strip().rstrip("/") or "https://api.coze.cn"
4986
+ url = base + "/v1/loop/traces/ingest"
4987
+ body = json.dumps({"spans": []}).encode()
4988
+ req = urllib.request.Request(
4989
+ url,
4990
+ data=body,
4991
+ headers={
4992
+ "Content-Type": "application/json",
4993
+ "Authorization": "Bearer " + os.environ.get("COZELOOP_API_TOKEN", ""),
4994
+ "x-tt-env": os.environ.get("x_tt_env", ""),
4995
+ "x-use-ppe": os.environ.get("x_use_ppe", ""),
4996
+ },
4997
+ method="POST",
4998
+ )
4999
+ try:
5000
+ with urllib.request.urlopen(req, timeout=10) as resp:
5001
+ text = resp.read().decode("utf-8", "replace")
5002
+ return {"url": url, "status": resp.status, "logid": resp.headers.get("x-tt-logid", "") or extract_logid(text), "body": text[:300]}
5003
+ except urllib.error.HTTPError as e:
5004
+ text = e.read().decode("utf-8", "replace")
5005
+ return {"url": url, "status": e.code, "logid": e.headers.get("x-tt-logid", "") or extract_logid(text), "body": text[:300]}
5006
+ except Exception as e:
5007
+ return {"url": url, "status": 0, "logid": "", "body": type(e).__name__ + ": " + str(e)}
5008
+
4950
5009
  try:
4951
5010
  import cozeloop
4952
5011
  kwargs = {
@@ -4966,11 +5025,15 @@ try:
4966
5025
  client.flush()
4967
5026
  client.close()
4968
5027
  if events:
4969
- print(json.dumps({"success": False, "body": "\\n".join(events), "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
5028
+ diag = http_diag()
5029
+ body = "\\n".join(events) + "\\nhttp_diag=" + json.dumps(diag, ensure_ascii=False)
5030
+ print(json.dumps({"success": False, "body": body, "logid": diag.get("logid", ""), "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
4970
5031
  sys.exit(1)
4971
- print(json.dumps({"success": True, "body": "", "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
5032
+ print(json.dumps({"success": True, "body": "", "logid": "", "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
4972
5033
  except Exception as e:
4973
- print(json.dumps({"success": False, "body": str(e), "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
5034
+ diag = http_diag()
5035
+ body = str(e) + "\\nhttp_diag=" + json.dumps(diag, ensure_ascii=False)
5036
+ print(json.dumps({"success": False, "body": body, "logid": diag.get("logid", ""), "api_base_url": os.environ.get("COZELOOP_API_BASE_URL", ""), "token_source": os.environ.get("COZELOOP_TOKEN_SOURCE", "")}, ensure_ascii=False))
4974
5037
  sys.exit(1)
4975
5038
  `;
4976
5039
  const env = {
@@ -5005,7 +5068,7 @@ except Exception as e:
5005
5068
  const snippet = String(body || '').slice(0, 300);
5006
5069
  if (snippet) console.log(snippet);
5007
5070
  }
5008
- return { success, status: result.code || 0, body, traceId: '', pairCode: pair, apiBaseUrl: apiBase, tokenSource };
5071
+ return { success, status: result.code || 0, body, traceId: '', pairCode: pair, apiBaseUrl: apiBase, tokenSource, logid: parsed?.logid || '' };
5009
5072
  }
5010
5073
 
5011
5074
  // 真实发一条最小 OTLP trace 到 CozeLoop,验证上报链路是否打通。
@@ -5538,7 +5601,7 @@ async function main() {
5538
5601
  } else if (CLOUD_MODE) {
5539
5602
  // 云端:注入已成功,验证失败不阻断(放行),记录结果供后台弹 warning。
5540
5603
  cloudResult.verify = 'fail';
5541
- cloudResult.logid = extractLogid(verifyResult.body) || cloudResult.logid;
5604
+ cloudResult.logid = verifyResult.logid || extractLogid(verifyResult.body) || cloudResult.logid;
5542
5605
  cloudResult.message = `trace 上报自检失败 HTTP ${verifyResult.status}: ${(verifyResult.body || '').slice(0, 200)}`;
5543
5606
  warn('trace 上报自检失败,但 hook 配置已写入(云端放行)。');
5544
5607
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coze_lab",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Configure local AI agents (Claude Code, Codex, OpenClaw) to report traces to CozeLoop",
5
5
  "keywords": [
6
6
  "cozeloop",
@@ -264,7 +264,7 @@ def _normalize_api_base_url(url: str) -> str:
264
264
 
265
265
  def get_api_base_url() -> str:
266
266
  return _normalize_api_base_url(
267
- os.environ.get("COZELOOP_API_BASE_URL", "") or os.environ.get("OTEL_ENDPOINT", "")
267
+ os.environ.get("COZELOOP_API_BASE_URL", "")
268
268
  )
269
269
 
270
270
  def get_fresh_token() -> Optional[str]:
@@ -225,7 +225,7 @@ def _normalize_api_base_url(url: str) -> str:
225
225
 
226
226
  def get_api_base_url() -> str:
227
227
  return _normalize_api_base_url(
228
- os.environ.get("COZELOOP_API_BASE_URL", "") or os.environ.get("OTEL_ENDPOINT", "")
228
+ os.environ.get("COZELOOP_API_BASE_URL", "")
229
229
  )
230
230
 
231
231