Document source fallback on session_compact, defer steer delivery when !isIdle, kept-window skill-reinject:inject entries, and double-compact acceptance criteria before implementation. Co-authored-by: Cursor <cursoragent@cursor.com>
36 KiB
ТЗ: pi-skill-reinject
Extension для Pi Coding Agent, который отслеживает уже вызванные skills и повторно инжектит их в контекст после auto compaction.
Статус: draft
Репозиторий: pi-auto-reinjection
Целевая платформа: upstream Pi (earendil-works/pi), не форки (oh-my-pi и т.п.)
1. Проблема
Pi использует progressive disclosure для skills: в system prompt всегда только name + description, полный SKILL.md попадает в контекст через read или /skill:name (skills.md).
При compaction старые сообщения суммаризуются; полный текст skill-блоков из «сжатой» части истории теряется (compaction.md). После auto compaction:
- descriptions skills остаются в system prompt;
- модель не обязана снова читать
SKILL.md(skills.md — «models don't always do this»); - встроенного механизма re-inject в upstream Pi нет.
2. Цель
Универсальный extension, который:
- Отслеживает skills, реально использованные в сессии.
- После auto compaction повторно инжектит их в контекст (как при
/skill:name). - По умолчанию выключен; включается командой на уровне сессии или глобально (навсегда).
3. Не-цели (v1)
- Замена/обёртка стандартного compaction summary.
- Re-inject после ручного
/compact(опционально в v2, см. §8). - Поддержка oh-my-pi-специфики (
compaction.autoContinue, snapcompact и т.д.). - Re-inject skills, которые модель «прочитала» через
read, но пользователь явно не вызывал — только если включена опцияtrackReadPaths(см. §6.2, по умолчаниюtrue). - Изменения в сторонних extensions (в т.ч. pi-auto-compact) — только опциональная интеграция на нашей стороне с автоопределением (§16).
4. Ссылки на документацию Pi
| Тема | Ссылка |
|---|---|
| Extensions (API, события, команды) | packages/coding-agent/docs/extensions.md |
| Compaction (когда срабатывает, что теряется) | packages/coding-agent/docs/compaction.md |
| Skills (вызов, формат, progressive disclosure) | packages/coding-agent/docs/skills.md |
| Settings (глобальные / project overrides) | packages/coding-agent/docs/settings.md |
| Примеры extensions | packages/coding-agent/examples/extensions/ |
sendUserMessage |
send-user-message.ts |
| Custom compaction hook | custom-compaction.ts |
parseSkillBlock (формат skill-блока) |
agent-session.ts |
_expandSkillCommand (как Pi разворачивает /skill:name) |
agent-session.ts |
| Agent Skills standard | agentskills.io |
| pi-auto-compact (совместимость) | github.com/capyup/pi-auto-compact |
| pi-auto-compact исходник | extensions/auto-compact.ts |
| Inter-extension events | event-bus.ts example |
before_agent_start (inject message) |
extensions.md — before_agent_start |
5. Поведение
5.1. Режимы включения
Три независимых слоя (приоритет сверху вниз):
| Слой | Хранение | Default | Описание |
|---|---|---|---|
| Session override | pi.appendEntry("skill-reinject:config", …) |
null (нет override) |
Вкл/выкл только в текущей сессии |
| Global default | ~/.pi/agent/settings.json → skillReinject.enabled |
false |
«Навсегда» для всех новых сессий |
| Effective | вычисляется | false |
sessionOverride ?? globalDefault |
Команда /skill-reinject (см. §7) меняет session override или global default.
Важно: session override не переживает /resume в другую сессию — восстанавливается из entries этой сессии. Global default читается при session_start.
5.2. Когда делать re-inject
Триггер: событие extension session_compact (extensions.md — session_before_compact / session_compact).
Условия (все должны выполниться):
effectiveEnabled === true- Compaction не отменён (
session_compactуспешно отработал) - Источник compaction = auto (
thresholdилиoverflow), не manual/compact
→ см. §8 про детекцию источника - Есть хотя бы один tracked skill, отсутствующий в kept-части контекста (§6.4)
- Skill всё ещё зарегистрирован в
resourceLoader(не удалён с диска)
Не делать re-inject:
- при
session_before_compactсcancel: true; - если список skills для re-inject пуст;
- если агент в момент
session_compactстримит иwillRetry === true(overflow recovery) — отложить доagent_endили использоватьdeliverAs: "followUp"(§6.5).
5.3. Что именно инжектить
Повторять поведение Pi _expandSkillCommand: user message с блоком
<skill name="{name}" location="{filePath}">
References are relative to {baseDir}.
{body без YAML frontmatter}
</skill>
Опционально добавлять служебный суффикс (конфигурируемо):
[skill-reinject] Re-applied after compaction. Follow this skill's workflow.
Не использовать цепочку /skill:a /skill:b в одном сообщении — Pi разворачивает только один /skill: на сообщение.
Для N skills при доставке через sendUserMessage: отдельное сообщение на skill, порядок = порядок первого вызова в сессии.
При доставке через before_agent_start или mid-turn sendMessage/steer (§6.5, режим defer, в т.ч. с pi-auto-compact): одно injected message с customType: "skill-reinject:inject" и всеми skill-блоками подряд (меньше turn'ов, нет гонки с follow-up).
6. Отслеживание skills
6.1. Структура состояния
interface TrackedSkill {
name: string; // frontmatter name
filePath: string; // абсолютный путь к SKILL.md
baseDir: string; // директория skill
firstSeenAt: number; // timestamp
lastSeenAt: number;
sources: Array<"slash" | "skill-block" | "read">;
}
interface ExtensionState {
version: 1;
sessionOverride: boolean | null;
skills: TrackedSkill[]; // dedupe by name, preserve insertion order
lastCompactionSource: "auto" | "manual" | null;
/** Skills, ожидающие re-inject (§6.5): idle → before_agent_start; mid-turn → steer на session_compact */
pendingReinject: string[]; // skill names
}
/** Runtime-only, не персистить */
interface RuntimeFlags {
autoCompactDetected: boolean;
autoCompactIntegration: "auto" | "defer" | "immediate" | "off";
}
In-memory кэш + персистенция через pi.appendEntry при каждом изменении tracked skills / session override.
6.2. Источники детекции
| # | Событие | Условие | source |
|---|---|---|---|
| 1 | input |
event.text matches /^\/skill:([a-z0-9-]+)/ |
slash |
| 2 | message_end (user) |
текст содержит <skill name="…" (regex из parseSkillBlock) |
skill-block |
| 3 | tool_call / tool_result |
toolName === "read" и path совпадает с SKILL.md известного skill |
read |
Для (3): сопоставлять path с skill.filePath из ctx / getSkills() (formatSkillsForPrompt).
Опция skillReinject.trackReadPaths (default true): если false, игнорировать детекцию через read.
6.3. Восстановление при session_start / /resume
На session_start (включая reason: "reload"):
- Пройти
ctx.sessionManager.getBranch():- entries
type === "custom"сcustomType === "skill-reinject:state"→ восстановить state; - user messages → re-scan skill blocks;
- entries
- Если entries state нет — full rescan ветки.
6.4. Skills уже в kept-контексте
После compaction часть recent messages сохраняется (keepRecentTokens, default 20k — settings.md).
Перед re-inject:
- Взять entries от
compactionEntry.firstKeptEntryIdдо хвоста ветки. - Для каждого tracked skill: если в kept window есть
<skill name="{name}"→ пропустить re-inject для этого skill. - Источники текста в kept slice:
- user messages (
type === "message",role === "user"); - наши reinject-сообщения:
type === "custom_message"сcustomType === "skill-reinject:inject"(§6.5.1) — skill-блоки вcontent, не в user role.
- user messages (
Пункт 3 закрывает ложное «skill вне kept» после успешного defer-reinject: custom_message не user message, но skill уже в контексте turn'а. Без этого второй compaction подряд снова планирует reinject (лишний inject; см. §16.6).
6.5. Доставка после compaction
Два режима доставки (выбор — §6.5.1 / §16):
6.5.1. Режим defer (рекомендуемый по умолчанию при наличии pi-auto-compact)
- На
session_compact: записать имена skills вstate.pendingReinject(не вызыватьsendUserMessage). - Доставка — одна точка решения на
session_compactпоctx.isIdle():
Условие на session_compact |
Доставка |
|---|---|
ctx.isIdle() |
Оставить pendingReinject; consume на следующем before_agent_start (kickoff pi-auto-compact follow-up / user prompt) |
!ctx.isIdle() (mid-turn compaction) |
Немедленно: pi.sendMessage({ customType: "skill-reinject:inject", content, display: true }, { deliverAs: "steer" }); очистить pendingReinject; записать compactionEntry.id в runtime, чтобы before_agent_start не дублировал inject для этого compaction |
- На
before_agent_start(idle-path): еслиpendingReinjectне пуст и steer для этого compaction ещё не доставлялся — вернуть injectedmessageсcustomType: "skill-reinject:inject"и объединёнными skill-блоками, очистить очередь.
Mid-turn steer: deliverAs: "steer" ставит skill-блоки в очередь до следующего LLM-вызова в том же turn (после tool result, без user prompt). Это закрывает сценарий, когда pi-auto-compact компактирует mid-turn и не шлёт follow-up (агент не idle) — consume только на before_agent_start теряет skill до следующего сообщения пользователя (B-003).
Не вызывать sendUserMessage в session_compact (§16.2). Steer — не user message и не конкурирует с pi-auto-compact follow-up на turn boundary.
На turn-boundary path skills попадают в контекст в том же turn, что и kickoff-сообщение (в т.ч. auto-continue от pi-auto-compact), без гонки sendUserMessage.
6.5.2. Режим immediate (sendUserMessage)
Использовать pi.sendUserMessage (extensions.md — sendUserMessage):
| Ситуация | Стратегия |
|---|---|
| Агент idle после compaction | Первый skill → sendUserMessage(expandedBlock); остальные → followUp |
Overflow recovery (willRetry) |
Все skills → sendUserMessage(..., { deliverAs: "followUp" }) |
| Агент стримит | deliverAs: "followUp" для всех |
Не использовать immediate, если обнаружен pi-auto-compact и autoCompactIntegration !== "off" — см. §16.
6.5.3. Выбор режима
| Условие | Режим доставки |
|---|---|
autoCompactIntegration: "defer" |
всегда defer |
autoCompactIntegration: "immediate" |
всегда sendUserMessage |
autoCompactIntegration: "off" |
по triggerTurn (§7.3) |
autoCompactIntegration: "auto" (default) + pi-auto-compact обнаружен |
defer |
autoCompactIntegration: "auto" + pi-auto-compact не обнаружен + triggerTurn: false |
defer (ждать следующий user prompt) |
autoCompactIntegration: "auto" + pi-auto-compact не обнаружен + triggerTurn: true |
immediate |
Важно: встроенный Pi auto-compaction (_runAutoCompaction) при reason: "threshold" не продолжает turn (willRetry: false). С установленным pi-auto-compact продолжение обеспечивает он, не Pi — наш defer рассчитан на этот сценарий.
7. Команда /skill-reinject
Зарегистрировать через pi.registerCommand("skill-reinject", …) (extensions.md — registerCommand).
7.1. Синтаксис
/skill-reinject # статус
/skill-reinject on # вкл в этой сессии
/skill-reinject off # выкл в этой сессии
/skill-reinject reset # сброс session override → global default
/skill-reinject global on # вкл навсегда (~/.pi/agent/settings.json)
/skill-reinject global off # выкл навсегда
/skill-reinject list # tracked skills
/skill-reinject clear # очистить tracked skills (не трогает toggle)
/skill-reinject now # принудительный re-inject (debug)
/skill-reinject integration auto|defer|immediate|off # режим доставки (§6.5, §16)
Алиасы (опционально): /sr, /skills-reinject.
7.2. Вывод /skill-reinject (status)
skill-reinject: off (session override) | on (global) | on (session)
delivery: defer (pi-auto-compact detected) | immediate | defer
tracked: 2 skills — redmine-issue-context, fup-blame-commits
pending reinject: 0
last compaction: auto @ 14:32
Footer status через ctx.ui.setStatus("skill-reinject", "on·2") (status-line.ts example).
7.3. Global settings
Писать в ~/.pi/agent/settings.json (merge, не затирать файл целиком):
{
"skillReinject": {
"enabled": false,
"trackReadPaths": true,
"triggerTurn": false,
"reinjectOnManualCompaction": false,
"autoCompactIntegration": "auto",
"suffix": "[skill-reinject] Re-applied after compaction."
}
}
| Поле | Default | Описание |
|---|---|---|
autoCompactIntegration |
"auto" |
"auto" | "defer" | "immediate" | "off" — см. §6.5.3, §16 |
Project override: .pi/settings.json → тот же ключ (merged по правилам Pi, settings.md — Project Overrides).
8. Детекция auto vs manual compaction
Extension event session_compact не передаёт reason (SessionCompactEvent).
Стратегия v1:
// input handler (до expansion) — единственный путь manual
if (text.startsWith("/compact")) pendingCompactionSource = "manual";
function ensureCompactionSourceMarked(runtime) {
if (runtime.pendingCompactionSource !== "manual") {
runtime.pendingCompactionSource = "auto";
}
}
// session_before_compact
ensureCompactionSourceMarked(runtime);
// session_compact — safety net, если before_compact не пришёл (mid-turn, гонка хуков)
ensureCompactionSourceMarked(runtime);
const shouldReinject =
effectiveEnabled &&
(pendingCompactionSource === "auto" || settings.reinjectOnManualCompaction);
state.lastCompactionSource = pendingCompactionSource;
pendingCompactionSource = null;
Fallback на session_compact: если session_before_compact не отработал, pendingCompactionSource остаётся null → без fallback lastCompactionSource: null, shouldReinject === false, status last compaction: none при реальном auto compact (B-003). Всё, что не помечено явным /compact в input, на session_compact считается auto.
Ручной RPC compact ({type: "compact"}) тоже помечать как manual если extension получает соответствующий сигнал (v2).
9. Архитектура файлов
pi-auto-reinjection/
├── SPEC.md # это ТЗ
├── README.md
├── package.json # pi package manifest (опционально npm)
├── src/
│ ├── index.ts # export default function(pi: ExtensionAPI)
│ ├── state.ts # load/save/merge state, appendEntry
│ ├── detect.ts # skill detection helpers
│ ├── expand.ts # expand skill → block (mirror Pi logic)
│ ├── reinject.ts # post-compaction reinject orchestration
│ ├── auto-compact.ts # detect @capyup/pi-auto-compact, delivery mode (§16)
│ ├── settings.ts # read/write skillReinject.* in settings.json
│ └── commands.ts # /skill-reinject handler
├── test/
│ ├── detect.test.ts
│ ├── kept-window.test.ts
│ └── expand.test.ts
└── .gitignore
9.1. Установка (целевая)
# dev
pi -e ~/Documents/repos/pi-auto-reinjection/src/index.ts
# production
cp -r src/index.ts ~/.pi/agent/extensions/skill-reinject.ts
# или через pi package / settings.extensions
См. extensions.md — Extension Locations: ~/.pi/agent/extensions/, .pi/extensions/.
10. Зависимости
{
"pi": {
"extensions": ["./src/index.ts"]
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "workspace:* или latest",
"typescript": "^5"
}
}
Импорты только из публичного API Pi (extensions.md — Available Imports).
Для expand skill body: readFileSync + strip YAML frontmatter (как Pi), без дублирования приватных internal imports если возможно; иначе — локальная копия логики с комментарием «mirror agent-session._expandSkillCommand».
11. Edge cases
| Case | Поведение |
|---|---|
| Skill удалён с диска | skip + ui.notify warning |
Skill disable-model-invocation: true |
re-inject всё равно (explicit inject) |
| Два skill с одним name (collision) | использовать первый из resourceLoader; warn |
| Compaction во время стрима | followUp delivery |
| Пустой tracked list | no-op |
/tree branch switch |
state из entries новой ветки; rescan |
session_shutdown |
flush pending appendEntry |
RPC / print mode (hasUI === false) |
команды работают; notify → no-op; reinject без UI feedback |
12. Тестирование
12.1. Unit
parseSkillBlock/ detect в user text- kept-window: skill in / not in kept messages
- expand: frontmatter strip, path resolution
- settings merge read/write
12.2. Manual E2E (standalone)
pi+ extension,/skill-reinject on/skill:some-skill→ длинная сессия → дождаться auto compaction (или уменьшитьkeepRecentTokens/reserveTokensв.pi/settings.json)- Проверить: после compaction в контексте снова есть
<skill name="some-skill"…> /skill-reinject off→ compaction → re-inject не происходит/skill-reinject global on→ новая сессия → re-inject безon
12.3. Manual E2E (с pi-auto-compact)
Предусловие: pi install npm:@capyup/pi-auto-compact (README).
- Оба extension загружены;
/skill-reinject on /skill-reinject→ status показываетdelivery: defer (pi-auto-compact detected)/skill:some-skill→ сессия до срабатывания pi-auto-compact (порог по умолчанию 90% context window)- После auto-compaction:
- pi-auto-compact отправляет follow-up («Auto-compact ran… Continue…»);
- агент продолжает работу без idle;
- в контексте turn'а есть skill-блок(и) до follow-up текста
- В логах/TUI нет ошибки
Agent is already processing/Failed to send queued message - Ручной
/compact→ pi-auto-compact не шлёт follow-up → re-inject только еслиreinjectOnManualCompaction: true, иначеpendingReinjectсбрасывается на следующем user prompt - Во время compaction пользователь печатает сообщение → pi-auto-compact молчит → re-inject через
before_agent_startна turn пользователя
13. Критерии приёмки (v1)
- Default off;
/skill-reinject onвключает re-inject в сессии /skill-reinject global onсохраняет в~/.pi/agent/settings.jsonи переживает restart- После auto compaction re-injectятся все tracked skills, отсутствующие в kept window
- После manual
/compactre-inject не происходит (при defaultreinjectOnManualCompaction: false) - Tracked skills:
/skill:name, skill-block в user msg,readнаSKILL.md - State переживает
/resumeтой же сессии - Footer status показывает on/off и count
- Нет duplicate skill blocks для skills уже в kept window (включая
skill-reinject:injectв kept slice, §6.4) - С pi-auto-compact: auto-detect, режим
defer, нет гонкиsendUserMessage, continue после compaction работает - С pi-auto-compact: ручной
/compactне ломает ни один extension - Два auto compaction подряд (в т.ч. второй mid-turn без user prompt): после каждого — tracked skills в контексте или явный skip (
skipped-keptвdebug);/skill-reinject→last compaction: auto, неnone(§8 fallback, §6.5.1 steer)
14. Будущие улучшения (v2+)
reinjectOnManualCompaction: trueкак осознанный opt-insession_before_compact: дописывать в custom summary список active skills- Опциональный
pi.eventsпротокол с pi-auto-compact (встраивать skill-блоки в follow-up текст — без PR в capyup не обязателен) - Pi package на npm (
keywords: ["pi-package"]) - Опция re-inject только «последнего активного» skill, а не всех
15. Риски
| Риск | Митигация |
|---|---|
| Re-inject раздувает контекст (N больших skills) | skillReinject.maxSkills (default unlimited; soft warn > 3) |
sendUserMessage запускает нежеланный turn |
defer по умолчанию при pi-auto-compact; иначе triggerTurn: false |
Гонка sendUserMessage с pi-auto-compact follow-up |
§16: не слать sendUserMessage в session_compact; idle → before_agent_start; mid-turn → sendMessage/steer (§6.5.1) |
| Нельзя отличить auto/manual без эвристики | input hook на /compact; pi-auto-compact manual /compact не в его onComplete |
| Двойной compaction (Pi default + pi-auto-compact) | документировать; опционально warn в status |
| Pi изменит формат skill block | version в state; тест на parseSkillBlock regex |
16. Совместимость с @capyup/pi-auto-compact
Типичная установка пользователя: pi install npm:@capyup/pi-auto-compact. Extension проактивно компактирует на turn_start / turn_end / emergency context и автоматически продолжает работу после auto-compaction.
16.1. Как работает pi-auto-compact (релевантное нам)
Источник: extensions/auto-compact.ts, README.
| Аспект | Поведение |
|---|---|
| Триггер compaction | ctx.compact({ customInstructions, onComplete, onError }) — не ручной /compact |
| Follow-up после auto-compact | onComplete → setImmediate(() => { if (ctx.isIdle()) pi.sendUserMessage(AUTO_COMPACT_FOLLOW_UP[phase]); }) |
Ручной /compact |
Не попадает в их onComplete → follow-up не отправляется |
| Тексты follow-up | "Auto-compact ran before this turn. Continue with the current task." и ещё 3 фазы (mid-turn, emergency, session-resume) |
| Гонки | Специально откладывают follow-up в setImmediate, чтобы не проиграть flush compactionQueuedMessages Pi |
| Keep budget | keepRecentPercent (default 15% context window), не keepRecentTokens Pi |
16.2. Конфликт без интеграции
Если skill-reinject на session_compact вызовет sendUserMessage синхронно или в том же setImmediate:
- Агент перестаёт быть idle → pi-auto-compact не шлёт follow-up → сессия замирает после compaction.
- Или оба шлют сообщения в одном tick →
"Agent is already processing"(комментарий в auto-compact.ts).
Вывод: при обнаружении pi-auto-compact re-inject обязан идти через режим defer, не через конкурирующий sendUserMessage в session_compact. Idle: before_agent_start; mid-turn (!isIdle): sendMessage с deliverAs: "steer" (§6.5.1) — тот же инвариант §16.5, без user message.
16.3. Целевой совместный flow
turn_start / turn_end / emergency
│
▼
pi-auto-compact: ctx.compact()
│
├── session_before_compact (наш hook: mark source=auto)
├── … Pi summarization …
├── session_compact (наш hook: pendingReinject := skills ∖ kept)
│ │
│ ├── isIdle → pending для before_agent_start
│ └── !isIdle → sendMessage steer (§6.5.1), без follow-up
└── onComplete → setImmediate → if isIdle: sendUserMessage("Auto-compact ran…")
│
▼
prompt() → before_agent_start (наш hook, idle-path)
│
├── inject: <skill>…</skill> × N ← re-inject (если не steer'нули)
└── user prompt: "Auto-compact ran…" ← kickoff pi-auto-compact
│
▼
agent продолжает с skills + summary + kept tail
16.4. Автоопределение pi-auto-compact
Без зависимости от npm-пакета и без правок в capyup:
function detectPiAutoCompact(pi: ExtensionAPI): boolean {
return pi.getCommands().some((c) => c.name === "auto-compact");
}
- Вызывать на
session_start(reason: "startup" | "resume" | "reload" | "switch"). - Кэшировать в
RuntimeFlags.autoCompactDetected. - При
false→ statusdelivery: defer (standalone)илиimmediateпоtriggerTurn.
Не полагаться на путь к файлу / package.json — только публичный API (getCommands).
Опция skillReinject.autoCompactIntegration:
| Значение | Поведение |
|---|---|
"auto" (default) |
defer если detectPiAutoCompact(), иначе по triggerTurn |
"defer" |
idle: before_agent_start; mid-turn (!isIdle): steer на session_compact (§6.5.1); никогда sendUserMessage в session_compact |
"immediate" |
всегда sendUserMessage (для отладки; с pi-auto-compact — риск §16.2) |
"off" |
игнорировать detect; только triggerTurn |
Команда /skill-reinject integration auto|defer|immediate|off — session override для autoCompactIntegration (персистить в skill-reinject:config entry).
16.5. Что мы не ломаем в pi-auto-compact
| Инвариант | Как обеспечиваем |
|---|---|
| Follow-up только когда idle | Не вызываем sendUserMessage в session_compact / onComplete tick |
| Follow-up только для своего auto-compact | Не трогаем ctx.compact() / onComplete |
Ручной /compact без follow-up |
Наш pendingReinject на manual: либо ждём user prompt (defer), либо skip (default) |
Emergency context truncation |
session_compact всё равно приходит после ctx.compact() — тот же defer |
16.6. Что pi-auto-compact не ломает в нас
| Сценарий | Результат |
|---|---|
| Auto-compact + follow-up (idle) | Следующий before_agent_start — наш inject; skills в контексте |
Auto-compact mid-turn (!isIdle, нет follow-up) |
Steer на session_compact (§6.5.1); skills до следующего LLM-вызова в том же turn |
| User печатает во время compaction | pi-auto-compact молчит; user prompt → наш inject на его turn (before_agent_start) |
pi-auto-compact keep-bookends / summarize-all |
Kept window определяем по compactionEntry.firstKeptEntryId в session branch (§6.4), не по их процентам |
| Два compaction подряд | Каждый session_compact пересчитывает pendingReinject; source fallback §8; дедуп по kept window включая skill-reinject:inject (§6.4) |
| Turn-boundary compact после steer | before_agent_start не дублирует inject, если steer уже доставил для compactionEntry.id этого compaction |
16.7. Coexistence с Pi default auto-compaction
Оба механизма могут сработать в одной сессии (Pi: после agent_end; pi-auto-compact: до turn). Рекомендация в README:
- при использовании pi-auto-compact рассмотреть
"compaction.enabled": falseв settings.json или оставить оба — skill-reinject отработает после каждогоsession_compact.
Extension не отключает чужой compaction; максимум — ui.notify hint при первом detect обоих.
16.8. Будущий опциональный протокол (v2, не блокирует v1)
Через pi.events:
// skill-reinject emits (optional, v2):
pi.events.emit("skill-reinject:pending", { skills: ["foo", "bar"] });
// pi-auto-compact could listen and append to follow-up — requires PR upstream
v1 не требует изменений в pi-auto-compact.
16.9. Константы для тестов (follow-up фразы pi-auto-compact)
Скопировать в auto-compact.ts как PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES для документирования/тестов, не для матчинга в runtime v1:
"Auto-compact ran before this turn.""Auto-compact ran mid-turn.""Emergency auto-compact ran.""Auto-compact ran on session resume."
Runtime v1 матчит follow-up не нужен — достаточно pendingReinject + любой следующий before_agent_start.