oh-pi 0.1.27 → 0.1.29

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-pi",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "One-click setup for pi-coding-agent. Like oh-my-zsh for pi.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,11 +42,29 @@ export interface AvailableModel {
42
42
  cost?: { input: number };
43
43
  }
44
44
 
45
+ /** Extract version score from model name: "claude-sonnet-4-0" → 4.0, "claude-3-5-haiku" → 3.5 */
46
+ function modelVersionScore(id: string): number {
47
+ // Match patterns like "4-0", "3-5", "4.5", "4o" etc.
48
+ const nums = id.match(/(\d+)[-.](\d+)/g);
49
+ if (!nums) {
50
+ const single = id.match(/(\d+)/g);
51
+ return single ? Math.max(...single.map(Number)) : 0;
52
+ }
53
+ // Take the highest version-like number pair
54
+ return Math.max(...nums.map(n => {
55
+ const [a, b] = n.split(/[-.]/).map(Number);
56
+ return a + (b ?? 0) / 10;
57
+ }));
58
+ }
59
+
45
60
  /**
46
61
  * 根据 caste 的 ModelTier 从可用模型中匹配最合适的模型
47
- * - fast(侦察蚁):关键词匹配轻量模型,优先同 provider
48
- * - balanced/powerful(工蚁/兵蚁):优先用当前会话模型,否则关键词匹配
49
- * - fallback:按 cost 排序选择
62
+ *
63
+ * 策略:从模型名提取版本号排序
64
+ * - fast(侦察蚁):选版本号最低的(轻量便宜)
65
+ * - powerful(工蚁):选版本号最高的(最强)
66
+ * - balanced(兵蚁):优先当前会话模型
67
+ * - 所有 tier 最终 fallback 到 currentModel
50
68
  */
51
69
  export function resolveModelForCaste(
52
70
  caste: AntCaste,
@@ -59,22 +77,19 @@ export function resolveModelForCaste(
59
77
  // 工蚁/兵蚁优先使用当前会话模型
60
78
  if (tier !== "fast" && currentModel) return currentModel;
61
79
 
62
- const keywords = MODEL_TIER_KEYWORDS[tier];
63
- // 优先匹配同 provider(从 currentModel 提取 provider 前缀)
64
- const provider = currentModel?.split("-")[0];
65
- const sameProvider = provider ? available.filter(m => m.id.toLowerCase().startsWith(provider)) : [];
66
- const pool = sameProvider.length > 0 ? sameProvider : available;
67
- const match = pool.find(m => keywords.some(k => m.id.toLowerCase().includes(k)));
68
- if (match) return match.id;
69
- // 扩大搜索范围
70
- if (sameProvider.length > 0) {
71
- const allMatch = available.find(m => keywords.some(k => m.id.toLowerCase().includes(k)));
72
- if (allMatch) return allMatch.id;
73
- }
74
- // Fallback:按 cost 排序
75
- const sorted = [...available].sort((a, b) => (a.cost?.input ?? 0) - (b.cost?.input ?? 0));
76
- if (tier === "fast") return sorted[0].id;
77
- return currentModel ?? sorted[sorted.length - 1].id;
80
+ // 按版本号排序
81
+ const scored = available.map(m => ({ id: m.id, score: modelVersionScore(m.id) }));
82
+ scored.sort((a, b) => a.score - b.score);
83
+
84
+ // 优先同 provider
85
+ const provider = currentModel?.split("/")[0] ?? currentModel?.split("-")[0];
86
+ const sameProvider = provider ? scored.filter(m => m.id.toLowerCase().includes(provider.toLowerCase())) : [];
87
+ const pool = sameProvider.length > 0 ? sameProvider : scored;
88
+
89
+ if (tier === "fast") return pool[pool.length - 1]?.id ?? currentModel;
90
+ if (tier === "powerful") return pool[pool.length - 1]?.id ?? currentModel;
91
+ // balanced: middle
92
+ return pool[Math.floor(pool.length / 2)]?.id ?? currentModel;
78
93
  }
79
94
 
80
95
  // ═══ 任务 (Food Source) ═══