coze_lab 0.1.42 → 0.1.43
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/package.json
CHANGED
|
@@ -550,6 +550,19 @@ def read_new_messages(file_path: str, start_line: int = 0) -> List[Dict[str, Any
|
|
|
550
550
|
|
|
551
551
|
# --- Content Helpers ---
|
|
552
552
|
|
|
553
|
+
def _usage_int(usage: Any, key: str) -> int:
|
|
554
|
+
"""Read a token count from a usage dict, treating missing/None/非数字 一律为 0。
|
|
555
|
+
|
|
556
|
+
Claude Code transcript 里 usage 的 cache_* 等字段常【存在但值为 null】,dict.get(key, 0)
|
|
557
|
+
对显式 null 返回 None 而非 0,后续 None + int / None > 0 会抛 TypeError,导致整个实时
|
|
558
|
+
上报失败、trace 查不到。这里统一兜底。
|
|
559
|
+
"""
|
|
560
|
+
if not isinstance(usage, dict):
|
|
561
|
+
return 0
|
|
562
|
+
v = usage.get(key)
|
|
563
|
+
return v if isinstance(v, int) else 0
|
|
564
|
+
|
|
565
|
+
|
|
553
566
|
def is_empty_content(content: Any) -> bool:
|
|
554
567
|
"""Return True if content carries no meaningful data."""
|
|
555
568
|
if content is None:
|
|
@@ -676,7 +689,7 @@ def _group_subagent_steps(progress_msgs: List[Dict[str, Any]]) -> List[Dict[str,
|
|
|
676
689
|
existing.extend(content)
|
|
677
690
|
last_step["tool_calls"].extend(tool_calls)
|
|
678
691
|
usage = pmsg.get("usage", {})
|
|
679
|
-
if usage
|
|
692
|
+
if _usage_int(usage, "input_tokens") > 0 or _usage_int(usage, "output_tokens") > 0:
|
|
680
693
|
last_step["assistant_message"]["message"]["usage"] = usage
|
|
681
694
|
else:
|
|
682
695
|
steps.append({
|
|
@@ -849,7 +862,7 @@ def group_messages_into_turns(messages: List[Dict[str, Any]]) -> List[Dict[str,
|
|
|
849
862
|
last_step["tool_calls"].extend(tool_calls)
|
|
850
863
|
# Carry over usage from the later line (earlier line typically has zeros)
|
|
851
864
|
usage = message.get("usage", {})
|
|
852
|
-
if usage
|
|
865
|
+
if _usage_int(usage, "input_tokens") > 0 or _usage_int(usage, "output_tokens") > 0:
|
|
853
866
|
last_step["assistant_message"]["message"]["usage"] = usage
|
|
854
867
|
else:
|
|
855
868
|
# New API response — create a new step
|
|
@@ -1329,10 +1342,10 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, history
|
|
|
1329
1342
|
|
|
1330
1343
|
# Set token usage for this specific model call
|
|
1331
1344
|
usage = assistant_message_obj.get("usage", {})
|
|
1332
|
-
input_tokens = usage
|
|
1333
|
-
output_tokens = usage
|
|
1334
|
-
cache_creation = usage
|
|
1335
|
-
cache_read = usage
|
|
1345
|
+
input_tokens = _usage_int(usage, "input_tokens")
|
|
1346
|
+
output_tokens = _usage_int(usage, "output_tokens")
|
|
1347
|
+
cache_creation = _usage_int(usage, "cache_creation_input_tokens")
|
|
1348
|
+
cache_read = _usage_int(usage, "cache_read_input_tokens")
|
|
1336
1349
|
if input_tokens > 0 or cache_creation > 0 or cache_read > 0:
|
|
1337
1350
|
model_span.set_input_tokens(input_tokens + cache_creation + cache_read)
|
|
1338
1351
|
if output_tokens > 0:
|
|
@@ -1402,10 +1415,10 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, history
|
|
|
1402
1415
|
|
|
1403
1416
|
# Distribute total usage evenly across sub-agent model steps.
|
|
1404
1417
|
total_usage = tool_call.get("_total_usage", {})
|
|
1405
|
-
total_in = (total_usage
|
|
1406
|
-
+ total_usage
|
|
1407
|
-
+ total_usage
|
|
1408
|
-
total_out = total_usage
|
|
1418
|
+
total_in = (_usage_int(total_usage, "input_tokens")
|
|
1419
|
+
+ _usage_int(total_usage, "cache_creation_input_tokens")
|
|
1420
|
+
+ _usage_int(total_usage, "cache_read_input_tokens"))
|
|
1421
|
+
total_out = _usage_int(total_usage, "output_tokens")
|
|
1409
1422
|
n_model_steps = len(sub_steps)
|
|
1410
1423
|
per_step_in = total_in // n_model_steps if n_model_steps > 0 else 0
|
|
1411
1424
|
per_step_out = total_out // n_model_steps if n_model_steps > 0 else 0
|
|
@@ -1778,12 +1791,12 @@ def send_steps_realtime(turns, session_id, history_turns, state, coze_tags_overr
|
|
|
1778
1791
|
if text_parts:
|
|
1779
1792
|
mspan.set_output("\n".join(text_parts))
|
|
1780
1793
|
usage = amo.get("usage", {})
|
|
1781
|
-
it_tok = usage
|
|
1794
|
+
it_tok = _usage_int(usage, "input_tokens") + _usage_int(usage, "cache_creation_input_tokens") + _usage_int(usage, "cache_read_input_tokens")
|
|
1782
1795
|
if it_tok > 0:
|
|
1783
1796
|
try: mspan.set_input_tokens(it_tok)
|
|
1784
1797
|
except Exception: pass
|
|
1785
|
-
if usage
|
|
1786
|
-
try: mspan.set_output_tokens(usage
|
|
1798
|
+
if _usage_int(usage, "output_tokens") > 0:
|
|
1799
|
+
try: mspan.set_output_tokens(_usage_int(usage, "output_tokens"))
|
|
1787
1800
|
except Exception: pass
|
|
1788
1801
|
mspan_ctx = client.get_span_from_header(mspan.to_header())
|
|
1789
1802
|
mspan.finish()
|
|
@@ -787,6 +787,18 @@ def truncate_text(text: str, limit: int = 12000) -> str:
|
|
|
787
787
|
|
|
788
788
|
# --- Message Grouping ---
|
|
789
789
|
|
|
790
|
+
def _usage_int(usage, key):
|
|
791
|
+
"""从 token_usage dict 读 token 数,missing/None/非数字 一律按 0。
|
|
792
|
+
|
|
793
|
+
transcript 里 token_usage 字段可能【存在但值为 null】,dict.get(key, 0) 对显式 null
|
|
794
|
+
返回 None 而非 0,后续 None > 0 / None + int 会抛 TypeError 中断上报。这里统一兜底。
|
|
795
|
+
"""
|
|
796
|
+
if not isinstance(usage, dict):
|
|
797
|
+
return 0
|
|
798
|
+
v = usage.get(key)
|
|
799
|
+
return v if isinstance(v, int) else 0
|
|
800
|
+
|
|
801
|
+
|
|
790
802
|
def _parse_ts(obj):
|
|
791
803
|
"""从 codex entry/payload 的 timestamp 解析 datetime(带时区)。失败返回 None。
|
|
792
804
|
|
|
@@ -1299,8 +1311,8 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, model_n
|
|
|
1299
1311
|
|
|
1300
1312
|
# Set token usage
|
|
1301
1313
|
token_usage = turn.get("token_usage", {})
|
|
1302
|
-
input_tokens = token_usage
|
|
1303
|
-
output_tokens = token_usage
|
|
1314
|
+
input_tokens = _usage_int(token_usage, "input_tokens")
|
|
1315
|
+
output_tokens = _usage_int(token_usage, "output_tokens")
|
|
1304
1316
|
if input_tokens > 0:
|
|
1305
1317
|
model_span.set_input_tokens(input_tokens)
|
|
1306
1318
|
if output_tokens > 0:
|
|
@@ -1446,10 +1458,12 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, model_n
|
|
|
1446
1458
|
sa_model_span.set_output(ModelOutput(choices=sa_choices))
|
|
1447
1459
|
|
|
1448
1460
|
sa_token = sa_turn.get("token_usage", {})
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
if
|
|
1452
|
-
sa_model_span.
|
|
1461
|
+
sa_in = _usage_int(sa_token, "input_tokens")
|
|
1462
|
+
sa_out = _usage_int(sa_token, "output_tokens")
|
|
1463
|
+
if sa_in > 0:
|
|
1464
|
+
sa_model_span.set_input_tokens(sa_in)
|
|
1465
|
+
if sa_out > 0:
|
|
1466
|
+
sa_model_span.set_output_tokens(sa_out)
|
|
1453
1467
|
|
|
1454
1468
|
# Subagent tool spans
|
|
1455
1469
|
for sa_tc in sa_turn.get("tool_calls", []):
|