mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-19 18:15:41 +00:00
feat(providers): enable Codex prompt cache controls (#1310)
This commit is contained in:
1 parent
b8726ff4f4
commit
968745bd16
9 files changed
+176
-5
No files matched your search
@@ -2,6 +2,8 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
@@ -328,8 +330,12 @@ func (l *Loop) makeCallLLM(req *RunRequest, emitRun func(AgentEvent)) func(ctx c
|
||||
chatReq.Options[providers.OptPeerKind] = req.PeerKind
|
||||
chatReq.Options[providers.OptLocalKey] = req.LocalKey
|
||||
chatReq.Options[providers.OptWorkspace] = tools.ToolWorkspaceFromCtx(ctx)
|
||||
if tid := store.TenantIDFromContext(ctx); tid != uuid.Nil {
|
||||
chatReq.Options[providers.OptTenantID] = tid.String()
|
||||
tenantID := store.TenantIDFromContext(ctx)
|
||||
if tenantID != uuid.Nil {
|
||||
chatReq.Options[providers.OptTenantID] = tenantID.String()
|
||||
}
|
||||
if supportsPromptCacheParams(provider) {
|
||||
setDefaultPromptCacheOptions(chatReq.Options, tenantID, l.agentUUID, provider.Name(), req.SessionKey)
|
||||
}
|
||||
|
||||
// Reasoning decision: resolve effort level for thinking models (o3, DeepSeek-R1, Kimi).
|
||||
@@ -697,3 +703,34 @@ func (l *Loop) reserveLLMUsageFor(ctx context.Context, req *RunRequest, iteratio
|
||||
MaxOutputTokens: l.maxOutputTokensFromRequest(chatReq),
|
||||
})
|
||||
}
|
||||
|
||||
func supportsPromptCacheParams(provider providers.Provider) bool {
|
||||
switch provider.(type) {
|
||||
case *providers.CodexProvider, *providers.ChatGPTOAuthRouter:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func setDefaultPromptCacheOptions(opts map[string]any, tenantID, agentID uuid.UUID, providerName, sessionKey string) {
|
||||
if opts == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := opts[providers.OptPromptCacheKey]; !ok {
|
||||
opts[providers.OptPromptCacheKey] = defaultPromptCacheKey(tenantID, agentID, providerName, sessionKey)
|
||||
}
|
||||
if _, ok := opts[providers.OptPromptCacheRetention]; !ok {
|
||||
opts[providers.OptPromptCacheRetention] = "24h"
|
||||
}
|
||||
}
|
||||
|
||||
func defaultPromptCacheKey(tenantID, agentID uuid.UUID, providerName, sessionKey string) string {
|
||||
h := sha256.Sum256([]byte(strings.Join([]string{
|
||||
tenantID.String(),
|
||||
agentID.String(),
|
||||
providerName,
|
||||
sessionKey,
|
||||
}, "\x00")))
|
||||
return "goclaw/" + hex.EncodeToString(h[:16])
|
||||
}
|
||||
@@ -2,8 +2,11 @@ package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/nextlevelbuilder/goclaw/internal/pipeline"
|
||||
"github.com/nextlevelbuilder/goclaw/internal/providers"
|
||||
"github.com/nextlevelbuilder/goclaw/pkg/protocol"
|
||||
@@ -54,3 +57,48 @@ func TestMakeCallLLM_StreamsFinalThinkingWhenNoThinkingChunkArrives(t *testing.T
|
||||
t.Fatalf("thinking payload = %+v", thinking[0].Payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptCacheOptionsHelpers(t *testing.T) {
|
||||
tenantID := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
||||
agentID := uuid.MustParse("22222222-2222-2222-2222-222222222222")
|
||||
|
||||
key1 := defaultPromptCacheKey(tenantID, agentID, "codex", "session-a")
|
||||
key2 := defaultPromptCacheKey(tenantID, agentID, "codex", "session-a")
|
||||
key3 := defaultPromptCacheKey(tenantID, agentID, "codex", "session-b")
|
||||
if key1 != key2 {
|
||||
t.Fatalf("defaultPromptCacheKey not stable: %q != %q", key1, key2)
|
||||
}
|
||||
if key1 == key3 {
|
||||
t.Fatal("defaultPromptCacheKey should vary by session")
|
||||
}
|
||||
if !strings.HasPrefix(key1, "goclaw/") {
|
||||
t.Fatalf("defaultPromptCacheKey = %q, want goclaw/ prefix", key1)
|
||||
}
|
||||
|
||||
opts := map[string]any{}
|
||||
setDefaultPromptCacheOptions(opts, tenantID, agentID, "codex", "session-a")
|
||||
if opts[providers.OptPromptCacheKey] != key1 {
|
||||
t.Fatalf("prompt cache key = %v, want %s", opts[providers.OptPromptCacheKey], key1)
|
||||
}
|
||||
if opts[providers.OptPromptCacheRetention] != "24h" {
|
||||
t.Fatalf("prompt cache retention = %v, want 24h", opts[providers.OptPromptCacheRetention])
|
||||
}
|
||||
|
||||
opts = map[string]any{
|
||||
providers.OptPromptCacheKey: "custom-key",
|
||||
providers.OptPromptCacheRetention: "in_memory",
|
||||
}
|
||||
setDefaultPromptCacheOptions(opts, tenantID, agentID, "codex", "session-a")
|
||||
if opts[providers.OptPromptCacheKey] != "custom-key" || opts[providers.OptPromptCacheRetention] != "in_memory" {
|
||||
t.Fatalf("custom prompt cache options were overwritten: %+v", opts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportsPromptCacheParams(t *testing.T) {
|
||||
if !supportsPromptCacheParams(providers.NewCodexProvider("codex", nil, "", "")) {
|
||||
t.Fatal("CodexProvider should support prompt cache params")
|
||||
}
|
||||
if supportsPromptCacheParams(finalThinkingStreamProvider{}) {
|
||||
t.Fatal("generic provider should not support prompt cache params")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user