Sıkıştırma ve Dal Özetleme
Yüksek Lisans'ların sınırlı bağlam pencereleri vardır. Konuşmalar çok uzadığında, Pi yeni çalışmaları korurken eski içeriği özetlemek için sıkıştırmayı kullanır. Bu sayfa hem otomatik sıkıştırmayı hem de branch summarization'yi kapsar.
Kaynak dosyalar (pi-mono):
packages/coding-agent/src/core/compaction/compaction.ts- Otomatik sıkıştırma mantığıpackages/coding-agent/src/core/compaction/branch-summarization.ts- Şube özetipackages/coding-agent/src/core/compaction/utils.ts- Paylaşılan yardımcı programlar (dosya izleme, serileştirme)packages/coding-agent/src/core/session-manager.ts- Giriş türleri (CompactionEntry,BranchSummaryEntry)packages/coding-agent/src/core/extensions/types.ts- Uzantı etkinlik türleri
Projenizdeki TypeScript tanımları için node_modules/@earendil-works/pi-coding-agent/dist/'yi inceleyin.
Genel Bakış
Pi'nin iki özetleme mekanizması vardır:
| Mekanizma | Tetiklemek | Amaç |
|---|---|---|
| Sıkıştırma | Bağlam eşiği aşıyor veya /compact |
Bağlamı boşaltmak için eski mesajları özetleyin |
| Şube özeti | /tree navigasyon |
Dalları değiştirirken bağlamı koruyun |
Her ikisi de aynı yapılandırılmış özet formatını kullanır ve dosya işlemlerini kümülatif olarak izler. Sıkıştırma ve dal özeti istekleri, yeni yönlendirme oturumu kimliklerini kullanır ve sağlayıcı tarafından desteklendiğinde, bu tek seferlik istemlerin yeniden kullanılma olasılığı düşük olduğundan bilgi istemi önbelleğine yazma işlemlerini devre dışı bırakır.
Sıkıştırma
Tetiklendiğinde
Otomatik sıkıştırma şu durumlarda tetiklenir:
contextTokens > contextWindow - reserveTokensVarsayılan olarak reserveTokens 16384 jetondur (~/.pi/agent/settings.json veya <project-dir>/.pi/settings.json olarak yapılandırılabilir). Bu, LLM'nin yanıtına yer bırakıyor.
İsteğe bağlı talimatların özete odaklandığı /compact [instructions] ile manuel olarak da tetikleyebilirsiniz.
Nasıl Çalışır?
- Kesme noktasını bul:
keepRecentTokens'ye (varsayılan 20k,~/.pi/agent/settings.jsonveya<project-dir>/.pi/settings.json'de yapılandırılabilir) ulaşılana kadar jeton tahminlerini toplayarak en yeni mesajdan geriye doğru yürüyün - Mesajları çıkar: Önceki tutulan sınırdan (veya oturum başlangıcından) kesme noktasına kadar olan mesajları toplayın
- Özet oluştur: Yapılandırılmış biçimde özetlemek için LLM'yi arayın ve önceki özeti mevcut olduğunda yinelenen bağlam olarak iletin
- Girişi ekle:
CompactionEntry'yi özet vefirstKeptEntryIdile kaydedin - Yeniden yükle:
firstKeptEntryIdtarihinden itibaren özet ve mesajlar kullanılarak oturum yeniden yüklenir
Before compaction:
entry: 0 1 2 3 4 5 6 7 8 9
┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┐
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
└────────┬───────┘ └──────────────┬──────────────┘
messagesToSummarize kept messages
↑
firstKeptEntryId (entry 4)
After compaction (new entry appended):
entry: 0 1 2 3 4 5 6 7 8 9 10
┌─────┬─────┬─────┬─────┬──────┬─────┬──── ─┬──────┬─────┬─────┬─────┐
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
└──────────┬──────┘ └──────────────────────┬───────────────────┘
not sent to LLM sent to LLM
↑
starts from firstKeptEntryId
What the LLM sees:
┌────────┬─────────┬─────┬─────┬──────┬──────┬─────┬──────┐
│ system │ summary │ usr │ ass │ tool │ tool │ ass │ tool │
└────────┴─────────┴─────┴─────┴──────┴──────┴─────┴──────┘
↑ ↑ └─────────────────┬────────────────┘
prompt from cmp messages from firstKeptEntryIdTekrarlanan sıkıştırmalarda özetlenen aralık, sıkıştırma girişinde değil, önceki sıkıştırmanın korunan sınırında (firstKeptEntryId) başlar ve tutulan giriş yolda bulunamazsa önceki sıkıştırmadan sonraki girişe geri döner. Bu, önceki sıkıştırmadan sağ çıkan mesajları bir sonraki özetleme geçişine de dahil ederek korur. Pi ayrıca yeni CompactionEntry'yi yazmadan önce yeniden oluşturulan oturum bağlamından tokensBefore'yi yeniden hesaplar, böylece simge sayısı değiştirilmekte olan gerçek sıkıştırma öncesi bağlamı yansıtır.
Bölünmüş Dönüşler
Bir "dönüş", bir kullanıcı mesajıyla başlar ve bir sonraki kullanıcı mesajına kadar tüm asistan yanıtlarını ve araç çağrılarını içerir. Normalde sıkıştırma dönüş sınırlarında kesilir.
Tek bir dönüş keepRecentTokens değerini aştığında, kesme noktası dönüşün ortasında bir asistan mesajına ulaşır. Bu bir "bölünmüş dönüş"tür:
Split turn (one huge turn exceeds budget):
entry: 0 1 2 3 4 5 6 7 8
┌─────┬─────┬─────┬──────┬─────┬──────┬──────┬─────┬──────┐
│ hdr │ usr │ ass │ tool │ ass │ tool │ tool │ ass │ tool │
└─────┴─────┴─────┴──────┴─────┴──────┴──────┴─────┴──────┘
↑ ↑
turnStartIndex = 1 firstKeptEntryId = 7
│ │
└──── turnPrefixMessages (1-6) ───────┘
└── kept (7-8)
isSplitTurn = true
messagesToSummarize = [] (no complete turns before)
turnPrefixMessages = [usr, ass, tool, ass, tool, tool]Bölünmüş dönüşler için Pi iki özet oluşturur ve bunları birleştirir:
- Geçmiş özeti: Önceki bağlam (varsa)
- Dönüş öneki özeti: Ayrık dönüşün ilk kısmı
Kesim Noktası Kuralları
Geçerli kesme noktaları şunlardır:
- Kullanıcı mesajları
- Asistan mesajları
- Bash Yürütme mesajları
- Özel mesajlar (custom_message, Branch_summary)
Hiçbir zaman takım sonuçlarında kesme yapmayın (takım çağrılarıyla kalmaları gerekir).
Sıkıştırma Giriş Yapısı
session-manager.ts'de tanımlanmış:
interface CompactionEntry<T = unknown> {
type: "compaction";
id: string;
parentId: string;
timestamp: number;
summary: string;
firstKeptEntryId: string;
tokensBefore: number;
usage?: Usage; // LLM usage that generated the summary
fromHook?: boolean; // true if provided by extension (legacy field name)
details?: T; // implementation-specific data
}
// Default compaction uses this for details (from compaction.ts):
interface CompactionDetails {
readFiles: string[];
modifiedFiles: string[];
}Extensions herhangi bir JSON serileştirilebilir veriyi details'de saklayabilir. Varsayılan sıkıştırma dosya işlemlerini izler ancak özel uzantı uygulamaları kendi yapılarını kullanabilir. Oluşturulan ve uzantı tarafından sağlanan özetler, mümkün olduğunda LLM'lerini usage saklar, böylece oturum toplamları özetleme çalışmasını içerir.
Uygulama için prepareCompaction() ve compact()'ye bakın. Doğrudan programlı özetleme için, generateSummary() özet metnini döndürür ve generateSummaryWithUsage(), { text, usage } değerini döndürür.
Şube Özetleme
Tetiklendiğinde
Farklı bir şubeye gitmek için /tree kullandığınızda, Pi bıraktığınız işi özetleme olanağı sunar. Bu, sol daldan yeni dalın içine bağlam enjekte eder.
Nasıl Çalışır?
- Ortak atayı bul: Eski ve yeni konumların paylaştığı en derin düğüm
- Girişleri toplayın: Eski yapraktan ortak ataya doğru yürüyün
- Bütçeyle hazırlanın: Belirteç bütçesine kadar olan mesajları dahil edin (önce en yenisi)
- Özet oluştur: Yapılandırılmış formatla LLM'yi arayın
- Girişi ekle: Gezinme noktasında
BranchSummaryEntrykaydet
Tree before navigation:
┌─ B ─ C ─ D (old leaf, being abandoned)
A ───┤
└─ E ─ F (target)
Common ancestor: A
Entries to summarize: B, C, D
After navigation with summary:
┌─ B ─ C ─ D
A ───┤
└─ E ─ F ─ [summary of B,C,D] (new leaf)Kümülatif Dosya Takibi
Hem sıkıştırma hem de branch summarization dosyaları kümülatif olarak izler. Bir özet oluştururken pi, dosya işlemlerini aşağıdakilerden çıkarır:
- Özetlenen mesajlardaki araç çağrıları
- Önceki sıkıştırma veya dallanma özeti
details(varsa)
Bu, dosya izlemenin birden çok sıkıştırmada veya iç içe geçmiş dal özetlerinde toplanarak okunan ve değiştirilen dosyaların tam geçmişini koruduğu anlamına gelir.
ŞubeÖzetGiriş Yapısı
session-manager.ts'de tanımlanmış:
interface BranchSummaryEntry<T = unknown> {
type: "branch_summary";
id: string;
parentId: string;
timestamp: number;
summary: string;
fromId: string; // Entry we navigated from
usage?: Usage; // LLM usage that generated the summary
fromHook?: boolean; // true if provided by extension (legacy field name)
details?: T; // implementation-specific data
}
// Default branch summarization uses this for details (from branch-summarization.ts):
interface BranchSummaryDetails {
readFiles: string[];
modifiedFiles: string[];
}Sıkıştırmayla aynı şekilde, uzantılar özel verileri details'de depolayabilir.
Uygulama için collectEntriesForBranchSummary(), prepareBranchEntries() ve generateBranchSummary()'ye bakın.
Özet Formatı
Hem sıkıştırma hem de branch summarization aynı yapılandırılmış formatı kullanır:
## Goal
[What the user is trying to accomplish]
## Constraints & Preferences
- [Requirements mentioned by user]
## Progress
### Done
- [x] [Completed tasks]
### In Progress
- [ ] [Current work]
### Blocked
- [Issues, if any]
## Key Decisions
- **[Decision]**: [Rationale]
## Next Steps
1. [What should happen next]
## Critical Context
- [Data needed to continue]
<read-files>
path/to/file1.ts
path/to/file2.ts
</read-files>
<modified-files>
path/to/changed.ts
</modified-files>Mesaj Serileştirme
Özetlemeden önce mesajlar serializeConversation() aracılığıyla metne serileştirilir:
[User]: What they said
[Assistant thinking]: Internal reasoning
[Assistant]: Response text
[Assistant tool calls]: read(path="foo.ts"); edit(path="bar.ts", ...)
[Tool result]: Output from toolBu, modelin bunu devam edecek bir konuşma olarak ele almasını engeller.
Araç sonuçları serileştirme sırasında 2000 karaktere kısaltılır. Bu sınırı aşan içerik, kaç karakterin kesildiğini gösteren bir işaretle değiştirilir. Araç sonuçları (özellikle read ve bash'den) genellikle bağlam boyutuna en büyük katkıyı sağladığından, bu, özetleme isteklerini makul belirteç bütçeleri dahilinde tutar.
Extensions aracılığıyla Özel Özetleme
Extensions hem sıkıştırmayı hem de branch summarization'yi engelleyebilir ve özelleştirebilir. Etkinlik türü tanımları için extensions/types.ts'e bakın.
session_before_compact
Otomatik sıkıştırmadan önce tetiklendi veya /compact. İptal edebilir veya özel özet sağlayabilir. Türler dosyasında SessionBeforeCompactEvent ve CompactionPreparation'ye bakın.
pi.on("session_before_compact", async (event, ctx) => {
const { preparation, branchEntries, customInstructions, reason, willRetry, signal } = event;
// preparation.messagesToSummarize - messages to summarize
// preparation.turnPrefixMessages - split turn prefix (if isSplitTurn)
// preparation.previousSummary - previous compaction summary
// preparation.fileOps - extracted file operations
// preparation.tokensBefore - context tokens before compaction
// preparation.firstKeptEntryId - where kept messages start
// preparation.settings - compaction settings
// branchEntries - all entries on current branch (for custom state)
// reason - "manual" (/compact), "threshold", or "overflow"
// willRetry - whether the aborted turn is retried after compaction (overflow recovery)
// signal - AbortSignal (pass to LLM calls)
// Cancel:
return { cancel: true };
// Custom summary:
return {
compaction: {
summary: "Your summary...",
firstKeptEntryId: preparation.firstKeptEntryId,
tokensBefore: preparation.tokensBefore,
// usage: summaryResponse.usage, // Optional; included in session totals
details: { /* custom data */ },
}
};
});Mesajları Metne Dönüştürme
Kendi modelinizle bir özet oluşturmak için serializeConversation kullanarak mesajları metne dönüştürün:
import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
pi.on("session_before_compact", async (event, ctx) => {
const { preparation } = event;
// Convert AgentMessage[] to Message[], then serialize to text
const conversationText = serializeConversation(
convertToLlm(preparation.messagesToSummarize)
);
// Returns:
// [User]: message text
// [Assistant thinking]: thinking content
// [Assistant]: response text
// [Assistant tool calls]: read(path="..."); bash(command="...")
// [Tool result]: output text
// Now send to your model for summarization
const { summary, usage } = await myModel.summarize(conversationText);
return {
compaction: {
summary,
firstKeptEntryId: preparation.firstKeptEntryId,
tokensBefore: preparation.tokensBefore,
usage,
}
};
});Farklı bir modelin kullanıldığı tam bir örnek için custom-compaction.ts'e bakın.
session_before_tree
/tree navigasyondan önce tetiklendi. Kullanıcının özetlemeyi seçip seçmemesine bakılmaksızın her zaman tetiklenir. Gezinmeyi iptal edebilir veya özel özet sağlayabilir.
pi.on("session_before_tree", async (event, ctx) => {
const { preparation, signal } = event;
// preparation.targetId - where we're navigating to
// preparation.oldLeafId - current position (being abandoned)
// preparation.commonAncestorId - shared ancestor
// preparation.entriesToSummarize - entries that would be summarized
// preparation.userWantsSummary - whether user chose to summarize
// Cancel navigation entirely:
return { cancel: true };
// Provide custom summary (only used if userWantsSummary is true):
if (preparation.userWantsSummary) {
return {
summary: {
summary: "Your summary...",
// usage: summaryResponse.usage, // Optional; included in session totals
details: { /* custom data */ },
}
};
}
});Türler dosyasında SessionBeforeTreeEvent ve TreePreparation'ye bakın.
Ayarlar
Sıkıştırmayı ~/.pi/agent/settings.json veya <project-dir>/.pi/settings.json olarak yapılandırın:
{
"compaction": {
"enabled": true,
"reserveTokens": 16384,
"keepRecentTokens": 20000
}
}| Ayar | Varsayılan | Tanım |
|---|---|---|
enabled |
true |
Otomatik sıkıştırmayı etkinleştir |
reserveTokens |
16384 |
LLM yanıtı için rezerve edilecek jetonlar |
keepRecentTokens |
20000 |
Saklanacak en son belirteçler (özetlenmemiş) |
"enabled": false ile otomatik sıkıştırmayı devre dışı bırakın. /compact ile manuel olarak sıkıştırmaya devam edebilirsiniz.