@phi-code-admin/phi-code 0.77.1 → 0.77.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.77.2] - 2026-06-13
4
+
5
+ ### Changed
6
+
7
+ - **Unified, dynamic context-window resolution across all providers.** A single
8
+ `inferContextWindow(modelId, apiValue, providerId)` resolver now backs both the
9
+ generic live-models path and the OpenCode Go path, replacing the duplicated flat
10
+ `128k` fallbacks. When a provider API omits the window, it is inferred by model
11
+ family (Qwen/MiniMax 1M, Gemini 1-2M, Kimi 256k, GLM/MiMo 200k, GPT-5 400k,
12
+ Claude 200k) instead of collapsing to 128k.
13
+ - **Background model refresh now covers the OpenCode Go provider pair.** The
14
+ session-start refresh (and `/models refresh`) previously skipped
15
+ `opencode-go-anthropic` entirely and did not split Qwen/MiniMax onto the
16
+ Anthropic endpoint. It now refreshes both `opencode-go` and
17
+ `opencode-go-anthropic` from the shared catalog, so large-context models
18
+ (e.g. `qwen3.7-plus`) self-correct to their real window on the next session
19
+ without re-running `/setup`.
20
+
3
21
  ## [0.77.1] - 2026-06-13
4
22
 
5
23
  ### Fixed
@@ -16,6 +16,11 @@
16
16
  */
17
17
 
18
18
  import { ApiKeyStore, type ConfigWatcher, type ExtensionAPI, getApiKeyStore, getConfigWatcher } from "phi-code";
19
+ import {
20
+ buildOpenCodeGoAnthropicProviderConfig,
21
+ buildOpenCodeGoProviderConfig,
22
+ getOpenCodeGoModels,
23
+ } from "./providers/opencode-go.js";
19
24
  import { fetchLiveModels, peekCache, resetLiveModelsCache, toPersistedModel } from "./providers/live-models.js";
20
25
 
21
26
  const PROVIDER_DISPLAY: Record<string, string> = {
@@ -42,6 +47,41 @@ interface RefreshOutcome {
42
47
  error?: string;
43
48
  }
44
49
 
50
+ /**
51
+ * Refresh the OpenCode Go provider pair from the shared catalog.
52
+ * "opencode-go" persists the OpenAI-compat models; "opencode-go-anthropic"
53
+ * persists the Qwen/MiniMax models served over the Anthropic endpoint. Both
54
+ * sides get family-inferred context windows via the config builders.
55
+ */
56
+ async function refreshOpenCodeGo(
57
+ store: ApiKeyStore,
58
+ watcher: ConfigWatcher,
59
+ providerId: string,
60
+ apiKey: string | undefined,
61
+ stored: ReturnType<ApiKeyStore["getProvider"]>,
62
+ ): Promise<RefreshOutcome> {
63
+ const { models, source } = await getOpenCodeGoModels({ apiKey, forceRefresh: true });
64
+ const keyForBuild = apiKey ?? stored?.apiKey ?? "local";
65
+ const config =
66
+ providerId === "opencode-go-anthropic"
67
+ ? buildOpenCodeGoAnthropicProviderConfig(keyForBuild, models)
68
+ : buildOpenCodeGoProviderConfig(keyForBuild, models);
69
+
70
+ if (config.models.length === 0) {
71
+ return { provider: providerId, source: source === "fallback" ? "fallback" : "skipped", count: 0 };
72
+ }
73
+
74
+ watcher.muteForWrite("models_json_changed");
75
+ store.setKey(providerId, stored?.apiKey ?? apiKey ?? "local", {
76
+ baseUrl: stored?.baseUrl ?? config.baseUrl,
77
+ api: stored?.api ?? config.api,
78
+ models: config.models,
79
+ });
80
+
81
+ const outcomeSource = source === "live" ? "live" : source === "cache" ? "cache" : "fallback";
82
+ return { provider: providerId, source: outcomeSource, count: config.models.length };
83
+ }
84
+
45
85
  async function refreshOne(
46
86
  store: ApiKeyStore,
47
87
  watcher: ConfigWatcher,
@@ -52,6 +92,12 @@ async function refreshOne(
52
92
  ? stored.apiKey
53
93
  : undefined;
54
94
 
95
+ // OpenCode Go is a provider pair the generic fetchLiveModels path can't express
96
+ // (and never handled the Anthropic side), so refresh it from the shared catalog.
97
+ if (providerId === "opencode-go" || providerId === "opencode-go-anthropic") {
98
+ return await refreshOpenCodeGo(store, watcher, providerId, apiKey, stored);
99
+ }
100
+
55
101
  resetLiveModelsCache(providerId);
56
102
  const result = await fetchLiveModels(providerId, {
57
103
  apiKey,
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared context-window resolver for all phi providers.
3
+ *
4
+ * Provider `/models` endpoints are inconsistent: some report the context window
5
+ * (under `context_length`, `context_window`, `inputTokenLimit`, ...), many omit
6
+ * it entirely (OpenCode Go for newer Qwen models, Alibaba, ...). A flat default
7
+ * badly under-reports large-context families and surfaces as a wrong "/128k" in
8
+ * the footer. This resolver layers the sources:
9
+ * 1. the value reported by the provider API (if present and positive);
10
+ * 2. a curated per-family heuristic (keeps large-context models correct);
11
+ * 3. a generic default.
12
+ *
13
+ * Family values mirror the bundled static specs (OPENCODE_GO_FALLBACK_MODELS,
14
+ * default-models.json, live-models static specs).
15
+ */
16
+
17
+ const DEFAULT_CONTEXT_WINDOW = 128_000;
18
+
19
+ export function inferContextWindow(modelId: string, apiValue?: number, providerId?: string): number {
20
+ if (typeof apiValue === "number" && apiValue > 0) return apiValue;
21
+
22
+ const id = (modelId ?? "").toLowerCase();
23
+ if (id.includes("qwen") || id.includes("minimax")) return 1_000_000;
24
+ if (id.includes("gemini")) return id.includes("flash") ? 1_000_000 : 2_000_000;
25
+ if (id.includes("kimi")) return 256_000;
26
+ if (id.includes("glm") || id.includes("mimo")) return 200_000;
27
+ if (id.includes("gpt-5")) return 400_000;
28
+ if (id.includes("claude")) return 200_000;
29
+
30
+ // Provider-level hint when the model id is opaque.
31
+ const provider = (providerId ?? "").toLowerCase();
32
+ if (provider.includes("google") || provider.includes("gemini")) return 2_000_000;
33
+
34
+ return DEFAULT_CONTEXT_WINDOW;
35
+ }
@@ -25,6 +25,7 @@ import {
25
25
  pingOpenCodeGo,
26
26
  } from "./opencode-go.js";
27
27
  import { ALIBABA_MODELS, ALIBABA_PROVIDERS, pingAlibaba } from "./alibaba.js";
28
+ import { inferContextWindow } from "./context-window.js";
28
29
 
29
30
  export const LAST_VERIFIED = "2026-05-15";
30
31
 
@@ -462,7 +463,9 @@ export function toPersistedModel(m: LiveModel): {
462
463
  name: m.name ?? m.id,
463
464
  reasoning: m.reasoning ?? true,
464
465
  input: ["text"] as const,
465
- contextWindow: m.contextWindow ?? 128_000,
466
+ // Infer by model family when the provider API omits the window, instead of
467
+ // collapsing large-context models (Qwen/MiniMax/Gemini/...) to a flat 128k.
468
+ contextWindow: inferContextWindow(m.id, m.contextWindow),
466
469
  maxTokens: m.maxTokens ?? 16_384,
467
470
  };
468
471
  }
@@ -18,6 +18,8 @@
18
18
  * Model IDs follow format: opencode-go/<model-id> (e.g., opencode-go/kimi-k2.6).
19
19
  */
20
20
 
21
+ import { inferContextWindow } from "./context-window.js";
22
+
21
23
  export const OPENCODE_GO_ENV_VAR = "OPENCODE_GO_API_KEY";
22
24
  export const OPENCODE_GO_AUTH_URL = "https://opencode.ai/auth";
23
25
  export const OPENCODE_GO_MODELS_URL = "https://opencode.ai/zen/go/v1/models";
@@ -211,17 +213,11 @@ export function isOpenCodeGoAnthropicModel(id: string): boolean {
211
213
 
212
214
  /**
213
215
  * Infer a model's context window by family when the OpenCode Go API does not
214
- * report one (it omits it for some newer models, e.g. qwen3.7-plus). A flat
215
- * 128k default badly under-reports the large-context Qwen/MiniMax models, which
216
- * surfaces as a wrong "/128k" in the footer. Values mirror OPENCODE_GO_FALLBACK_MODELS.
216
+ * report one (it omits it for some newer models, e.g. qwen3.7-plus). Delegates
217
+ * to the shared resolver so every provider applies the same family heuristics.
217
218
  */
218
219
  export function inferOpenCodeGoContextWindow(id: string, provided?: number): number {
219
- if (typeof provided === "number" && provided > 0) return provided;
220
- const lower = id.toLowerCase();
221
- if (/^(qwen|minimax)/.test(lower)) return 1_000_000;
222
- if (/^kimi/.test(lower)) return 256_000;
223
- if (/^(glm|mimo)/.test(lower)) return 200_000;
224
- return 128_000;
220
+ return inferContextWindow(id, provided, "opencode-go");
225
221
  }
226
222
 
227
223
  function toPersistedOpenCodeGoModel(m: OpenCodeGoModel) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.77.1",
3
+ "version": "0.77.2",
4
4
  "description": "Coding agent CLI with persistent memory, sub-agents, intelligent routing, and orchestration",
5
5
  "type": "module",
6
6
  "piConfig": {