Files
cpa-plugin/patch/cli-proxy-api-codex-context-capability.patch
T

139 lines
4.7 KiB
Diff

diff --git a/internal/client/codex/models/experimental_context_test.go b/internal/client/codex/models/experimental_context_test.go
new file mode 100644
index 00000000..e41a1ec1
--- /dev/null
+++ b/internal/client/codex/models/experimental_context_test.go
@@ -0,0 +1,37 @@
+package models
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/router-for-me/CLIProxyAPI/v8/internal/registry"
+)
+
+func TestCodexExperimentalContextFollowsCanonicalAlias(t *testing.T) {
+ r := registry.GetGlobalRegistry()
+ const clientID = "experimental-context-alias-test"
+ r.RegisterClient(clientID, "codex", []*registry.ModelInfo{
+ {ID: "context-test-alias", MetadataModelID: "gpt-6-astra"},
+ {ID: "context-test-unrelated"},
+ })
+ t.Cleanup(func() { r.UnregisterClient(clientID) })
+ response := BuildResponseForClient([]map[string]any{
+ {"id": "gpt-6-astra"}, {"id": "context-test-alias"}, {"id": "context-test-unrelated"},
+ }, r.GetModelProviders, false, "0.155.0")
+ encoded, err := MarshalCompact(response)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var decoded codexClientModelsPayload
+ if err := json.Unmarshal(encoded, &decoded); err != nil || len(decoded.Models) != 3 {
+ t.Fatalf("serialized catalog = %s, err = %v", encoded, err)
+ }
+ for _, entry := range decoded.Models {
+ slug := stringModelValue(entry, "slug")
+ want := slug != "context-test-unrelated"
+ got, present := entry["supports_experimental_context"].(bool)
+ if got != want || (slug != "context-test-unrelated" && !present) {
+ t.Fatalf("%s experimental context = %v, want %v", slug, got, want)
+ }
+ }
+}
diff --git a/internal/registry/codex_client_models.go b/internal/registry/codex_client_models.go
index 370abf29..1fae27be 100644
--- a/internal/registry/codex_client_models.go
+++ b/internal/registry/codex_client_models.go
@@ -10,6 +10,8 @@ import (
"sync"
log "github.com/sirupsen/logrus"
+ "github.com/tidwall/gjson"
+ "github.com/tidwall/sjson"
)
//go:embed models/codex_client_models.json
@@ -59,6 +61,17 @@ func loadCodexClientModelsFromBytes(data []byte, source string) (bool, error) {
return false, fmt.Errorf("%s: %w", source, err)
}
+ // This patched host supports Astra experimental context, including after remote refresh.
+ for i, model := range gjson.GetBytes(data, "models").Array() {
+ if model.Get("slug").String() == "gpt-6-astra" {
+ updated, err := sjson.SetBytes(data, fmt.Sprintf("models.%d.supports_experimental_context", i), true)
+ if err != nil {
+ return false, fmt.Errorf("%s: supplement experimental context capability: %w", source, err)
+ }
+ data = updated
+ }
+ }
+
cloned := append([]byte(nil), data...)
codexClientCatalogStore.mu.Lock()
defer codexClientCatalogStore.mu.Unlock()
diff --git a/internal/registry/codex_experimental_context_test.go b/internal/registry/codex_experimental_context_test.go
new file mode 100644
index 00000000..c8d5e3ef
--- /dev/null
+++ b/internal/registry/codex_experimental_context_test.go
@@ -0,0 +1,58 @@
+package registry
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestExperimentalContextCatalogRefresh(t *testing.T) {
+ original, _ := GetCodexClientModelsSnapshot()
+ previousURLs := codexClientModelsURLs
+ t.Cleanup(func() {
+ codexClientModelsURLs = previousURLs
+ if _, err := loadCodexClientModelsFromBytes(original, "test cleanup"); err != nil {
+ t.Fatal(err)
+ }
+ })
+ for _, tc := range []struct {
+ name string
+ value any
+ want bool
+ }{
+ {"missing", nil, true},
+ {"explicit false", false, true},
+ {"explicit true", true, true},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ model := testCodexClientModel("gpt-6-astra", 2)
+ if tc.value != nil {
+ model["supports_experimental_context"] = tc.value
+ }
+ catalog := testCodexClientCatalog(t, testCodexClientModel("gpt-5.5", 1), model)
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, _ = w.Write(catalog)
+ }))
+ defer server.Close()
+ codexClientModelsURLs = []string{server.URL}
+ tryRefreshCodexClientModels(context.Background(), "test experimental refresh")
+ data, revision := GetCodexClientModelsSnapshot()
+ var payload codexClientModelsPayload
+ if err := json.Unmarshal(data, &payload); err != nil {
+ t.Fatal(err)
+ }
+ if got := payload.Models[1]["supports_experimental_context"]; got != tc.want {
+ t.Fatalf("experimental context = %v, want %v", got, tc.want)
+ }
+ if _, exists := payload.Models[0]["supports_experimental_context"]; exists {
+ t.Fatal("unrelated model gained experimental context")
+ }
+ tryRefreshCodexClientModels(context.Background(), "test repeated refresh")
+ if GetCodexClientModelsRevision() != revision {
+ t.Fatal("unchanged catalog advanced revision")
+ }
+ })
+ }
+}