fix(channel): auto-recover from 529 and normalize cross-provider tool_use ids#31
Merged
Conversation
…_use ids
Two related channel-session stability fixes:
1. 529 (overloaded) auto-recovery
- Detect transient API errors (529/429/503/overloaded) via new
is_transient_api_error() + TransientApiError, honoring the
stream-json "is_error" flag (stream_handler.rs)
- handle_transient_api_recovery(): jittered exponential backoff retry
of the same --resume session, bounded by recovery_depth (event_dispatch.rs)
- Implement Full Jitter in RetryPolicy::delay_for_attempt() (retry.rs)
- Clean up the tracked Claude PID when the thinking-message send fails,
preventing "Busy" lock from a lingering zombie PID (event_dispatch.rs)
2. Cross-provider session resume compatibility
- Anthropic API requires toolu_* tool_use ids; ZAI/GLM emit call_* (OpenAI
style), causing HTTP 400 on resume -> "recent session not found"
- sanitize_session_tool_use_ids(): 2-pass remap of call_* -> toolu_* on
both assistant tool_use.id and user tool_result.tool_use_id (sessions.rs)
- Wired into sanitize_session(); surfaces in all 3 sanitize log sites
Tests: +18 unit tests across stream_handler/retry/sessions.
fmt/clippy clean, full suite green (346 + 11).
- Gate transient-API classification on stream-json is_error so a normal assistant result mentioning 'rate limit'/'overloaded' is never discarded and replayed as a 529 (removes the tautological is_error dead branch) - Split context-limit and transient recovery into independent depth counters so a transient retry can no longer exhaust the compaction budget and clear the session - Kill (not just untrack) the tracked Claude PID before recovery re-entry, and dedupe the two transient entry blocks into one helper - Read session JSONL once in sanitize_session and reuse parsed content across all sanitizer cores; unify the two id validators
This was referenced Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
두 가지 채널 세션 안정성 개선입니다.
1. 529(서버 과부하) 자동 복구
Telegram 등 채널에서 Claude API가
529 Overloaded를 반환한 뒤 세션이 복구되지 않던 문제를 해결합니다. 이전에는 컨텍스트 한계(context_limit)에만 자동 복구 경로가 있었습니다.is_transient_api_error()+TransientApiError추가 — 529/429/503/overloaded/rate limit 패턴과 stream-json의is_error: true플래그 모두 인식 (stream_handler.rs)handle_transient_api_recovery()— 동일 세션--resume으로 지수 백오프 + jitter 자동 재시도 (최대 3회,recovery_depth로 무한 루프 방지) (event_dispatch.rs)RetryPolicy::delay_for_attempt()에 Full Jitter(AWS 패턴) 구현 — 이전엔jitter필드가 선언만 되고 미사용 (retry.rs)event_dispatch.rs)동작: 529 감지 → raw 에러 표시 → "Retrying in Xs (1/3)..." → 백오프 후 동일 세션 재시도 → 성공 시 정상 응답, 3회 실패 시 안내.
2. provider 교차 세션 resume 호환성
claude -c와claudy <zai-profile> -c를 같은 디렉토리에서 번갈아 쓸 때 최근 세션이 안 이어지던 문제를 해결합니다.루트 코스 (실제 세션 파일에서 검증):
tool_use.id=call_<hex>(OpenAI 스타일)tool_use.id=toolu_<base62>(Anthropic 표준)Anthropic API는
toolu_패턴을 요구하므로, zai 세션을 claude로 resume하면 history의call_*ID로 400 거부 → 세션 로드 실패 → "최근 세션이 안 보임".sanitize_session_tool_use_ids(): 기존server_tool_usesanitizer와 동일한 2-pass 패턴으로call_*→toolu_*변환. assistant의tool_use.id와 user의tool_result.tool_use_id양쪽을 atomic 재작성.type=="tool_use"만 처리해server_tool_use와 충돌 방지 (sessions.rs)sanitize_session()통합 → resume 직전 자동 실행 (3개 호출부 변경 없이 자동 적용)tool_use_ids=N필드 추가Test plan
cargo fmtcargo clippy -- -D warningscargo test— 346 unit + 11 integration, 전부 통과 (+18 신규 테스트)claude -c→ resume 직전tool_use_ids=N로그 → 세션 정상 이어짐Notes
CLAUDE_CONFIG_DIR분리는 의도된 동작).