Repository: microsoft/RD-Agent
File: rdagent/oai/utils/embedding.py (Python)

Code before:

    # Get model's maximum token limit
    if max_tokens is None:
        base_max_tokens = get_embedding_max_tokens(model)
        # Apply retry strategy: reduce by 50% on each retry
        if retry_count > 3:
            # Ultimate fallback after 3 failed attempts
            max_tokens = 512
        elif retry_count >= 1:
            # Reduce by 50% on each retry for first 3 attempts
            # retry_count=1 -> use base_max_tokens (first actual retry)
            # retry_count=2 -> use base_max_tokens // 2
            # retry_count=3 -> use base_max_tokens // 4
            max_tokens = base_max_tokens // (2 ** (retry_count - 1))
        else:
            max_tokens = base_max_tokens

    # Apply safety margin only if requested (default) and not in ultimate fallback mode
    if apply_safety_margin and retry_count <= 3:
        safe_max_tokens = int(max_tokens * 0.9)
    else:
        # For forced limits or ultimate fallback, use the limit directly
        safe_max_tokens = max_tokens

    # Calculate current token count
    current_tokens = estimate_token_count(text, model)

    if current_tokens <= safe_max_tokens:
        return text

    logger.warning(
        f"Text too long for embedding model {model} (retry #{retry_count}): "
        f"{current_tokens} tokens > {safe_max_tokens} limit "
        f"{'(with safety margin)' if apply_safety_margin and retry_count <= 3 else '(forced limit)'}. "
        f"Using binary search to truncate."
    )

    # Binary search by words
    words = text.split()
    if not words:
        # Edge case: empty after split
        return ""

    left, right = 0, len(words)

    while left < right:
        mid = (left + right + 1) // 2
        truncated_text = " ".join(words[:mid])
        tokens = estimate_token_count(truncated_text, model)

        if tokens <= safe_max_tokens:

Review comment (suggestion):
```
enc_ids = encoder(model=model, text=text)
enc_ids_trunc =  enc_ids[:safe_max_tokens]
text_trunc = decoder(model=model, ids=enc_ids_trunc )
```

Code after:
        f"Text too long for embedding model {model}: "
        f"{current_tokens} tokens > {safe_max_tokens} limit (with safety margin). "
        f"Truncating using encode/decode approach."
    )

    try:
        # Use encode/decode approach for precise truncation
        enc_ids = encode(model=model, text=text)
        enc_ids_trunc = enc_ids[:safe_max_tokens]
        text_trunc = decode(model=model, tokens=enc_ids_trunc)
        # Ensure we return a string type (mypy type safety)
        text_trunc = str(text_trunc) if text_trunc is not None else ""

        final_tokens = token_counter(model=model, text=text_trunc)
        logger.warning(f"Truncation completed: {current_tokens} -> {final_tokens} tokens")

        return text_trunc
    except Exception as e:
        raise RuntimeError(
            f"Failed to truncate text for embedding model {model}. "
            f"Please set LLM_SETTINGS.embedding_max_length to a smaller value. "
            f"Original error: {e}"
        ) from e


def truncate_content_list(content_list: list[str], model: str) -> list[str]:
    """
    Truncate a list of content strings.

    Args:
        content_list: List of content strings to truncate
        model: Model name

    Returns:
        List of truncated content strings
    """
    truncated_list = []
    for content in content_list:
        truncated_content = trim_text_for_embedding(content, model)
        truncated_list.append(truncated_content)

    return truncated_list