This commit implements fully automatic injection of online research results into the LLM prompt without user clicks.
## Backend
### Environment Variables
- Added `PAPAYU_ONLINE_AUTO_USE_AS_CONTEXT=1` (default: 0) to enable automatic injection of online research results into subsequent `proposeActions` calls.
- Added `is_online_auto_use_as_context()` helper function in `online_research/mod.rs`.
### Command Changes
- **`propose_actions` command**: Added `online_fallback_reason: Option<String>` parameter to track the error code that triggered online fallback.
- **`llm_planner::plan` function**: Added `online_fallback_reason: Option<&str>` parameter for tracing.
- **Trace Enhancements**: Added `online_fallback_reason` field to trace when `online_fallback_executed` is true.
### Module Exports
- Made `extract_error_code_prefix` public in `online_research/fallback.rs` for frontend use.
## Frontend
### Project Settings
- Added `onlineAutoUseAsContext` state (persisted in `localStorage` as `papa_yu_online_auto_use_as_context`).
- Initialized from localStorage or defaults to `false`.
- Auto-saved to localStorage on change.
### Auto-Chain Flow
- When `plan.ok === false` and `plan.online_fallback_suggested` is present:
- If `onlineAutoUseAsContext === true` and not already attempted for this goal (cycle protection via `lastGoalWithOnlineFallbackRef`):
- Automatically calls `researchAnswer(query)`.
- Truncates result to `8000` chars and `10` sources (frontend-side limits).
- Immediately calls `proposeActions` again with:
- `online_context_md`
- `online_context_sources`
- `online_fallback_executed: true`
- `online_fallback_reason: error_code`
- `online_fallback_attempted: true`
- Displays the new plan/error without requiring "Use as context" button click.
- If `onlineAutoUseAsContext === false` or already attempted:
- Falls back to manual mode (shows online research block with "Use as context (once)" button).
### Cycle Protection
- `lastGoalWithOnlineFallbackRef` tracks the last goal that triggered online fallback.
- If the same goal triggers fallback again, auto-chain is skipped to prevent infinite loops.
- Maximum 1 auto-chain per user query.
### UI Enhancements
- **Online Research Block**:
- When `onlineAutoUseAsContext === true`: displays "Auto-used ✓" badge.
- Hides "Use as context (once)" button when auto-use is enabled.
- Adds "Disable auto-use" button (red) to disable auto-use for the current project.
- When disabled, shows system message: "Auto-use отключён для текущего проекта."
### API Updates
- **`proposeActions` in `tauri.ts`**: Added `onlineFallbackReason?: string | null` parameter.
## Tests
- **`online_context_auto_test.rs`**: Added unit tests for:
- `test_is_online_auto_use_disabled_by_default`
- `test_is_online_auto_use_enabled_when_set`
- `test_extract_error_code_prefix_timeout`
- `test_extract_error_code_prefix_schema`
- `test_extract_error_code_prefix_empty_when_no_prefix`
All tests pass.
## Documentation
### README.md
- Added "Auto-use (X4)" subsection under "Online Research":
- Describes `PAPAYU_ONLINE_AUTO_USE_AS_CONTEXT=1` env var (default: 0).
- Explains cycle protection: maximum 1 auto-chain per goal.
- Documents UI behavior: "Auto-used ✓" badge and "Disable auto-use" button.
## Behavior Summary
**Without auto-use (default):**
1. `proposeActions` → error + `online_fallback_suggested`
2. UI calls `researchAnswer`
3. UI displays online research block with "Use as context (once)" button
4. User clicks button → sets `onlineContextPending` → next `proposeActions` includes context
**With auto-use enabled (`PAPAYU_ONLINE_AUTO_USE_AS_CONTEXT=1`):**
1. `proposeActions` → error + `online_fallback_suggested`
2. UI calls `researchAnswer` automatically
3. UI displays online research block with "Auto-used ✓" badge
4. UI immediately calls `proposeActions` again with online context → displays new plan
5. If still fails → no retry (cycle protection)
## Build Status
- ✅ Backend: `cargo build --lib` (2 warnings about unused code for future features)
- ✅ Frontend: `npm run build`
- ✅ Tests: `cargo test online_context_auto_test --lib` (5 passed)
Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
4.8 KiB
Markdown
99 lines
4.8 KiB
Markdown
# Protocol v1 — контракт papa-yu
|
||
|
||
Краткий документ (1–2 страницы): что гарантируется, лимиты, логирование, PLAN→APPLY, strict/best-effort.
|
||
|
||
---
|
||
|
||
## Версионирование
|
||
|
||
- **schema_version:** 1
|
||
- **schema_hash:** sha256 от `llm_response_schema.json` (в trace)
|
||
- При изменении контракта — увеличивать schema_version; v2 — новый документ.
|
||
|
||
**Default protocol:** v2; Apply может fallback на v1 при специфичных кодах ошибок (см. PROTOCOL_V2_PLAN.md).
|
||
|
||
---
|
||
|
||
## Гарантии
|
||
|
||
1. **JSON:** ответ LLM парсится; при неудаче — 1 repair-ретрай с подсказкой.
|
||
2. **Валидация:** path (no `../`, absolute, `~`), конфликты действий, content (no NUL, pseudo-binary).
|
||
3. **UPDATE base:** в APPLY каждый UPDATE_FILE — только для файлов, прочитанных в Plan.
|
||
4. **Protected paths:** `.env`, `*.pem`, `*.key`, `id_rsa*`, `**/secrets/**` — запрещены.
|
||
5. **Apply:** snapshot → apply → auto_check; при падении check — rollback.
|
||
|
||
---
|
||
|
||
## Лимиты
|
||
|
||
| Область | Переменная | По умолчанию |
|
||
|---------|------------|--------------|
|
||
| path_len | — | 240 |
|
||
| actions | — | 200 |
|
||
| total_content_bytes | — | 5MB |
|
||
| context_files | PAPAYU_CONTEXT_MAX_FILES | 8 |
|
||
| file_chars | PAPAYU_CONTEXT_MAX_FILE_CHARS | 20000 |
|
||
| context_total | PAPAYU_CONTEXT_MAX_TOTAL_CHARS | 120000 |
|
||
|
||
---
|
||
|
||
## Логирование
|
||
|
||
| Событие | Где |
|
||
|---------|-----|
|
||
| LLM_REQUEST_SENT | stderr (model, schema_version, provider, token_budget, input_chars) |
|
||
| LLM_RESPONSE_OK, LLM_RESPONSE_REPAIR | stderr |
|
||
| VALIDATION_FAILED | stderr (code, reason) |
|
||
| CONTEXT_CACHE_HIT, CONTEXT_CACHE_MISS | stderr (key) |
|
||
| CONTEXT_DIET_APPLIED | stderr (files, dropped, truncated, total_chars) |
|
||
| APPLY_SUCCESS, APPLY_ROLLBACK, PREVIEW_READY | stderr |
|
||
|
||
**Trace (PAPAYU_TRACE=1):** `.papa-yu/traces/<trace_id>.json` — config_snapshot, context_stats, cache_stats, validated_json, schema_version, schema_hash.
|
||
|
||
---
|
||
|
||
## PLAN → APPLY
|
||
|
||
1. **Plan:** `plan: <текст>` или «исправь/почини» → LLM возвращает `actions: []`, `summary`, `context_requests`.
|
||
2. **Apply:** `apply: <текст>` или «ok»/«применяй» при сохранённом плане → LLM применяет план с тем же context.
|
||
3. **NO_CHANGES:** при пустом `actions` в APPLY — `summary` обязан начинаться с `NO_CHANGES:`.
|
||
|
||
---
|
||
|
||
## Strict / best-effort
|
||
|
||
- **strict (PAPAYU_LLM_STRICT_JSON=1):** `response_format: json_schema` в API; при ошибке schema — repair-ретрай.
|
||
- **best-effort:** без response_format; извлечение из ```json ... ```; при ошибке — repair-ретрай.
|
||
- **Capability detection:** при 4xx/5xx с упоминанием response_format — retry без него.
|
||
|
||
---
|
||
|
||
## Кеш контекста
|
||
|
||
read_file, search, logs, env кешируются в plan-цикле. Ключ Logs: `{source, last_n}` — разные last_n не пересекаются.
|
||
|
||
---
|
||
|
||
## Контекст-диета
|
||
|
||
При превышении лимитов — урезание: search → logs → файлы низкого приоритета; FILE (read_file) — последними; для priority=0 гарантия минимум 4k chars.
|
||
|
||
---
|
||
|
||
## Provider Compatibility
|
||
|
||
| Provider | Endpoint | `response_format: json_schema` | `strict` | OneOf (array/object) | Режим |
|
||
|----------|----------|--------------------------------:|---------:|---------------------:|-------|
|
||
| OpenAI | `/v1/chat/completions` | ✅ | ✅ | ✅ | strict + local validate |
|
||
| OpenAI-compatible (часть) | разные | ⚠️ | ⚠️ | ⚠️ | best-effort + local validate + repair |
|
||
| Ollama | `/api/chat` | ❌ (часто) | ❌ | ⚠️ | best-effort + local validate + repair |
|
||
|
||
**Поведенческие гарантии:**
|
||
1. Если `response_format` не поддержан провайдером → fallback и лог `LLM_RESPONSE_FORMAT_FALLBACK`.
|
||
2. Локальная schema validation выполняется всегда (если schema compile ok).
|
||
3. Repair-ретрай выполняется один раз при невалидном JSON.
|
||
4. Если после repair невалидно → Err.
|
||
5. Capability detection: при 4xx/5xx с упоминанием response_format/json_schema → retry без него.
|
||
|
||
Ускоряет диагностику: если Ollama/локальная модель «тупит» — выключи `PAPAYU_LLM_STRICT_JSON` или оставь пустым.
|