Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pageindex/tree_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
import sys
from types import SimpleNamespace

from .utils import (ConfigLoader, _is_openai_model, llm_acompletion,
strip_internal_keys)
from .utils import (ConfigLoader, _is_openai_model, _is_unrecoverable,
llm_acompletion, strip_internal_keys)

TRIGGER_PAGES = 5 # only look ahead on nodes larger than this
ROUTING_COST = 1 # R(v), in pages
Expand Down Expand Up @@ -679,6 +679,8 @@ async def expand(structure, pages, lines, args, log, frozen):
try:
proposed = await propose_children(node, pages, args)
except Exception as exc:
if _is_unrecoverable(exc):
raise # every remaining node would fail identically
log.append({"op": "expand", "node_id": node.get("node_id"),
"decision": "error", "attempt": attempts,
"detail": f"{type(exc).__name__}: {exc}"})
Expand Down
15 changes: 15 additions & 0 deletions pageindex/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ def _is_openai_model(model):
_openai_async_client = None


# Misconfiguration: no retry can fix a rejected key or a model that does not
# exist, and every later call fails the same way. Deliberately not 400, which
# also carries context_length_exceeded, a per-prompt failure the caller absorbs
# today. An unknown status is a transport failure and stays retryable.
_UNRECOVERABLE_STATUS = frozenset({401, 403, 404})


def _is_unrecoverable(exc: Exception) -> bool:
return getattr(exc, "status_code", None) in _UNRECOVERABLE_STATUS


def llm_completion(model, prompt, chat_history=None, return_finish_reason=False):
use_openai_sdk = _is_openai_model(model)
if model:
Expand Down Expand Up @@ -76,6 +87,8 @@ def llm_completion(model, prompt, chat_history=None, return_finish_reason=False)
return content, finish_reason
return content
except Exception as e:
if _is_unrecoverable(e):
raise
print('************* Retrying *************')
logging.error(f"Error: {e}")
if i < max_retries - 1:
Expand Down Expand Up @@ -116,6 +129,8 @@ async def llm_acompletion(model, prompt):
)
return response.choices[0].message.content
except Exception as e:
if _is_unrecoverable(e):
raise
print('************* Retrying *************')
logging.error(f"Error: {e}")
if i < max_retries - 1:
Expand Down
Loading