распознавание: большие раздачи размечаются целиком, файлы вне плана видны

- модель адресует файл номером строки нашего списка вместо копии пути: ответ
  на 180 файлов вместо ~15k токенов стоит ~2.5k, усечение сотней снято,
  max_files и max_tokens ушли в [recognition], correction-ретрай больше не
  переприсылает список
- негодный элемент ответа отбрасывается поимённой причиной, обрыв генерации и
  отказ по размеру запроса названы своими причинами, покрытие плана блокирует
  авто только при непокрытом видеофайле
- раскладка показывает все файлы раздачи со строками «не в плане» и полным
  порядком сортировки; снимок списка файлов лёг рядом с планом (миграция 0012)
This commit is contained in:
av
2026-09-02 08:54:58 +03:00
parent 01ac0430a9
commit fc9a3b4066
26 changed files with 1978 additions and 201 deletions
+20
View File
@@ -54,8 +54,17 @@ type Response struct {
Content string
Model string
Usage Usage
// FinishReason — причина завершения генерации, как её назвал провайдер
// ("stop", "length", …). Пусто — провайдер её не сообщил. Нужна
// вызывающему: обрыв по длине неотличим от мусора по одному лишь телу
// ответа, а повторять такой запрос бессмысленно (см. recognize).
FinishReason string
}
// FinishLength — значение FinishReason, которым OpenAI-совместимые провайдеры
// сообщают обрыв генерации по достижении предела токенов.
const FinishLength = "length"
// Provider — абстракция доступа к LLM. recognize работает только с ним и не
// знает про конкретный транспорт.
type Provider interface {
@@ -75,6 +84,17 @@ type Config struct {
// ErrUnknownType — запрошенный [llm].type не поддерживается.
var ErrUnknownType = errors.New("llm: unknown provider type")
// ErrRequestTooLarge — провайдер отказал из-за размера самого запроса
// (переполнение контекста), а не из-за его содержимого. Вызывающему это
// отдельная ветвь: такой отказ не лечится повтором, а называется человеку
// своей причиной и крутится настройкой ([recognition].max_files).
//
// Признак ставит транспорт — там, где ещё целы HTTP-статус и полное тело
// ответа (см. openai.go). Вызывающий проверяет его errors.Is: у итоговой
// ошибки текст обрезан и в него попадает эхо запроса, так что матчить по нему
// нельзя (docs/conventions/errors.md).
var ErrRequestTooLarge = errors.New("llm: request too large")
// New собирает провайдер по дискриминатору cfg.Type. logger nil → slog.Default().
func New(cfg Config, logger *slog.Logger) (Provider, error) {
if logger == nil {