Pi için yapılandırma, özelleştirme, platform kurulumu ve API referansları.

Oturum Dosyası Formatı

Oturumlar JSONL (JSON Satır) dosyaları olarak saklanır. Her satır, type alanına sahip bir JSON nesnesidir. Oturum girişleri id/parentId alanları aracılığıyla bir ağaç yapısı oluşturarak yeni dosyalar oluşturmadan yerinde dallanmaya olanak tanır.

Dosya Konumu

~/.pi/agent/sessions/--<path>--/<timestamp>_<uuid>.jsonl

Burada <path>, /'nin - ile değiştirildiği çalışma dizini.

Oturumları Silme

Oturumlar, ~/.pi/agent/sessions/ altındaki .jsonl dosyaları silinerek kaldırılabilir.

Pi ayrıca oturumların /resume'den etkileşimli olarak silinmesini de destekler (bir oturum seçin ve Ctrl+D tuşuna basın, ardından onaylayın). Mevcut olduğunda pi, kalıcı olarak silinmeyi önlemek için trash CLI tuşlarını kullanır.

Oturum Sürümü

Oturumların başlığında bir sürüm alanı bulunur:

  • Sürüm 1: Doğrusal giriş sırası (eski, yükte otomatik olarak taşınan)
  • Sürüm 2: id/parentId bağlantılı ağaç yapısı
  • Sürüm 3: hookMessage rolü custom olarak yeniden adlandırıldı (uzantı birleştirme)

Mevcut oturumlar yüklendiğinde otomatik olarak geçerli sürüme (v3) taşınır.

Kaynak Dosyaları

GitHub (pi-mono)'deki kaynak:

Projenizdeki TypeScript tanımları için node_modules/@earendil-works/pi-coding-agent/dist/ ve node_modules/@earendil-works/pi-ai/dist/'yi inceleyin.

Mesaj Türleri

Oturum girişleri AgentMessage nesne içerir. Bu türleri anlamak, oturumları ayrıştırmak ve uzantıları yazmak için çok önemlidir.

İçerik Blokları

Mesajlar, yazılan içerik bloklarından oluşan diziler içerir:

interface TextContent {
  type: "text";
  text: string;
}

interface ImageContent {
  type: "image";
  data: string;      // base64 encoded
  mimeType: string;  // e.g., "image/jpeg", "image/png"
}

interface ThinkingContent {
  type: "thinking";
  thinking: string;
}

interface ToolCall {
  type: "toolCall";
  id: string;
  name: string;
  arguments: Record<string, any>;
}

Temel Mesaj Türleri (pi-ai'den)

interface UserMessage {
  role: "user";
  content: string | (TextContent | ImageContent)[];
  timestamp: number;  // Unix ms
}

interface AssistantMessage {
  role: "assistant";
  content: (TextContent | ThinkingContent | ToolCall)[];
  api: string;
  provider: string;
  model: string;
  usage: Usage;
  stopReason: "stop" | "length" | "toolUse" | "error" | "aborted";
  errorMessage?: string;
  timestamp: number;
}

interface ToolResultMessage {
  role: "toolResult";
  toolCallId: string;
  toolName: string;
  content: (TextContent | ImageContent)[];
  details?: any;      // Tool-specific metadata
  usage?: Usage;      // Nested LLM work performed by the tool
  isError: boolean;
  timestamp: number;
}

interface Usage {
  input: number;
  output: number;
  cacheRead: number;
  cacheWrite: number;
  totalTokens: number;
  cost: {
    input: number;
    output: number;
    cacheRead: number;
    cacheWrite: number;
    total: number;
  };
}

Dışa aktarılan pi-ai StopReason türü aynı zamanda "pending"'yi de içerir, ancak bu değer akış etkinliklerindeki kısmi mesajlar için ayrılmıştır. Terminal done/error mesajları, pi'nin asistan mesajını sürdürmesinden önce bunu bir tamamlanma nedeni ile değiştirir, bu nedenle "pending" JSONL oturumunda asla görünmemelidir.

Genişletilmiş Mesaj Türleri (pi-coding-agent'tan)

interface BashExecutionMessage {
  role: "bashExecution";
  command: string;
  output: string;
  exitCode: number | undefined;
  cancelled: boolean;
  truncated: boolean;
  fullOutputPath?: string;
  excludeFromContext?: boolean;  // true for !! prefix commands
  timestamp: number;
}

interface CustomMessage {
  role: "custom";
  customType: string;            // Extension identifier
  content: string | (TextContent | ImageContent)[];
  display: boolean;              // Show in TUI
  details?: any;                 // Extension-specific metadata
  timestamp: number;
}

interface BranchSummaryMessage {
  role: "branchSummary";
  summary: string;
  fromId: string;                // Entry we branched from
  timestamp: number;
}

interface CompactionSummaryMessage {
  role: "compactionSummary";
  summary: string;
  tokensBefore: number;
  timestamp: number;
}

AgentMessage Birliği

type AgentMessage =
  | UserMessage
  | AssistantMessage
  | ToolResultMessage
  | BashExecutionMessage
  | CustomMessage
  | BranchSummaryMessage
  | CompactionSummaryMessage;

Giriş Tabanı

Tüm girişler (SessionHeader hariç) SessionEntryBase'yi genişletir:

interface SessionEntryBase {
  type: string;
  id: string;           // 8-char hex ID
  parentId: string | null;  // Parent entry ID (null for first entry)
  timestamp: string;    // ISO timestamp
}

Giriş Türleri

Oturum Başlığı

Dosyanın ilk satırı. Yalnızca meta veriler, ağacın parçası değil (id/parentId yok).

{"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project"}

Ebeveynle yapılan oturumlar için (/fork, /clone veya newSession({ parentSession }) aracılığıyla oluşturulan):

{"type":"session","version":3,"id":"uuid","timestamp":"2024-12-03T14:00:00.000Z","cwd":"/path/to/project","parentSession":"/path/to/original/session.jsonl"}

OturumMesajGirişi

Görüşmede bir mesaj. message alanı bir AgentMessage içerir.

{"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello"}}
{"type":"message","id":"b2c3d4e5","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}}
{"type":"message","id":"c3d4e5f6","parentId":"b2c3d4e5","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false}}

Model Değişikliği Girişi

Kullanıcı oturumun ortasında modelleri değiştirdiğinde ortaya çıkar.

{"type":"model_change","id":"d4e5f6g7","parentId":"c3d4e5f6","timestamp":"2024-12-03T14:05:00.000Z","provider":"openai","modelId":"gpt-4o"}

Düşünme Seviyesi Değişimi Girişi

Kullanıcı düşünme/akıl yürütme düzeyini değiştirdiğinde yayılır.

{"type":"thinking_level_change","id":"e5f6g7h8","parentId":"d4e5f6g7","timestamp":"2024-12-03T14:06:00.000Z","thinkingLevel":"high"}

Sıkıştırma Girişi

Bağlam sıkıştırıldığında oluşturulur. Önceki mesajların özetini saklar.

{"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}

Daha yeni donanımla oluşturulan sıkıştırmalar, tutulan sıkıştırma sonrası bağlamı firstKeptEntryId yerine doğrudan girişe yerleştirir:

{"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","tokensBefore":50000,"retainedTail":[{"role":"user","content":"latest request"},{"role":"assistant","content":[{"type":"text","text":"latest reply"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}]}

İsteğe bağlı alanlar:

  • usage: Özetin oluşturulmasından LLM kullanımı; oturum belirtecine ve maliyet toplamlarına dahil edilir
  • retainedTail: Sıkıştırıldıktan sonra saklanan materyalize AgentMessage[]. Bu yalnızca eski oturumlarla geriye dönük uyumluluk için isteğe bağlıdır. Daha yeni donanımla oluşturulan sıkıştırmalar bunu içerir, böylece sıkıştırma girişinden önce eski girişleri yürümeden bu kontrol noktasından bağlamı yeniden oluşturabiliriz.
  • details: Uygulamaya özel veriler (ör. varsayılan için { readFiles: string[], modifiedFiles: string[] } veya uzantılar için özel veriler)
  • fromHook: true bir uzantı tarafından oluşturulmuşsa, false/undefined pi tarafından oluşturulmuşsa (eski alan adı)
  • firstKeptEntryId: eski giriş formatıyla uyumluluk için.

ŞubeÖzetGiriş

/tree yoluyla dallar değiştirilirken, sol dalın ortak ataya kadar LLM tarafından oluşturulan bir özetiyle oluşturulur. Terk edilmiş yoldan bağlamı yakalar.

{"type":"branch_summary","id":"g7h8i9j0","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:15:00.000Z","fromId":"f6g7h8i9","summary":"Branch explored approach A..."}

İsteğe bağlı alanlar:

  • usage: Özetin oluşturulmasından LLM kullanımı; oturum belirtecine ve maliyet toplamlarına dahil edilir
  • details: Varsayılan için dosya izleme verileri ({ readFiles: string[], modifiedFiles: string[] }) veya uzantılar için özel veriler
  • fromHook: true bir uzantı tarafından oluşturulmuşsa, false/undefined pi tarafından oluşturulmuşsa (eski alan adı)

Özel Giriş

Uzantı durumunun kalıcılığı. LLM bağlamına katılmaz.

{"type":"custom","id":"h8i9j0k1","parentId":"g7h8i9j0","timestamp":"2024-12-03T14:20:00.000Z","customType":"my-extension","data":{"count":42}}

Yeniden yükleme sırasında uzantınızın girişlerini tanımlamak için customType tuşunu kullanın. İnteraktif mod, özel girişleri pi.registerEntryRenderer(customType, renderer) aracılığıyla işleyebilir ancak yine de Yüksek Lisans bağlamına katılmazlar.

ÖzelMesajGirişi

LLM bağlamına katılan, uzantı enjekte edilen mesajlar.

{"type":"custom_message","id":"i9j0k1l2","parentId":"h8i9j0k1","timestamp":"2024-12-03T14:25:00.000Z","customType":"my-extension","content":"Injected context...","display":true}

Alanlar:

  • content: Dize veya (TextContent | ImageContent)[] (KullanıcıMesajı ile aynı)
  • display: true = TUI'de farklı stilde göster, false = gizli
  • details: İsteğe bağlı uzantıya özgü meta veriler (LLM'ye gönderilmez)

Etiket Girişi

Bir girişteki kullanıcı tanımlı yer imi/işaretçi.

{"type":"label","id":"j0k1l2m3","parentId":"i9j0k1l2","timestamp":"2024-12-03T14:30:00.000Z","targetId":"a1b2c3d4","label":"checkpoint-1"}

Bir etiketi temizlemek için labelundefined olarak ayarlayın.

Oturum Bilgisi Girişi

Oturum meta verileri (ör. kullanıcı tanımlı görünen ad). Uzantılarda /name, --name / -n veya pi.setSessionName() aracılığıyla ayarlayın.

{"type":"session_info","id":"k1l2m3n4","parentId":"j0k1l2m3","timestamp":"2024-12-03T14:35:00.000Z","name":"Refactor auth module"}

Oturum adı, ayarlandığında ilk mesaj yerine oturum seçicide (/resume) görüntülenir.

Ağaç Yapısı

Girişler bir ağaç oluşturur:

  • İlk girişte parentId: null var
  • Sonraki her giriş parentId aracılığıyla ebeveynine işaret eder
  • Dallanma daha önceki bir girdiden yeni alt öğeler yaratır
  • "Yaprak" ağaçtaki mevcut konumdur
[user msg] ─── [assistant] ─── [user msg] ─── [assistant] ─┬─ [user msg] ← current leaf
                                                            │
                                                            └─ [branch_summary] ─── [user msg] ← alternate branch

Bağlam Oluşturma

buildContextEntries() mevcut yapraktan köke doğru yürür ve sıkıştırmayı dikkate alarak aktif giriş listesini üretir:

  1. Yoldaki tüm girişleri toplar
  2. Yol üzerinde bir CompactionEntry varsa:
    • Önce sıkıştırma girişini içerir
    • retainedTail mevcutsa, bağımsız bir kontrol noktası görevi görür ve sıkıştırma sonrasındaki girişler dahil edilir
    • Aksi takdirde firstKeptEntryId'den sıkıştırmaya kadar olan girişler dahil edilir
    • Daha sonra sıkıştırmadan sonraki girişler dahil edilir
  3. Etkileşimli modun bunları oluşturabilmesi için seçilen aralıktaki mesaj dışı girişleri korur

buildSessionContext() Yüksek Lisans için mesaj listesini oluşturmak üzere bu giriş listesini temel alır:

  1. Geçerli modeli ve düşünme düzeyi ayarlarını tam yoldan çıkarır
  2. Seçilen girişleri mesajlara dönüştürür:
    • message -> saklanan AgentMessage
    • compaction -> compactionSummary artı retainedTail mevcut olduğunda
    • branch_summary -> branchSummary
    • custom_message -> CustomMessage
    • custom -> içerik mesajı yok

Bu, daha yeni sıkıştırmaların müstakil kontrol noktaları gibi davranmasını sağlar. retainedTail isteğe bağlıdır, bu nedenle yalnızca firstKeptEntryId depolayan eski oturumlar doğru şekilde yüklenmeye devam eder.

Ayrıştırma Örneği

import { readFileSync } from "fs";

const lines = readFileSync("session.jsonl", "utf8").trim().split("\n");

for (const line of lines) {
  const entry = JSON.parse(line);

  switch (entry.type) {
    case "session":
      console.log(`Session v${entry.version ?? 1}: ${entry.id}`);
      break;
    case "message":
      console.log(`[${entry.id}] ${entry.message.role}: ${JSON.stringify(entry.message.content)}`);
      break;
    case "compaction":
      console.log(`[${entry.id}] Compaction: ${entry.tokensBefore} tokens summarized`);
      break;
    case "branch_summary":
      console.log(`[${entry.id}] Branch from ${entry.fromId}`);
      break;
    case "custom":
      console.log(`[${entry.id}] Custom (${entry.customType}): ${JSON.stringify(entry.data)}`);
      break;
    case "custom_message":
      console.log(`[${entry.id}] Extension message (${entry.customType}): ${entry.content}`);
      break;
    case "label":
      console.log(`[${entry.id}] Label "${entry.label}" on ${entry.targetId}`);
      break;
    case "model_change":
      console.log(`[${entry.id}] Model: ${entry.provider}/${entry.modelId}`);
      break;
    case "thinking_level_change":
      console.log(`[${entry.id}] Thinking: ${entry.thinkingLevel}`);
      break;
  }
}

Oturum Yöneticisi API

Oturumlarla programlı olarak çalışmanın temel yöntemleri.

Statik Oluşturma Yöntemleri

  • SessionManager.create(cwd, sessionDir?) - Yeni oturum
  • SessionManager.open(path, sessionDir?) - Mevcut oturum dosyasını aç
  • SessionManager.continueRecent(cwd, sessionDir?) - En yeniye devam et veya yeni oluştur
  • SessionManager.inMemory(cwd?) - Dosya kalıcılığı yok
  • SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?) - Başka bir projeden oturumu çatallayın

Statik Listeleme Yöntemleri

  • SessionManager.list(cwd, sessionDir?, onProgress?) - Bir dizindeki oturumları listeleyin
  • SessionManager.listAll(onProgress?) - Tüm projelerdeki tüm oturumları listeleyin

Örnek Yöntemleri - Oturum Yönetimi

  • newSession(options?) - Yeni bir oturum başlatın (seçenekler: { parentSession?: string })
  • setSessionFile(path) - Farklı bir oturum dosyasına geçin
  • createBranchedSession(leafId) - Şubeyi yeni oturum dosyasına çıkart

Örnek Yöntemleri - Ekleme (tüm dönüş giriş kimlikleri)

  • appendMessage(message) - Mesaj ekle
  • appendThinkingLevelChange(level) - Düşünce değişikliğini kaydedin
  • appendModelChange(provider, modelId) - Model değişikliğini kaydedin
  • appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?) - Sıkıştırma ekleyin
  • appendCustomEntry(customType, data?) - Uzantı durumu (bağlamda değil)
  • appendSessionInfo(name) - Oturumun görünen adını ayarlayın
  • appendCustomMessageEntry(customType, content, display, details?) - Uzantı mesajı (bağlamda)
  • appendLabelChange(targetId, label) - Etiketi ayarla/temizle

Örnek Yöntemleri - Ağaçta Gezinme

  • getLeafId() - Mevcut konum
  • getLeafEntry() - Mevcut yaprak girişini alın
  • getEntry(id) - Kimliğe göre giriş alın
  • getBranch(fromId?) - Girişten köke doğru yürüyün
  • getTree() - Tam ağaç yapısını elde edin
  • getChildren(parentId) - Doğrudan çocukları alın
  • getLabel(id) - Giriş için etiketi alın
  • branch(entryId) - Yaprağı önceki girişe taşı
  • resetLeaf() - Yaprağı null değerine sıfırla (herhangi bir girişten önce)
  • branchWithSummary(entryId, summary, details?, fromHook?) - Bağlam özetini içeren dal

Örnek Yöntemleri - Bağlam ve Bilgi

  • buildContextEntries() - Sıkıştırma uygulanmış aktif şube girişlerini alın
  • buildSessionContext() - Yüksek Lisans için mesajları, düşünce seviyesini ve modeli alın
  • getEntries() - Tüm girişler (başlık hariç)
  • getHeader() - Oturum başlığı meta verileri
  • getSessionName() - En son session_info girişinden görünen adı alın
  • getCwd() - Çalışma dizini
  • getSessionDir() - Oturum depolama dizini
  • getSessionId() - Oturum UUID'si
  • getSessionFile() - Oturum dosyası yolu (bellek içi için tanımsız)
  • isPersisted() - Oturumun diske kaydedilip kaydedilmeyeceği