Documentation
¶
Overview ¶
Package provider is the single LLM transport for Coremetry.
FAZ 1.1 (AI Assistant tasarımı, docs/plans/ai-assistant-design-2026-08-16.md §2.1 / §4-Faz1). Bugün 8 ayrı istek üreticisi var (copilot.go ×3, chat.go ×2, stream.go ×2, rag.go embed) ve her biri gövde şeklini, header'ları ve salvage zincirini KENDİ kopyasıyla taşıyor. Bunun bedeli ölçüldü: 1024 max_tokens paritesi ~1000 sürüm boyunca anthropic/github yollarında eksik kaldı (v0.9.1120). Tek transport o sınıfı kapatır.
FAZ 1.2 — kapsam ÜÇ sağlayıcının BUFFERED explain yolunun tamamı: DoOpenAI (JSON merdiveni dahil) + DoAnthropic + DoGitHub. Eski buffered üreticiler (explain*WithUsage) silindi; artık tek yazılış var. Stream (stream:true) ve tool-calling (chat.go) üreticileri bilinçli olarak DIŞARIDA — onlar sonraki dilimde taşınır; bu dilimde yalnız salvage/parse zincirini buradan çağırırlar, yani kurtarma mantığı da tek yerde.
Tasarım kuralı: provider DURUM TUTMAZ. Config bir SNAPSHOT olarak dışarıdan gelir; canlı yapılandırmanın (kilit, 30s refresh, TLS-skip, timeout, GitHub oturum jetonu, JSON-yetenek kararları) sahibi copilot.Service'tir ve öyle kalır. Merdiven de öyle: hangi basamağın DENENECEĞİ ve reddedilince ne yapılacağı Service'in kararı, gövdeye hangi response_format'ın basılacağı buranın işi.
Index ¶
- Constants
- func EmptyAnswerError(finishReason string) error
- func IsSalvagedThinking(s string) bool
- func MarkSalvagedThinking(s string) string
- func SalvageAnswer(content, reasoningContent, reasoning string) string
- func StripThinking(s string) string
- func ThinkingContent(s string) string
- type ChatMessage
- type ChatRequest
- type ChatResponse
- type Config
- type EmbedRequest
- type EmbedResponse
- type HTTPError
- type Request
- type Response
- func DoAnthropic(ctx context.Context, cfg Config, req Request) (Response, error)
- func DoGitHub(ctx context.Context, cfg Config, req Request) (Response, error)
- func DoOpenAI(ctx context.Context, cfg Config, req Request) (Response, error)
- func ParseAnthropic(respBody []byte) (Response, error)
- func ParseGitHubChat(respBody []byte) (Response, error)
- func ParseOpenAIChat(respBody []byte) (Response, error)
- func StreamAnthropic(ctx context.Context, cfg Config, req Request, onDelta func(string)) (Response, error)
- func StreamOpenAI(ctx context.Context, cfg Config, req Request, onDelta func(string)) (Response, error)
- type StreamFallbackError
- type StreamStage
- type StreamVerdict
- type ToolCall
- type ToolResult
- type ToolSpec
Constants ¶
const ( JSONPlain = 0 // response_format yok JSONObject = 1 // {"type":"json_object"} JSONSchema = 2 // {"type":"json_schema", …} )
JSON zorlama basamakları. DoOpenAI üçünü de basar; hangi basamağın deneneceğine ve reddedilince bir alta inileceğine copilot.Service karar verir (yetenek kararları uç-başına önbellekli, yani DURUM).
Basamak sınırın DIŞINDAysa ya da JSONSchema şemasız gelirse DoOpenAI açık hata döndürür: sessizce kısıtsız çağrıya düşmek, isteyen yüzeyin garantisini haber vermeden kaybettirirdi (fail-open-silently-unapplies sınıfı).
const SalvagedThinkingPrefix = "⚠ Bu metin modelin DÜŞÜNCE bloğundan kurtarıldı — " +
"nihai cevabı değil, çalışma notu. Çıkarımlar ve sayılar yarım olabilir.\n\n"
SalvagedThinkingPrefix — kurtarılmış düşünce bloğunun önüne konan uyarı. Dışa açık, çünkü tüketiciler (arayüz, denetim) bu metni TANIYABİLMELİ — dizgeyi kendi kopyalarında tekrar yazmasınlar.
Variables ¶
This section is empty.
Functions ¶
func EmptyAnswerError ¶
EmptyAnswerError — kurtarılacak hiçbir şey kalmadığında operatöre EYLEME DÖNÜK hata. finish_reason="length" ayrı bir teşhistir: bütçe düşünme fazında tükenmiştir, çözüm max_tokens'ı yükseltmek ya da düşünmeyi kapatmaktır.
Metinler copilot.go'daki ikizleriyle BİREBİR aynı tutuluyor — canary sırasında aynı yüzey iki yoldan da aynı cümleyi döndürmeli (parity testi bunu pinler).
func IsSalvagedThinking ¶ added in v0.10.37
IsSalvagedThinking — bu cevap düşünce bloğundan mı kurtarıldı.
Tüketiciler (arayüz rozeti, denetim sorgusu) buna bakıyor; dizge karşılaştırmasını kendi içlerinde yazmak, işaret değişince sessizce kopmak demekti.
func MarkSalvagedThinking ¶ added in v0.10.37
MarkSalvagedThinking — düşünce bloğunu işaretler.
Boş girdi boş kalır: işaretin tek başına gitmesi, olmayan bir cevabı varmış gibi göstermek olurdu.
func SalvageAnswer ¶
SalvageAnswer — cevabı modelin koyduğu yerden çeker, öncelik sırasıyla:
- son </think> sonrasındaki content (normal hâl),
- ayrılmış reasoning alanı (reasoning_content → reasoning),
- son çare: <think> bloğunun İÇİ.
Hiçbiri yoksa boş döner — çağıran EmptyAnswerError ile teşhis eder.
func StripThinking ¶
StripThinking, bazı yerel reasoning modellerinin content'e gömdüğü <think>…</think> bloğunu atar; SON </think> sonrasını döndürür. Blok yoksa yalnız trim eder.
func ThinkingContent ¶
ThinkingContent, İLK <think>…</think> bloğunun İÇİNİ döndürür — StripThinking hiçbir şey bırakmadığında son çare. Bazı modeller yalnız düşünce bloğu üretir ve o düşünce genelde açıklamanın kendisidir; kurtarmak, isteği başarısız saymaktan iyidir.
Types ¶
type ChatMessage ¶ added in v0.9.1125
type ChatMessage struct {
Role string // "user" | "assistant"
Text string `json:",omitempty"`
ToolCalls []ToolCall `json:",omitempty"`
ToolResults []ToolResult `json:",omitempty"`
}
ChatMessage, sağlayıcı-nötr tek konuşma turu. Bir kullanıcı turu Text (soru) VEYA ToolResults (fonksiyon çıktıları) taşır. Bir asistan turu Text (düz metin) ve/veya ToolCalls (çalıştırılmasını istediği fonksiyonlar) taşır.
type ChatRequest ¶ added in v0.9.1125
type ChatRequest struct {
Model string
MaxTokens int
// Temperature nil = gövdeye HİÇ koyma (bkz. Request.Temperature).
Temperature *float64
System string
Messages []ChatMessage
Tools []ToolSpec
}
ChatRequest — çok turlu, tool'lu tek bir model çağrısının girdileri. Request'in (tek-atış explain) tool'lu ikizi: aynı ayar alanları, System + tek User yerine Messages + Tools.
type ChatResponse ¶ added in v0.9.1125
ChatResponse — çözümlenmiş tur. ToolCalls doluysa çağıran onları çalıştırıp döngüye devam eder; boşsa Text nihai cevaptır.
func ChatAnthropicTools ¶ added in v0.9.1125
func ChatAnthropicTools(ctx context.Context, cfg Config, req ChatRequest) (ChatResponse, error)
ChatAnthropicTools tek bir tool'lu Messages turu yürütür.
func ChatGitHubTools ¶ added in v0.9.1125
func ChatGitHubTools(ctx context.Context, cfg Config, req ChatRequest) (ChatResponse, error)
ChatGitHubTools tek bir tool'lu Copilot turu yürütür. cfg.APIKey = ÇÖZÜLMÜŞ oturum jetonu (jeton takası DURUM taşır ve copilot.Service'te kalır — DoGitHub ile aynı kural).
func ChatOpenAITools ¶ added in v0.9.1125
func ChatOpenAITools(ctx context.Context, cfg Config, req ChatRequest) (ChatResponse, error)
ChatOpenAITools tek bir tool'lu openai-compat turu yürütür.
type Config ¶
Config — çağrı anındaki yapılandırma SNAPSHOT'ı.
HTTPClient zorunlu: timeout (operatör-ayarlı, v0.9.1120) ve TLS-skip transport'u onun içinde yaşıyor. Nil'e sessizce http.DefaultClient koymak, 180s local-LLM timeout'unu ve kurumsal-CA muafiyetini haber vermeden düşürürdü.
type EmbedRequest ¶ added in v0.9.1126
type EmbedRequest struct {
Model string
// Inputs — sıra ANLAMLIDIR. Çağıran vektörleri girdi indeksiyle
// eşleştirir (rag chunk_idx'e yazar); yanıt `index` alanına göre
// yeniden sıralanır, geliş sırasına DEĞİL.
Inputs []string
}
EmbedRequest — bir /embeddings çağrısının tel-üstü girdileri.
Toplu-iş (batch) sınırı BURADA DEĞİL, çağırandadır: rag kendi embedBatchMax=64 döngüsünü korur, çünkü sınırın sebebi uç-başına istek boyu ve o karar yapılandırmanın sahibinin işi. Burada dilimleme yapmak, ai_calls'ta "bir satır = bir HTTP çağrısı" sözleşmesini de sessizce bozardı.
type EmbedResponse ¶ added in v0.9.1126
EmbedResponse — çözümlenmiş yanıt.
InputTokens `usage.prompt_tokens`tan gelir. OpenAI ve vLLM ikisi de embeddings yanıtında usage yollar; yollamayan uçlarda 0 kalır ve kaydedici satırı yine yazar (gecikme + statü tek başına değerli — Response'un usage sözleşmesiyle aynı duruş).
func DoEmbeddings ¶ added in v0.9.1126
func DoEmbeddings(ctx context.Context, cfg Config, req EmbedRequest) (EmbedResponse, error)
DoEmbeddings tek bir /embeddings çağrısı yapar ve vektörleri GİRDİ SIRASINDA döndürür.
Hata semantiği eski ikiziyle aynı: taşıma hatası "embedding isteği: %w", 200 dışı yanıt "embedding endpoint %d: <gövde>" — artık HTTPError tipiyle, yani statü metinden ayıklanmadan okunabiliyor.
func ParseEmbeddings ¶ added in v0.9.1126
func ParseEmbeddings(r io.Reader, n int) (EmbedResponse, error)
ParseEmbeddings, /embeddings yanıtını çözer ve vektörleri GİRDİ indeksine göre yerleştirir.
Kardeşlerinden farklı olarak []byte değil io.Reader alır ve okuma TAVANI YOKTUR — bilerek: 64 metinlik bir bge-m3 batch'i 64×1024 float32'yi JSON olarak ~4-5MB'ta taşır, yani chat yolunun 1MB'lık maxRespBytes tavanı burada yanıtın ORTASINDAN keserdi. Kesik gövde "decode" hatası olarak görünür ve teşhisi çok pahalıya patlardı.
type HTTPError ¶ added in v0.9.1124
type HTTPError struct {
// Provider — hata metnindeki önek. Sağlayıcı adının kendisi değil,
// eski kodun BASTIĞI etiket: "openai-compat", "anthropic",
// "github copilot".
Provider string
Status int
// Body — kırpılmış yanıt gövdesi (okuma tavanı maxRespBytes).
Body string
}
errors.go — taşımanın hata sözleşmesi.
İki tüketicisi var ve ikisi de METNE bakıyordu:
- copilot.isQuotaErr — mesajda " 429" / "quota" / "rate limit" arayıp kota devre-kesicisini kuruyor (v0.9.200). Yeni bir cümle kurmak kesiciyi sessizce silahsız bırakırdı.
- JSON merdiveni — "response_format'ı anlamadım" ailesini (400, 422, 501) statüden ayırt ediyor.
(1) metinle çalışmaya devam ediyor: string sözleşmesi eskiden beri pinli. (2) artık metinden statü ayıklamıyor — HTTPError tipli hata statüyü TAŞIYOR, çağıran errors.As ile okuyor. Bu, "gövde metninde üç haneli sayı ara" sınıfını tamamen kapatır.
type Request ¶
type Request struct {
Model string
MaxTokens int
// Temperature nil = gövdeye HİÇ koyma. copilot.Service bugün
// daima bir değer gönderiyor (tuneTemperature ok=true); nil hâli,
// bazı reasoning uçlarının temperature'ı reddettiği gelecekteki
// "hiç gönderme" durumu için ifade edilebilir tutuluyor.
Temperature *float64
System string
User string
// JSONLevel — JSONPlain | JSONObject | JSONSchema. Yalnız
// openai-compat yolunda uygulanır: anthropic ve github uçlarına
// response_format bugüne kadar hiç gönderilmedi ve bu dilim
// DAVRANIŞ TAŞIYOR, değiştirmiyor. O iki taşıyıcı JSONPlain
// dışındaki basamağı açık hatayla reddeder ki "uyguladım" sanılmasın.
JSONLevel int
// JSONSchemaName / JSONSchema — yalnız JSONLevel==JSONSchema'da
// okunur ve İKİSİ de zorunludur. Boş şemayla json_schema göndermek
// 400 alır ve o uç için GEREKSİZ bir yetenek kararı yazdırırdı
// (v0.9.527); Service şemasız isteği zaten bir alt basamağa indirir,
// buradaki denetim o sözleşmenin ikinci kilidi.
JSONSchemaName string
JSONSchema map[string]any
}
Request — bir LLM çağrısının tel-üstü girdileri.
Model burada da, Config'te de var: Config kimlik/uç bilgisidir (baseURL+key+varsayılan model), Request ise O çağrının modelidir. Boşsa Config.Model, o da boşsa sağlayıcı varsayılanı kullanılır.
type Response ¶
Response — çözümlenmiş yanıt. Token sayıları `usage` alanından gelir; bazı yerel uçlar (eski Ollama, vLLM) usage yollamaz ve 0 kalır — kaydedici satırı yine yazar (gecikme + statü değerli).
func DoAnthropic ¶ added in v0.9.1124
DoAnthropic tek bir buffered Messages çağrısı yapar.
max_tokens ve temperature Request'ten gelir. Bu, v0.9.1120'nin düzelttiği hatanın taşınmış hâli: bu yol ~1000 sürüm boyunca sabit 1024 ve HİÇ temperature göndermişti (openai-compat 4096 alırken). Değerlerin sahibi Service; buranın işi onları gövdeye basmak.
func DoGitHub ¶ added in v0.9.1124
DoGitHub tek bir buffered Copilot chat.completion çağrısı yapar. cfg.APIKey = ÇÖZÜLMÜŞ oturum jetonu (yukarıdaki (1)).
func DoOpenAI ¶
DoOpenAI tek bir buffered (stream'siz) chat.completion çağrısı yapar ve kurtarma zincirinden geçmiş metni döndürür.
Hata semantiği copilot.go'daki ikiziyle aynı tutulmuştur: taşıma hatası "openai-compat call: %w", ≥300 yanıtı "openai-compat %d: <gövde>" (HTTPError tipiyle, statü ayıklanabilir). Kota kesicisi (429 → 1h pencere) ve JSON merdiveni ÇAĞIRANDA kalır: transport döner, Service karar verir.
func ParseAnthropic ¶ added in v0.9.1124
ParseAnthropic, buffered bir Messages gövdesini çözer. Saf: ağ yok, durum yok. Streaming yolu da bunu çağırıyor — bir vekil stream:true bayrağını yutup tek-atış JSON döndürdüğünde, elde OLAN gövdeyi çözümlemek ikinci bir faturalı çağrıdan iyidir (v0.8.404).
content[] birden çok text bloğu taşıyabilir (Anthropic uzun yanıtı bölebiliyor); text OLMAYAN bloklar (tool_use, thinking) atlanır.
func ParseGitHubChat ¶ added in v0.9.1124
ParseGitHubChat, Copilot'un chat.completion gövdesini çözer. Kasıtlı olarak ParseOpenAIChat'ten ayrı — yukarıdaki (3).
func ParseOpenAIChat ¶
ParseOpenAIChat, buffered bir chat.completion gövdesini çözer ve kurtarma zincirini uygular. Saf: ağ yok, durum yok — tablo testli.
func StreamAnthropic ¶ added in v0.9.1125
func StreamAnthropic(ctx context.Context, cfg Config, req Request, onDelta func(string)) (Response, error)
StreamAnthropic tek bir stream:true Messages çağrısı yapar. Sözleşme StreamOpenAI ile aynı (bkz. yukarısı).
Uç sabittir: Config.BaseURL bu yolda OKUNMAZ — buffered ikizindeki (DoAnthropic) kararın aynısı.
func StreamOpenAI ¶ added in v0.9.1125
func StreamOpenAI(ctx context.Context, cfg Config, req Request, onDelta func(string)) (Response, error)
StreamOpenAI tek bir stream:true chat.completion çağrısı yapar ve içerik parçalarını onDelta ile yayınlar. onDelta nil olabilir.
Akış kurulamazsa *StreamFallbackError döner — geri düşme KARARI çağıranındır (bkz. dosya başı). Akış başladıktan SONRA kopan bağlantı geri düşüş DEĞİLDİR: parçalar istemciye ulaştı, hata düz döner.
type StreamFallbackError ¶ added in v0.9.1125
type StreamFallbackError struct {
Verdict StreamVerdict
Stage StreamStage
Provider string // "openai-compat" | "anthropic" — log/hata öneki
Status int // StageHead dışında 0
ContentType string
Body []byte
Err error // bağlanma / okuma hatası, varsa
}
StreamFallbackError — "akış olmadı". Service errors.As ile okur, Verdict + Stage'e bakıp kararı verir.
Body, taşımanın ZATEN okuduğu gövdedir: VerdictParseBuffered'da tam tek-atış cevabı (Service onu buffered çözümleyiciye verir — ikinci faturalı çağrı YOK), diğerlerinde log için kırpılmış parçadır.
func (*StreamFallbackError) Error ¶ added in v0.9.1125
func (e *StreamFallbackError) Error() string
func (*StreamFallbackError) Unwrap ¶ added in v0.9.1125
func (e *StreamFallbackError) Unwrap() error
type StreamStage ¶ added in v0.9.1125
type StreamStage int
StreamStage — geri düşüşün hangi aşamada olduğunu söyler. Service'in log satırı üçünü ayrı cümlelerle yazıyor ve operatör bu cümlelerle teşhis koyuyor (bağlanamadı mı, baş mı reddetti, akış boş mu geldi).
const ( // StageConnect — istek hiç kurulamadı (DNS/TCP/TLS/timeout). StageConnect StreamStage = iota // StageHead — yanıt başı geldi ve akış DEĞİL (statü/content-type). StageHead // StageEmptyStream — SSE başlıkları geldi ama gövde TEK bir olay // bile üretmeden bitti. Hâlâ ilk-bayt bölgesi: bir kez geri düş, // karar YAZMA. StageEmptyStream )
type StreamVerdict ¶ added in v0.9.1125
type StreamVerdict int
StreamVerdict — stream:true yoklamasının yanıt BAŞINA verilen karar. Yalnız "bu istek şekli kabul edilmiyor" diyen statüler kalıcı karar üretir; geçici olan her şey YALNIZ bu çağrı için geri düşer ve bir dahakine yeniden yoklanır.
const ( // VerdictStream — 200 + text/event-stream: akışı tüket. VerdictStream StreamVerdict = iota // VerdictParseBuffered — 200 + SSE-olmayan gövde: sunucu stream:true // bayrağını yuttu ve tek atışta cevapladı. Gövde ZATEN cevaptır — // ikinci (faturalı) çağrı yapmadan çözümlenmeli. VerdictParseBuffered // VerdictFallbackCache — bayrağın kesin reddi (bazı vLLM sürümleri // stream:true'ya 400 döner): buffered'a BİR kez düş + kararı // önbelleğe yaz. VerdictFallbackCache // VerdictFallbackOnce — geçici ya da akışa özgü olmayan hata (429 // kota, 5xx, auth): buffered'a BİR kez düş ama önbelleğe YAZMA. VerdictFallbackOnce )
func ClassifyStreamResponse ¶ added in v0.9.1125
func ClassifyStreamResponse(status int, contentType string) StreamVerdict
ClassifyStreamResponse, stream:true yoklamasının yanıt BAŞINI bir karara eşler. Saf + tablo testli.
type ToolCall ¶ added in v0.9.1125
type ToolCall struct {
ID string // sağlayıcı üretimi id, sonuçta geri yollanır
Name string // tool adı
Input json.RawMessage // argümanlar (JSON)
// Raw, openai-compat sağlayıcısının döndürdüğü TAM tool_call
// nesnesidir (v0.8.373, operatör-bildirimi). Gemini'nin uyumluluk
// ucu ek alanlar iliştiriyor (extra_content → thought_signature) ve
// tekrar oynatılan functionCall onları taşımıyorsa sonraki turu 400
// INVALID_ARGUMENT ile REDDEDİYOR — nesneyi yukarıdaki kırpılmış
// alanlardan yeniden kurmak bilinmeyen her şeyi sessizce düşürüyordu.
// Doluysa tekrar kodlayıcısı Raw'ı BİREBİR gönderir; ID/Name/Input
// yürütücünün çözümlenmiş görüşü olarak kalır. Anthropic yolunda ve
// eski mesajlarda nil.
Raw json.RawMessage `json:",omitempty"`
}
ToolCall, modelin istediği tek bir fonksiyon çağrısı.
type ToolResult ¶ added in v0.9.1125
type ToolResult struct {
CallID string
Name string
Content string // JSON'a çevrilmiş tool çıktısı (ya da hata metni)
IsError bool
}
ToolResult, bir ToolCall'ın yürütülmüş çıktısı; model okuyabilsin diye sonraki tura geri beslenir.