
Memo arka ucu, merkezi bir App orkestratörü etrafında 29 paket halinde yapılandırılmış monolitik bir Go uygulamasıdır. Yalnızca standart kütüphanenin http.ServeMux'u kullanılarak localhost:8090 üzerinden düz bir REST + SSE API'si sunar.
// main.go
func main() {
port := flag.Int("port", 8090, "HTTP server port")
flag.Parse()
app, _ := app.New()
app.Start()
webserver.ListenAndServe(app, *port)
}
app.New() tüm alt sistemleri başlatır. webserver.ListenAndServe yolları kaydeder ve HTTP sunucusunu başlatır.
internal/app/App yapısı arka ucun beynidir:
type App struct {
cfg *config.Config
store *memory.Store
provider *provider.Router
conductor *orchestra.Conductor
executor *agent.Executor
syncer *cloudsync.Drive
waclient *whatsapp.Client
calendar *calendar.Store
sessions *sessions.Manager
identity *identity.Manager
skills *skill.Manager
mood *mood.Engine
db *database.DB
// ...
}
App üzerindeki ana yöntemler:
| Yöntem | Dosya | Amaç |
|---|---|---|
Chat() |
internal/app/chat.go |
Tam sohbet işlem hattı — prompt oluşturma, hafıza erişimi, sağlayıcı yönlendirme, akış |
ChatStream() |
internal/app/llm.go |
Token düzeyinde SSE akış sarmalayıcısı |
RememberExchange() |
internal/app/memory.go |
Konuşma turunu RAG'de sakla |
SearchMemory() |
internal/app/memory.go |
RRF ile hibrit arama |
ExecuteAgent() |
internal/app/agent.go |
Araç çağırma işlem hattı |
RunOrchestra() |
internal/app/orchestra.go |
Çoklu-model paralel yürütme |
internal/webserver/ paketi, HTTP işleyicilerini App'ten ayırmak için bir köprü deseni kullanır:
// internal/webserver/bridge.go
type AppBridge interface {
Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error)
ChatStream(ctx context.Context, req ChatRequest, ch chan<- SSEEvent) error
// ... ~90 yöntem imzası
}
type FullBridge struct {
app *app.App
}
func (b *FullBridge) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
return b.app.Chat(ctx, req)
}
İşleyiciler yalnızca köprü arayüzünü bilir — asla somut App'i değil. Bu, işleyicileri sahte köprülerle test etmeyi ve HTTP koduna dokunmadan gelecekteki mimari değişiklikleri mümkün kılar.
internal/webserver/// internal/webserver/server.go
func ListenAndServe(app *app.App, port int) error {
mux := http.NewServeMux()
bridge := &FullBridge{app: app}
registerFlutterRoutes(mux, bridge)
return http.ListenAndServe(fmt.Sprintf(":%d", port), mux)
}
| Önek | Sayı | Amaç |
|---|---|---|
/api/chat |
3 | Mesaj gönder, yanıt akışı, durdur |
/api/memory/ |
8 | Ara, hatırla, unut, dışa aktar, içe aktar, analitik, hata ayıkla, ayarlar |
/api/providers/ |
10 | Her sağlayıcı türü için CRUD + test |
/api/models/ |
6 | Keşfet, indir, listele, sil, HuggingFace kataloğu |
/api/agent/ |
4 | Yürüt, izinler, işlem hattı durumu |
/api/orchestra/ |
5 | Çalıştır, yapılandır, roller, durum |
/api/calendar/ |
5 | CRUD etkinlikler, ayarlar, hatırlatıcılar |
/api/sync/ |
6 | Gönder, çek, durum, OAuth, ayarlar |
/api/whatsapp/ |
8 | Eşleştir, durum, mesajlar, gönder, kişiler, ara |
/api/skills/ |
6 | Listele, al, yükle, kaldır, etkinleştir |
/api/config/ |
4 | Al, ayarla, dışa aktar, içe aktar |
/api/mood/ |
3 | Puan, ayarlar, aç/kapat |
/api/proactive/ |
4 | Ayarlar, öneriler, geçmiş, tetikle |
/api/sessions/ |
4 | Listele, al, sil, yeniden adlandır |
/api/llama/ |
5 | Başlat, durdur, durum, GPU bilgisi, modeller |
/api/system/ |
3 | Sürüm, sağlık, kapat |
Sohbet ve ajan yanıtları Sunucu-Gönderilen Olaylar (SSE) kullanır:
// internal/webserver/handlers_flutter.go
func handleChatStream(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
flusher, _ := w.(http.Flusher)
eventCh := make(chan SSEEvent, 100)
go bridge.ChatStream(r.Context(), req, eventCh)
for event := range eventCh {
fmt.Fprintf(w, "data: %s\n\n", event.JSON())
flusher.Flush()
}
}
Olaylar şunları içerir: token, thinking, tool_executing, tool_result, memory_retrieved, error, done.
internal/provider/Sağlayıcı yönlendiricisi birden çok LLM arka ucunu yönetir:
// internal/provider/router.go
type Router struct {
providers map[string]Provider // sağlayıcı adına göre anahtarlanmış
order []string // öncelik sırası (yedekleme zinciri)
mu sync.RWMutex
}
type Provider interface {
Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error)
ChatStream(ctx context.Context, req ChatRequest, ch chan<- TokenEvent) error
Health(ctx context.Context) bool
}
| Sağlayıcı | Dosya | API Türü |
|---|---|---|
llama.cpp |
llama.go |
Yerel, OpenAI-uyumlu |
openai |
openai.go |
Bulut, OpenAI API |
gemini |
gemini.go |
Bulut, Gemini API |
claude |
claude.go |
Bulut, Anthropic API |
grok |
grok.go |
Bulut, xAI API |
groq |
groq.go |
Bulut, Groq API |
openrouter |
openrouter.go |
Bulut, OpenRouter API |
ollama |
ollama.go |
Yerel, Ollama API |
opencode-zen |
opencode_zen.go |
Bulut, OpenCode Zen API |
opencode-go |
opencode_go.go |
Bulut, OpenCode Go API |
func (r *Router) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
for _, name := range r.order {
provider := r.providers[name]
if !provider.Enabled() {
continue
}
resp, err := provider.Chat(ctx, req)
if err == nil {
return resp, nil
}
provider.RecordFailure()
// Sonraki sağlayıcıya geç
}
return nil, ErrAllProvidersFailed
}
3 ardışık başarısızlıktan sonra bir sağlayıcı otomatik devre dışı bırakılır. Bir arka plan sağlık kontrolü goroutine'i devre dışı sağlayıcıları yoklar ve düzeldiklerinde yeniden etkinleştirir.
internal/memory/// internal/memory/store.go
type Store struct {
db *sql.DB
embedModel string
mu sync.RWMutex
}
func (s *Store) Search(ctx context.Context, query string, topK int) ([]Memory, error)
func (s *Store) Store(ctx context.Context, exchange Exchange) error
func (s *Store) Forget(ctx context.Context, pattern string) (int, error)
func (s *Store) Export(ctx context.Context) ([]byte, error)
func (s *Store) Import(ctx context.Context, data []byte) error
storeMu (sync.RWMutex) eşzamanlı hafıza yeniden başlatmaya karşı koruma sağlar. Uygun kilidi tutmadan asla depoyu okumayın veya yazmayın.
internal/agent/// internal/agent/executor.go
type Executor struct {
tools map[string]Tool
permissions *PermissionPolicy
sandbox *Sandbox
pipeline *Pipeline
}
func (e *Executor) Execute(ctx context.Context, task string, events chan<- AgentEvent) (string, error)
filepath.EvalSymlinks ile sembolik bağlar çözülürrun_command 60sn zaman aşımıyla bash -c üzerinden çalışırinternal/orchestra/// internal/orchestra/conductor.go
type Conductor struct {
roles map[string]Role // 8 rol
chiefModel string
}
type Role struct {
Name string // planner, frontend, backend, ...
Provider string
Model string
SystemPrompt string
Enabled bool
}
Şef:
orchestra:role_started, orchestra:role_completed)internal/database/// internal/database/db.go
type DB struct {
Write chan func(*sql.DB) // Serileştirilmiş yazma kuyruğu
Read *sql.DB // Eşzamanlı okumalar
}
Tüm SQLite yazmaları, database is locked hatalarını önlemek için Write kanalından geçer. Okumalar Read tanıtıcısında eşzamanlı olarak gerçekleşebilir. Bu, gömme yazmalarının ve FTS indeks güncellemelerinin atomik olması gereken hafıza deposu için özellikle önemlidir.
Başlatma:
config.Load() → db.Open() → provider.Init() → memory.Init()
→ agent.Init() → cloudsync.Init() → whatsapp.Init()
→ calendar.Init() → mood.Init() → webserver.ListenAndServe()
Kapatma:
webserver.Shutdown() [yeni istekleri kabul etmeyi durdur]
→ whatsapp.Stop() → cloudsync.Stop() → calendar.Stop()
→ mood.Stop() → memory.Close() → db.Close()
Kapatmada önce web sunucusu durmalıdır. Alt sistemleri web sunucusundan önce durdurmak, uçuş halindeki HTTP isteklerinin nil/geçersiz kaynaklara erişmesine ve çökmesine neden olur.
http.ServeMuxApp'e referans vermezcontext.Context ilk parametre olarak — asla yapı alanlarında saklanmaz (yaşam döngüsü goroutine'leri hariç)sync.RWMutex — saparsanız nedenini belgeleyindatabase.DB.Write kanalını kullanınCGO_ENABLED=1