refactor: replace opencode/glm-4.7-free with opencode/big-pickle model
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -46,7 +46,7 @@ describe("Agent Config Integration", () => {
|
||||
const config = {
|
||||
sisyphus: { model: "anthropic/claude-opus-4-6" },
|
||||
oracle: { model: "openai/gpt-5.2" },
|
||||
librarian: { model: "opencode/glm-4.7-free" },
|
||||
librarian: { model: "opencode/big-pickle" },
|
||||
}
|
||||
|
||||
// when - migration is applied
|
||||
@@ -65,7 +65,7 @@ describe("Agent Config Integration", () => {
|
||||
Sisyphus: { model: "anthropic/claude-opus-4-6" },
|
||||
oracle: { model: "openai/gpt-5.2" },
|
||||
"Prometheus (Planner)": { model: "anthropic/claude-opus-4-6" },
|
||||
librarian: { model: "opencode/glm-4.7-free" },
|
||||
librarian: { model: "opencode/big-pickle" },
|
||||
}
|
||||
|
||||
// when - migration is applied
|
||||
|
||||
@@ -251,7 +251,7 @@ describe("fuzzyMatchModel", () => {
|
||||
it("should match github-copilot claude-opus-4-6 to claude-opus-4.6", () => {
|
||||
const available = new Set([
|
||||
"github-copilot/claude-opus-4.6",
|
||||
"opencode/glm-4.7-free",
|
||||
"opencode/big-pickle",
|
||||
])
|
||||
const result = fuzzyMatchModel("claude-opus-4-6", available, ["github-copilot"])
|
||||
expect(result).toBe("github-copilot/claude-opus-4.6")
|
||||
@@ -327,16 +327,16 @@ describe("fuzzyMatchModel", () => {
|
||||
expect(result).toBe("anthropic/claude-opus-4-6")
|
||||
})
|
||||
|
||||
// given available models with similar model IDs (e.g., glm-4.7 and glm-4.7-free)
|
||||
// when searching for the longer variant (glm-4.7-free)
|
||||
// given available models with similar model IDs (e.g., glm-4.7 and big-pickle)
|
||||
// when searching for the longer variant (big-pickle)
|
||||
// then return exact model ID match, not the shorter one
|
||||
it("should prefer exact model ID match over shorter substring match", () => {
|
||||
const available = new Set([
|
||||
"zai-coding-plan/glm-4.7",
|
||||
"zai-coding-plan/glm-4.7-free",
|
||||
"zai-coding-plan/big-pickle",
|
||||
])
|
||||
const result = fuzzyMatchModel("glm-4.7-free", available)
|
||||
expect(result).toBe("zai-coding-plan/glm-4.7-free")
|
||||
const result = fuzzyMatchModel("big-pickle", available)
|
||||
expect(result).toBe("zai-coding-plan/big-pickle")
|
||||
})
|
||||
|
||||
// given available models with similar model IDs
|
||||
@@ -345,7 +345,7 @@ describe("fuzzyMatchModel", () => {
|
||||
it("should still prefer shorter match when searching for shorter variant", () => {
|
||||
const available = new Set([
|
||||
"zai-coding-plan/glm-4.7",
|
||||
"zai-coding-plan/glm-4.7-free",
|
||||
"zai-coding-plan/big-pickle",
|
||||
])
|
||||
const result = fuzzyMatchModel("glm-4.7", available)
|
||||
expect(result).toBe("zai-coding-plan/glm-4.7")
|
||||
@@ -690,13 +690,13 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
it("should prefer provider-models cache over models.json", async () => {
|
||||
writeProviderModelsCache({
|
||||
models: {
|
||||
opencode: ["glm-4.7-free", "gpt-5-nano"],
|
||||
opencode: ["big-pickle", "gpt-5-nano"],
|
||||
anthropic: ["claude-opus-4-6"]
|
||||
},
|
||||
connected: ["opencode", "anthropic"]
|
||||
})
|
||||
writeModelsCache({
|
||||
opencode: { models: { "glm-4.7-free": {}, "gpt-5-nano": {}, "gpt-5.2": {} } },
|
||||
opencode: { models: { "big-pickle": {}, "gpt-5-nano": {}, "gpt-5.2": {} } },
|
||||
anthropic: { models: { "claude-opus-4-6": {}, "claude-sonnet-4-6": {} } }
|
||||
})
|
||||
|
||||
@@ -705,7 +705,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
})
|
||||
|
||||
expect(result.size).toBe(3)
|
||||
expect(result.has("opencode/glm-4.7-free")).toBe(true)
|
||||
expect(result.has("opencode/big-pickle")).toBe(true)
|
||||
expect(result.has("opencode/gpt-5-nano")).toBe(true)
|
||||
expect(result.has("anthropic/claude-opus-4-6")).toBe(true)
|
||||
expect(result.has("opencode/gpt-5.2")).toBe(false)
|
||||
@@ -738,7 +738,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
// then falls back to models.json (no whitelist filtering)
|
||||
it("should fallback to models.json when provider-models cache not found", async () => {
|
||||
writeModelsCache({
|
||||
opencode: { models: { "glm-4.7-free": {}, "gpt-5-nano": {}, "gpt-5.2": {} } },
|
||||
opencode: { models: { "big-pickle": {}, "gpt-5-nano": {}, "gpt-5.2": {} } },
|
||||
})
|
||||
|
||||
const result = await fetchAvailableModels(undefined, {
|
||||
@@ -746,7 +746,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
})
|
||||
|
||||
expect(result.size).toBe(3)
|
||||
expect(result.has("opencode/glm-4.7-free")).toBe(true)
|
||||
expect(result.has("opencode/big-pickle")).toBe(true)
|
||||
expect(result.has("opencode/gpt-5-nano")).toBe(true)
|
||||
expect(result.has("opencode/gpt-5.2")).toBe(true)
|
||||
})
|
||||
@@ -757,7 +757,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
it("should filter by connectedProviders even with provider-models cache", async () => {
|
||||
writeProviderModelsCache({
|
||||
models: {
|
||||
opencode: ["glm-4.7-free"],
|
||||
opencode: ["big-pickle"],
|
||||
anthropic: ["claude-opus-4-6"],
|
||||
google: ["gemini-3-pro"]
|
||||
},
|
||||
@@ -769,7 +769,7 @@ describe("fetchAvailableModels with provider-models cache (whitelist-filtered)",
|
||||
})
|
||||
|
||||
expect(result.size).toBe(1)
|
||||
expect(result.has("opencode/glm-4.7-free")).toBe(true)
|
||||
expect(result.has("opencode/big-pickle")).toBe(true)
|
||||
expect(result.has("anthropic/claude-opus-4-6")).toBe(false)
|
||||
expect(result.has("google/gemini-3-pro")).toBe(false)
|
||||
})
|
||||
|
||||
@@ -81,7 +81,7 @@ export function fuzzyMatchModel(
|
||||
}
|
||||
|
||||
// Priority 2: Exact model ID match (part after provider/)
|
||||
// This ensures "glm-4.7-free" matches "zai-coding-plan/glm-4.7-free" over "zai-coding-plan/glm-4.7"
|
||||
// This ensures "big-pickle" matches "zai-coding-plan/big-pickle" over "zai-coding-plan/glm-4.7"
|
||||
// Use filter + shortest to handle multi-provider cases (e.g., openai/gpt-5.2 + opencode/gpt-5.2)
|
||||
const exactModelIdMatches = matches.filter((model) => {
|
||||
const modelId = model.split("/").slice(1).join("/")
|
||||
|
||||
@@ -28,7 +28,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => {
|
||||
const sisyphus = AGENT_MODEL_REQUIREMENTS["sisyphus"]
|
||||
|
||||
// #when - accessing Sisyphus requirement
|
||||
// #then - fallbackChain has claude-opus-4-6 first, glm-4.7-free last
|
||||
// #then - fallbackChain has claude-opus-4-6 first, big-pickle last
|
||||
expect(sisyphus).toBeDefined()
|
||||
expect(sisyphus.fallbackChain).toBeArray()
|
||||
expect(sisyphus.fallbackChain).toHaveLength(5)
|
||||
@@ -41,7 +41,7 @@ describe("AGENT_MODEL_REQUIREMENTS", () => {
|
||||
|
||||
const last = sisyphus.fallbackChain[4]
|
||||
expect(last.providers[0]).toBe("opencode")
|
||||
expect(last.model).toBe("glm-4.7-free")
|
||||
expect(last.model).toBe("big-pickle")
|
||||
})
|
||||
|
||||
test("librarian has valid fallbackChain with glm-4.7 as primary", () => {
|
||||
@@ -404,7 +404,7 @@ describe("FallbackEntry type", () => {
|
||||
// given - a FallbackEntry without variant
|
||||
const entry: FallbackEntry = {
|
||||
providers: ["opencode", "anthropic"],
|
||||
model: "glm-4.7-free",
|
||||
model: "big-pickle",
|
||||
}
|
||||
|
||||
// when - accessing variant
|
||||
@@ -434,7 +434,7 @@ describe("ModelRequirement type", () => {
|
||||
test("ModelRequirement variant is optional", () => {
|
||||
// given - a ModelRequirement without top-level variant
|
||||
const requirement: ModelRequirement = {
|
||||
fallbackChain: [{ providers: ["opencode"], model: "glm-4.7-free" }],
|
||||
fallbackChain: [{ providers: ["opencode"], model: "big-pickle" }],
|
||||
}
|
||||
|
||||
// when - accessing variant
|
||||
|
||||
@@ -19,7 +19,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
|
||||
{ providers: ["kimi-for-coding"], model: "k2p5" },
|
||||
{ providers: ["opencode"], model: "kimi-k2.5-free" },
|
||||
{ providers: ["zai-coding-plan"], model: "glm-4.7" },
|
||||
{ providers: ["opencode"], model: "glm-4.7-free" },
|
||||
{ providers: ["opencode"], model: "big-pickle" },
|
||||
],
|
||||
requiresAnyModel: true,
|
||||
},
|
||||
@@ -39,7 +39,7 @@ export const AGENT_MODEL_REQUIREMENTS: Record<string, ModelRequirement> = {
|
||||
librarian: {
|
||||
fallbackChain: [
|
||||
{ providers: ["zai-coding-plan"], model: "glm-4.7" },
|
||||
{ providers: ["opencode"], model: "glm-4.7-free" },
|
||||
{ providers: ["opencode"], model: "big-pickle" },
|
||||
{ providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-6" },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -117,7 +117,7 @@ describe("resolveModelWithFallback", () => {
|
||||
test("returns uiSelectedModel with override source when provided", () => {
|
||||
// given
|
||||
const input: ExtendedModelResolutionInput = {
|
||||
uiSelectedModel: "opencode/glm-4.7-free",
|
||||
uiSelectedModel: "opencode/big-pickle",
|
||||
userModel: "anthropic/claude-opus-4-6",
|
||||
fallbackChain: [
|
||||
{ providers: ["anthropic", "github-copilot"], model: "claude-opus-4-6" },
|
||||
@@ -130,15 +130,15 @@ describe("resolveModelWithFallback", () => {
|
||||
const result = resolveModelWithFallback(input)
|
||||
|
||||
// then
|
||||
expect(result!.model).toBe("opencode/glm-4.7-free")
|
||||
expect(result!.model).toBe("opencode/big-pickle")
|
||||
expect(result!.source).toBe("override")
|
||||
expect(logSpy).toHaveBeenCalledWith("Model resolved via UI selection", { model: "opencode/glm-4.7-free" })
|
||||
expect(logSpy).toHaveBeenCalledWith("Model resolved via UI selection", { model: "opencode/big-pickle" })
|
||||
})
|
||||
|
||||
test("UI selection takes priority over config override", () => {
|
||||
// given
|
||||
const input: ExtendedModelResolutionInput = {
|
||||
uiSelectedModel: "opencode/glm-4.7-free",
|
||||
uiSelectedModel: "opencode/big-pickle",
|
||||
userModel: "anthropic/claude-opus-4-6",
|
||||
availableModels: new Set(["anthropic/claude-opus-4-6"]),
|
||||
systemDefaultModel: "google/gemini-3-pro",
|
||||
@@ -148,7 +148,7 @@ describe("resolveModelWithFallback", () => {
|
||||
const result = resolveModelWithFallback(input)
|
||||
|
||||
// then
|
||||
expect(result!.model).toBe("opencode/glm-4.7-free")
|
||||
expect(result!.model).toBe("opencode/big-pickle")
|
||||
expect(result!.source).toBe("override")
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user