coze_lab 0.1.15 → 0.1.16
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 +5 -0
- package/index.js +4 -1
- package/package.json +1 -1
- package/scripts/codex/cozeloop_hook.py +42 -0
package/README.md
CHANGED
|
@@ -61,6 +61,11 @@ For cloud Codex with `--cloud --agent-id=<agentId>`, Codex hooks are written to
|
|
|
61
61
|
does not already exist, so callers do not need to pass `--codex-home` for the
|
|
62
62
|
standard coze-bridge layout.
|
|
63
63
|
|
|
64
|
+
Codex hook diagnostics are appended to `hooks/cozeloop.log` under the same
|
|
65
|
+
Codex home. For cloud Codex, check
|
|
66
|
+
`~/.coze/agents/<agentId>/codex-home/hooks/cozeloop.log`. If that file is not
|
|
67
|
+
created after a new Codex turn, Codex did not load or execute the hook.
|
|
68
|
+
|
|
64
69
|
## Token lifecycle
|
|
65
70
|
|
|
66
71
|
OAuth tokens are stored in `~/.cozeloop/credentials.json` (mode 600).
|
package/index.js
CHANGED
|
@@ -4554,6 +4554,7 @@ function writeCodexHook(token, workspaceId, pythonCmd, codexHome, cloud) {
|
|
|
4554
4554
|
const hooksDir = path.join(home, 'hooks');
|
|
4555
4555
|
const hookScript = path.join(hooksDir, 'cozeloop_hook.py');
|
|
4556
4556
|
const envFile = path.join(hooksDir, 'cozeloop.env');
|
|
4557
|
+
const logFile = path.join(hooksDir, 'cozeloop.log');
|
|
4557
4558
|
const hooksJson = path.join(home, 'hooks.json');
|
|
4558
4559
|
|
|
4559
4560
|
// 1. Write Python hook scripts (trace + refresh)
|
|
@@ -4571,6 +4572,7 @@ function writeCodexHook(token, workspaceId, pythonCmd, codexHome, cloud) {
|
|
|
4571
4572
|
if (!cloud) {
|
|
4572
4573
|
envLines.push(`COZELOOP_API_TOKEN=${token}`);
|
|
4573
4574
|
}
|
|
4575
|
+
envLines.push(`COZELOOP_HOOK_LOG=${logFile}`);
|
|
4574
4576
|
envLines.push('TRACE_TO_COZELOOP=true');
|
|
4575
4577
|
// PPE 泳道:cozeloop SDK 读这两个环境变量,自动注入 x-tt-env / x-use-ppe header
|
|
4576
4578
|
envLines.push(`x_tt_env=${PPE_TT_ENV}`);
|
|
@@ -4615,7 +4617,7 @@ function writeCodexHook(token, workspaceId, pythonCmd, codexHome, cloud) {
|
|
|
4615
4617
|
ok(`Hook registered in ${hooksJson}`);
|
|
4616
4618
|
warn('Codex hook trust: 首次启动 Codex 会提示 "Hooks need review"。在该提示按 t(Trust all and continue),或在会话内运行 /hooks 后按 t,即可一次性信任全部 hook 启用 trace 上报。');
|
|
4617
4619
|
|
|
4618
|
-
return { hookScript, envFile, hooksJson };
|
|
4620
|
+
return { hookScript, envFile, hooksJson, logFile };
|
|
4619
4621
|
}
|
|
4620
4622
|
|
|
4621
4623
|
function resolveCodexHome(args) {
|
|
@@ -5325,6 +5327,7 @@ async function main() {
|
|
|
5325
5327
|
summaryLines.push(`Hook script: ${written.hookScript || '~/.codex/hooks/cozeloop_hook.py'}`);
|
|
5326
5328
|
summaryLines.push(`Config: ${written.hooksJson || '~/.codex/hooks.json'}`);
|
|
5327
5329
|
summaryLines.push(`Credentials: ${written.envFile || '~/.codex/hooks/cozeloop.env'}`);
|
|
5330
|
+
if (written.logFile) summaryLines.push(`Hook log: ${written.logFile}`);
|
|
5328
5331
|
} else {
|
|
5329
5332
|
summaryLines.push(`Config: ~/.openclaw/openclaw.json`);
|
|
5330
5333
|
}
|
package/package.json
CHANGED
|
@@ -130,12 +130,15 @@ def _make_finish_event_processor():
|
|
|
130
130
|
def _processor(info):
|
|
131
131
|
try:
|
|
132
132
|
if not getattr(info, "is_event_fail", False):
|
|
133
|
+
hook_log("upload success")
|
|
133
134
|
return
|
|
134
135
|
detail = getattr(info, "detail_msg", "") or ""
|
|
135
136
|
logid = _extract_logid(detail)
|
|
136
137
|
if logid:
|
|
138
|
+
hook_log(f"upload failed logid={logid} detail={detail[:500]}")
|
|
137
139
|
print(f"[CozeLoop] 上报失败 logid={logid} (可用 bytedcli log get-logid-log {logid} 排查)", file=sys.stderr)
|
|
138
140
|
else:
|
|
141
|
+
hook_log(f"upload failed detail={detail[:500]}")
|
|
139
142
|
print(f"[CozeLoop] 上报失败: {detail[:300]}", file=sys.stderr)
|
|
140
143
|
except Exception:
|
|
141
144
|
pass
|
|
@@ -255,8 +258,27 @@ else:
|
|
|
255
258
|
DEBUG = os.environ.get("CC_COZELOOP_DEBUG", "").lower() == "true"
|
|
256
259
|
|
|
257
260
|
|
|
261
|
+
def _log_file_path() -> str:
|
|
262
|
+
return os.environ.get("COZELOOP_HOOK_LOG", "").strip()
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def hook_log(message: str):
|
|
266
|
+
"""Append one diagnostic line to the hook log, if configured."""
|
|
267
|
+
log_path = _log_file_path()
|
|
268
|
+
if not log_path:
|
|
269
|
+
return
|
|
270
|
+
try:
|
|
271
|
+
p = Path(log_path).expanduser()
|
|
272
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
273
|
+
with p.open("a", encoding="utf-8") as f:
|
|
274
|
+
f.write(f"{datetime.now().isoformat()} {message}\n")
|
|
275
|
+
except Exception:
|
|
276
|
+
pass
|
|
277
|
+
|
|
278
|
+
|
|
258
279
|
def debug_log(message: str):
|
|
259
280
|
"""Print debug message if debug mode is enabled."""
|
|
281
|
+
hook_log(f"DEBUG {message}")
|
|
260
282
|
if DEBUG:
|
|
261
283
|
print(f"[COZELOOP_HOOK_DEBUG] {datetime.now().isoformat()} - {message}", file=sys.stderr)
|
|
262
284
|
|
|
@@ -690,12 +712,15 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, model_n
|
|
|
690
712
|
token = get_fresh_token()
|
|
691
713
|
if token:
|
|
692
714
|
os.environ["COZELOOP_API_TOKEN"] = token
|
|
715
|
+
hook_log(f"token resolved prefix={token[:12]}...")
|
|
693
716
|
print(f"[CozeLoop] Token 获取成功 ({token[:12]}...)", file=sys.stderr)
|
|
694
717
|
else:
|
|
718
|
+
hook_log("token missing")
|
|
695
719
|
print("[CozeLoop] 警告: 未找到有效 Token,上报可能失败", file=sys.stderr)
|
|
696
720
|
creds = _load_credentials()
|
|
697
721
|
workspace_id = (creds or {}).get("workspace_id") or os.environ.get("COZELOOP_WORKSPACE_ID", "") or _DEFAULT_WORKSPACE_ID
|
|
698
722
|
os.environ["COZELOOP_WORKSPACE_ID"] = workspace_id
|
|
723
|
+
hook_log(f"workspace_id={workspace_id}")
|
|
699
724
|
client_kwargs = {
|
|
700
725
|
"ultra_large_report": True,
|
|
701
726
|
"upload_timeout": 120,
|
|
@@ -1018,13 +1043,16 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, model_n
|
|
|
1018
1043
|
debug_log(f"Error processing turn {i}: {e}")
|
|
1019
1044
|
continue
|
|
1020
1045
|
|
|
1046
|
+
hook_log(f"processed turns={len(turns)} session_id={session_id}")
|
|
1021
1047
|
debug_log(f"Successfully processed {len(turns)} turn(s) for session {session_id}")
|
|
1022
1048
|
|
|
1023
1049
|
except Exception as e:
|
|
1050
|
+
hook_log(f"send exception={repr(e)}")
|
|
1024
1051
|
debug_log(f"An error occurred while sending traces to CozeLoop: {e}")
|
|
1025
1052
|
return None
|
|
1026
1053
|
finally:
|
|
1027
1054
|
client.close()
|
|
1055
|
+
hook_log("client closed")
|
|
1028
1056
|
debug_log("CozeLoop client closed.")
|
|
1029
1057
|
|
|
1030
1058
|
return ctx
|
|
@@ -1035,10 +1063,12 @@ def send_turns_to_cozeloop(turns: List[Dict[str, Any]], session_id: str, model_n
|
|
|
1035
1063
|
def main():
|
|
1036
1064
|
"""Main entry point for the Codex CozeLoop hook."""
|
|
1037
1065
|
print("[CozeLoop] Hook triggered (Codex).", file=sys.stderr)
|
|
1066
|
+
hook_log("hook triggered")
|
|
1038
1067
|
debug_log("Codex CozeLoop hook started.")
|
|
1039
1068
|
|
|
1040
1069
|
# Check if tracing is enabled
|
|
1041
1070
|
if os.environ.get("TRACE_TO_COZELOOP", "").lower() == "false":
|
|
1071
|
+
hook_log("skip trace disabled")
|
|
1042
1072
|
debug_log("TRACE_TO_COZELOOP is set to 'false', skipping")
|
|
1043
1073
|
return
|
|
1044
1074
|
|
|
@@ -1046,10 +1076,12 @@ def main():
|
|
|
1046
1076
|
try:
|
|
1047
1077
|
raw_input = sys.stdin.read().strip()
|
|
1048
1078
|
if not raw_input:
|
|
1079
|
+
hook_log("skip no stdin")
|
|
1049
1080
|
debug_log("No input received from stdin")
|
|
1050
1081
|
return
|
|
1051
1082
|
hook_input = json.loads(raw_input)
|
|
1052
1083
|
except Exception as e:
|
|
1084
|
+
hook_log(f"skip stdin parse error={repr(e)}")
|
|
1053
1085
|
debug_log(f"Error reading hook input from stdin: {e}")
|
|
1054
1086
|
return
|
|
1055
1087
|
|
|
@@ -1058,10 +1090,12 @@ def main():
|
|
|
1058
1090
|
# Get transcript path
|
|
1059
1091
|
transcript_path = hook_input.get("transcript_path")
|
|
1060
1092
|
if not transcript_path:
|
|
1093
|
+
hook_log("skip missing transcript_path")
|
|
1061
1094
|
debug_log("No transcript_path in hook input")
|
|
1062
1095
|
return
|
|
1063
1096
|
|
|
1064
1097
|
if not os.path.exists(transcript_path):
|
|
1098
|
+
hook_log(f"skip transcript not found path={transcript_path}")
|
|
1065
1099
|
debug_log(f"Transcript file not found: {transcript_path}")
|
|
1066
1100
|
return
|
|
1067
1101
|
|
|
@@ -1073,9 +1107,11 @@ def main():
|
|
|
1073
1107
|
entries = read_rollout_messages(transcript_path, state["last_processed_line"])
|
|
1074
1108
|
|
|
1075
1109
|
if not entries:
|
|
1110
|
+
hook_log(f"skip no new entries transcript={transcript_path}")
|
|
1076
1111
|
debug_log("No new entries to process")
|
|
1077
1112
|
return
|
|
1078
1113
|
|
|
1114
|
+
hook_log(f"read entries={len(entries)} from_line={state['last_processed_line']} transcript={transcript_path}")
|
|
1079
1115
|
debug_log(f"Read {len(entries)} new entries from line {state['last_processed_line']}")
|
|
1080
1116
|
|
|
1081
1117
|
# Parse session identity
|
|
@@ -1125,6 +1161,7 @@ def main():
|
|
|
1125
1161
|
last_line = max(e.get("_line_number", 0) for e in entries) + 1
|
|
1126
1162
|
state["last_processed_line"] = last_line
|
|
1127
1163
|
save_state(state_file, state)
|
|
1164
|
+
hook_log(f"subagent saved session_id={session_id} turns={len(turns[-1:])} last_line={last_line}")
|
|
1128
1165
|
debug_log("Subagent data saved, hook completed")
|
|
1129
1166
|
return
|
|
1130
1167
|
|
|
@@ -1135,6 +1172,7 @@ def main():
|
|
|
1135
1172
|
for t in turns
|
|
1136
1173
|
)
|
|
1137
1174
|
if not has_coze_ctx:
|
|
1175
|
+
hook_log(f"skip no coze-context turns={len(turns)} session_id={session_id}")
|
|
1138
1176
|
debug_log("No coze-context found in any turn, skipping upload.")
|
|
1139
1177
|
return
|
|
1140
1178
|
history_context = state.get("conversation_history", [])
|
|
@@ -1147,12 +1185,16 @@ def main():
|
|
|
1147
1185
|
state["last_processed_line"] = last_line
|
|
1148
1186
|
state["conversation_history"] = updated_history
|
|
1149
1187
|
save_state(state_file, state)
|
|
1188
|
+
hook_log(f"state advanced last_line={last_line} session_id={session_id}")
|
|
1150
1189
|
debug_log(f"State updated, last processed line: {last_line}")
|
|
1151
1190
|
else:
|
|
1191
|
+
hook_log(f"send failed state not advanced session_id={session_id}")
|
|
1152
1192
|
debug_log("Send failed, state not advanced")
|
|
1153
1193
|
else:
|
|
1194
|
+
hook_log(f"skip no turns session_id={session_id}")
|
|
1154
1195
|
debug_log("No turns to send")
|
|
1155
1196
|
|
|
1197
|
+
hook_log("hook completed")
|
|
1156
1198
|
debug_log("Codex CozeLoop hook completed.")
|
|
1157
1199
|
|
|
1158
1200
|
|