Current section

Files

Jump to
cmdc lib cmdc agent overflow.ex
Raw

lib/cmdc/agent/overflow.ex

defmodule CMDC.Agent.Overflow do
# 内部模块 — LLM provider 上下文溢出检测。API 不保证稳定。
@moduledoc false
@overflow_patterns [
"context_length_exceeded",
"maximum context length",
"max_tokens",
"max_prompt_tokens",
"too many tokens",
"prompt is too long",
"prompt_tokens_exceeded",
"request too large",
"context window",
"token limit",
"exceeds the limit",
"input too long",
"exceeds the model's maximum",
"reduce the length",
"maximum number of tokens",
"content_too_large",
"string_above_max_length"
]
# ==========================================================================
# Public API
# ==========================================================================
@doc "返回所有溢出错误模式字符串列表。"
@spec overflow_patterns() :: [String.t()]
def overflow_patterns, do: @overflow_patterns
@doc """
返回 `true` 如果错误字符串匹配已知的上下文窗口溢出模式。
## 示例
iex> CMDC.Agent.Overflow.context_overflow?("context_length_exceeded")
true
iex> CMDC.Agent.Overflow.context_overflow?("rate_limit")
false
"""
@spec context_overflow?(term()) :: boolean()
def context_overflow?(reason) do
text = stringify(reason) |> String.downcase()
matches_any?(text, @overflow_patterns)
end
@doc """
返回 `true` 如果 input_tokens 超过 context_window。
## 示例
iex> CMDC.Agent.Overflow.usage_overflow?(250_000, 200_000)
true
"""
@spec usage_overflow?(non_neg_integer(), pos_integer()) :: boolean()
def usage_overflow?(input_tokens, context_window)
when is_integer(input_tokens) and is_integer(context_window) and context_window > 0 do
input_tokens > context_window
end
def usage_overflow?(_input_tokens, _context_window), do: false
# ==========================================================================
# 私有辅助
# ==========================================================================
defp stringify(reason) when is_binary(reason), do: reason
defp stringify(reason) when is_atom(reason), do: Atom.to_string(reason)
defp stringify(reason), do: inspect(reason)
defp matches_any?(text, patterns) do
Enum.any?(patterns, &String.contains?(text, &1))
end
end