w-dispatch-ai 1.0.21 → 1.0.22

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.
Files changed (49) hide show
  1. package/README.md +15 -3
  2. package/dist/w-dispatch-ai.umd.js +2 -2
  3. package/dist/w-dispatch-ai.umd.js.map +1 -1
  4. package/docs/WDispatchAi.mjs.html +5 -3
  5. package/docs/adapters.mjs.html +5 -3
  6. package/docs/budgetFor.mjs.html +2 -2
  7. package/docs/buildValidator.mjs.html +166 -0
  8. package/docs/castPintOr.mjs.html +2 -2
  9. package/docs/dfTimeoutMs.mjs.html +2 -2
  10. package/docs/dispatchAi.mjs.html +2 -2
  11. package/docs/dispatchAiFallback.mjs.html +2 -2
  12. package/docs/dispatchAiWkf.mjs.html +2 -2
  13. package/docs/dispatchAntigravity.mjs.html +2 -2
  14. package/docs/dispatchApiOpenaiCompat.mjs.html +4 -68
  15. package/docs/dispatchApiOpenaiResponses.mjs.html +498 -0
  16. package/docs/dispatchClaude.mjs.html +2 -2
  17. package/docs/dispatchCodex.mjs.html +2 -2
  18. package/docs/dispatchOpencode.mjs.html +2 -2
  19. package/docs/getCliArgs.mjs.html +2 -2
  20. package/docs/getErrorResult.mjs.html +2 -2
  21. package/docs/getErrorType.mjs.html +5 -3
  22. package/docs/global.html +2277 -1159
  23. package/docs/index.html +2 -2
  24. package/docs/readEnvFile.mjs.html +2 -2
  25. package/docs/resolveProviders.mjs.html +3 -3
  26. package/docs/wkf_callAiWithFallback.mjs.html +2 -2
  27. package/docs/wkf_createFileStore.mjs.html +2 -2
  28. package/docs/wkf_createUsageCounter.mjs.html +2 -2
  29. package/docs/wkf_extractJsonLoose.mjs.html +2 -2
  30. package/docs/wkf_noSideEffectPrefix.mjs.html +2 -2
  31. package/docs/wkf_runFanout.mjs.html +2 -2
  32. package/docs/wkf_runFanoutPipeline.mjs.html +2 -2
  33. package/docs/wkf_runRolePipeline.mjs.html +2 -2
  34. package/docs/wkf_salvageTruncatedArray.mjs.html +2 -2
  35. package/g.mjs +2 -2
  36. package/package.json +1 -1
  37. package/src/WDispatchAi.mjs +3 -1
  38. package/src/adapters.mjs +3 -1
  39. package/src/buildValidator.mjs +94 -0
  40. package/src/dispatchApiOpenaiCompat.mjs +2 -66
  41. package/src/dispatchApiOpenaiResponses.mjs +426 -0
  42. package/src/getErrorType.mjs +3 -1
  43. package/src/providers.mjs +303 -213
  44. package/src/resolveProviders.mjs +1 -1
  45. package/test/tools/fakeServerForApiTest.mjs +108 -3
  46. package/test/unit-WDispatchAi.test.mjs +10 -6
  47. package/test/unit-adapters.test.mjs +5 -3
  48. package/test/unit-dispatchAi.test.mjs +1 -1
  49. package/test/unit-dispatchApiOpenaiResponses.test.mjs +198 -0
package/src/providers.mjs CHANGED
@@ -1,213 +1,303 @@
1
- // providers.mjs — 預設providers定義檔(實測可用之供應商條目, 開發端可直接全用或自選)
2
- //
3
- // 【性質】純資料檔, 不讀環境變數。金鑰以envVar間接引用(機密不落設定檔),
4
- // 使用前須經resolveProviders展開(envVar → keys, 缺變數者自動停用並回報);
5
- // 展開後之陣列可直接餵dispatchAiFallback, table可直接餵dispatchAiWkf。
6
- //
7
- // 【id命名】依「路徑:模型」規則(詳dispatchAiFallback.mjs檔頭之id設計規則):
8
- // oc:=經opencode CLI(有工具、較慢) / agy:=antigravity CLI / claude:/codex:=訂閱登入態CLI
9
- // zen:/agnes:/poolside:=REST直呼(免CLI免登入、快, 純文字生成)
10
- // 同一模型之CLI版與REST版屬不同供應商(能力與額度池皆不同), 故各為一條。
11
- //
12
- // 【zen免費模型清單為「更新日快照」, 不保證即為當前狀態】zen:系收錄截至2026-08-21
13
- // 經GET https://opencode.ai/zen/v1/models 查得之「全部」免費模型(*-free), 不做好用篩選——
14
- // 新模型會上線、舊模型可能下架或限流, 且各模型能力/速度/輸出習慣差異極大
15
- // (各條目註解記錄已測特性), 由呼叫端自行評估選用; 要查當前清單, 以OPENCODE_KEYS
16
- // 打上述/models端點即可。暫時打不通的條目(限流/額度)依本套件哲學保留不移除:
17
- // 恢復的偵測就是下次再打一次, 代價僅一次快速失敗(fallback/cooldownMs即為此而生)。
18
- //
19
- // 【使用方式】
20
- // import providers from 'w-dispatch-ai/src/providers.mjs'
21
- // import resolveProviders from 'w-dispatch-ai/src/resolveProviders.mjs'
22
- // import readEnvFile from 'w-dispatch-ai/src/readEnvFile.mjs'
23
- // let env = readEnvFile('./.env') //OPENCODE_KEYS/AGNES_KEYS/POOLSIDE_KEYS, 逗號分隔多把; 不污染process.env
24
- // let { providers: ps, table, skipped } = resolveProviders(providers, { env }) //全取
25
- // let r2 = resolveProviders(providers, { env, pick: ['agnes:agnes-2.5-flash', 'claude:sonnet'] }) //自選, pick順序即遞補優先序
26
- //
27
- // 【timeout規劃】各條目刻意不帶timeoutMs, 由上層依任務型態統一給定、條目僅於特例覆寫:
28
- // 簡單任務(秒級~分鐘級): 沿用套件統一預設即可(全轉接器一律300000=5分鐘, 見dfTimeoutMs.mjs)。
29
- // 複雜任務(單一AI工作約15分鐘、fallback須能走到最末):
30
- // timeoutMs: 1200000 (20min=15min工作+33%餘裕, 單次嘗試上限)
31
- // minAttemptMs: 1200000 (剩餘預算不足完整視窗即不開工——開了也不可能完成, 純浪費)
32
- // budgetMs: 鏈長K×timeoutMs (逾時型失敗每組只燒一次timeout即跳組, 故K×20min
33
- // 保證能走到最末; 例K=4 → 4800000=80min。無外部排程時限則可null=不限)
34
- // agy之printTimeout由timeoutMs自動推導(−30s), 無須另設。
35
- // 工作流層總時長: RolePipeline為各階段序列相加(M階段≈M×名額預算);
36
- // Fanout各名額並行(≈單一名額預算+整合名額預算), 外部排程上限須據此預留。
37
- // 外部調整四層(細者覆蓋粗者): dispatchAiWkf之defaults(全域) → 各工作流callOpt
38
- // → 各階段/名額規格 → 各provider條目。
39
-
40
-
41
- let providers = [
42
-
43
- //cli
44
- {
45
- id: 'oc:opencode/deepseek-v4-flash-free',
46
- model: 'opencode/deepseek-v4-flash-free',
47
- kind: 'opencode',
48
- envVar: 'OPENCODE_KEYS',
49
- provider: 'opencode',
50
- config: {
51
- permission: { edit: 'deny', write: 'deny', bash: 'deny' },
52
- },
53
- //2026-08-21實測失敗(UnknownError, 與zen:deepseek同日之401同源); 保留理由見該條註記
54
- },
55
- {
56
- id: 'oc:agnes-ai/agnes-2.5-flash',
57
- model: 'agnes-ai/agnes-2.5-flash',
58
- kind: 'opencode',
59
- envVar: 'AGNES_KEYS',
60
- provider: 'agnes-ai',
61
- config: {
62
- provider: {
63
- 'agnes-ai': {
64
- npm: '@ai-sdk/openai-compatible',
65
- name: 'Agnes',
66
- options: { baseURL: 'https://apihub.agnes-ai.com/v1' },
67
- models: { 'agnes-2.5-flash': { name: 'Agnes 2.5 Flash' } },
68
- },
69
- },
70
- permission: { edit: 'deny', write: 'deny', bash: 'deny' },
71
- },
72
- },
73
- {
74
- id: 'oc:poolside/poolside/laguna-s-2.1',
75
- model: 'poolside/poolside/laguna-s-2.1',
76
- kind: 'opencode',
77
- envVar: 'POOLSIDE_KEYS',
78
- provider: 'poolside',
79
- config: {
80
- provider: {
81
- 'poolside': {
82
- npm: '@ai-sdk/openai-compatible',
83
- name: 'Poolside',
84
- options: { baseURL: 'https://inference.poolside.ai/v1' },
85
- models: { 'poolside/laguna-s-2.1': { name: 'Laguna S 2.1' } },
86
- },
87
- },
88
- permission: { edit: 'deny', write: 'deny', bash: 'deny' },
89
- },
90
- },
91
- {
92
- id: 'agy:gemini-3.7-flash-high',
93
- model: 'gemini-3.7-flash-high',
94
- kind: 'antigravity',
95
- addDirs: ['.'],
96
- //保留CLI權限閘門(條目自帶防寫, 與其餘三家CLI條目一致): canary實測(2026-08-15)
97
- //無此鎖時要求建檔會真的落地(12.5s); false之下寫入被擋且不卡逾時(6.4s正常返回)
98
- //唯讀工具照常(8.0s讀檔答對)。注意被擋時agy回ok:true且stdout為空(靜默拒絕非報錯),
99
- //工作流層無害(空回覆過不了validate而自動遞補); 需要寫入能力請於條目覆寫為true
100
- skipPermissions: false,
101
- },
102
- {
103
- id: 'claude:sonnet',
104
- model: 'sonnet',
105
- kind: 'claude',
106
- extraArgs: ['--disallowedTools', 'Write,Edit,NotebookEdit,Bash'],
107
- },
108
- {
109
- id: 'codex:gpt-5.6-luna',
110
- model: 'gpt-5.6-luna',
111
- kind: 'codex',
112
- sandbox: 'read-only',
113
- },
114
-
115
- //api版
116
- //zen:系為2026-08-21快照(檔頭聲明), 各條註記當日以「請只回覆兩個字:完成」實測之結果
117
- {
118
- id: 'zen:deepseek-v4-flash-free',
119
- model: 'deepseek-v4-flash-free',
120
- kind: 'api-openai-compat',
121
- envVar: 'OPENCODE_KEYS',
122
- baseURL: 'https://opencode.ai/zen/v1',
123
- body: { max_tokens: 8192 },
124
- //2026-08-21實測回401(官方訊息: Free promotion has ended); opencode方案端仍列此模型,
125
- //判讀為用量壓力下之暫時狀態而保留, 恢復之偵測即下次再打
126
- },
127
- {
128
- id: 'zen:laguna-s-2.1-free',
129
- model: 'laguna-s-2.1-free',
130
- kind: 'api-openai-compat',
131
- envVar: 'OPENCODE_KEYS',
132
- baseURL: 'https://opencode.ai/zen/v1',
133
- body: { max_tokens: 8192 },
134
- //2026-08-21實測4.0s; 同一laguna之第三條路(Poolside官方REST/oc CLI/zen), 三者故障域獨立
135
- },
136
- {
137
- id: 'zen:x-preview-f-free',
138
- model: 'x-preview-f-free', //官方顯示名Ox Alpha Free
139
- kind: 'api-openai-compat',
140
- envVar: 'OPENCODE_KEYS',
141
- baseURL: 'https://opencode.ai/zen/v1',
142
- body: { max_tokens: 8192 },
143
- //2026-08-21實測2.4s; 使用端回報批次涵蓋率偏低(3篇輸入常只回1~2篇), 批次任務慎用
144
- },
145
- {
146
- id: 'zen:muse-spark-1.2-contributor-free',
147
- model: 'muse-spark-1.2-contributor-free',
148
- kind: 'api-openai-compat',
149
- envVar: 'OPENCODE_KEYS',
150
- baseURL: 'https://opencode.ai/zen/v1',
151
- body: { max_tokens: 8192 },
152
- //2026-08-21實測3.9s; 使用端回報批次涵蓋率100%、術語標準、內容密度高
153
- },
154
- {
155
- id: 'zen:mimo-v2.5-free',
156
- model: 'mimo-v2.5-free',
157
- kind: 'api-openai-compat',
158
- envVar: 'OPENCODE_KEYS',
159
- baseURL: 'https://opencode.ai/zen/v1',
160
- body: { max_tokens: 8192 },
161
- //2026-08-21實測連續429(FreeUsageLimitError, 容量型)——429證明閘道認得此id(寫錯會回其他4xx)
162
- },
163
- {
164
- id: 'zen:hy3-free',
165
- model: 'hy3-free',
166
- kind: 'api-openai-compat',
167
- envVar: 'OPENCODE_KEYS',
168
- baseURL: 'https://opencode.ai/zen/v1',
169
- body: { max_tokens: 8192 },
170
- //2026-08-21實測3.2s
171
- },
172
- {
173
- id: 'zen:nemotron-3-ultra-free',
174
- model: 'nemotron-3-ultra-free',
175
- kind: 'api-openai-compat',
176
- envVar: 'OPENCODE_KEYS',
177
- baseURL: 'https://opencode.ai/zen/v1',
178
- body: { max_tokens: 8192 },
179
- //2026-08-21實測2.2s; function calling協定實測可用(tool_calls格式標準, 但本套件api類不支援工具)
180
- },
181
- {
182
- id: 'zen:nemotron-3.5-lightning-free',
183
- model: 'nemotron-3.5-lightning-free',
184
- kind: 'api-openai-compat',
185
- envVar: 'OPENCODE_KEYS',
186
- baseURL: 'https://opencode.ai/zen/v1',
187
- body: { max_tokens: 8192 },
188
- //2026-08-21實測27.4s——名為lightning實測卻最慢, timeout與批量規劃須留意
189
- },
190
- {
191
- id: 'agnes:agnes-2.5-flash',
192
- model: 'agnes-2.5-flash',
193
- kind: 'api-openai-compat',
194
- envVar: 'AGNES_KEYS',
195
- baseURL: 'https://apihub.agnes-ai.com/v1',
196
- body: { max_tokens: 8192 },
197
- },
198
- {
199
- id: 'poolside:laguna-s-2.1',
200
- model: 'poolside/laguna-s-2.1',
201
- kind: 'api-openai-compat',
202
- envVar: 'POOLSIDE_KEYS',
203
- baseURL: 'https://inference.poolside.ai/v1',
204
- body: {
205
- max_tokens: 8192,
206
- chat_template_kwargs: { enable_thinking: false },
207
- },
208
- },
209
-
210
- ]
211
-
212
-
213
- export default providers
1
+ // providers.mjs — 預設providers定義檔(實測可用之供應商條目, 開發端可直接全用或自選)
2
+ //
3
+ // 【性質】純資料檔, 不讀環境變數。金鑰以envVar間接引用(機密不落設定檔),
4
+ // 使用前須經resolveProviders展開(envVar → keys, 缺變數者自動停用並回報);
5
+ // 展開後之陣列可直接餵dispatchAiFallback, table可直接餵dispatchAiWkf。
6
+ //
7
+ // 【id命名】依「路徑:模型」規則(詳dispatchAiFallback.mjs檔頭之id設計規則):
8
+ // oc:=經opencode CLI(有工具、較慢) / agy:=antigravity CLI / claude:/codex:=訂閱登入態CLI
9
+ // zen:/agnes:/poolside:=REST直呼(免CLI免登入、快, 純文字生成)
10
+ // 同一模型之CLI版與REST版屬不同供應商(能力與額度池皆不同), 故各為一條。
11
+ //
12
+ // ══════════════════════════════════════════════════════════════════════════════
13
+ // 【OpenCode Zen 接入方式——動 zen:條目前必讀, 免得又把「打錯端點」誤判成「模型壞了」】
14
+ // ══════════════════════════════════════════════════════════════════════════════
15
+ //
16
+ // 權威來源(唯一, 有疑問先查它, 不要憑既有條目推論):
17
+ // https://opencode.ai/docs/zh-tw/zen/ 內含「端點」章節之逐模型端點對照表
18
+ // https://opencode.ai/zen/v1/models ← 當前可用model id清單(需Bearer金鑰)
19
+ //
20
+ // 核心事實: zen「不是」單一OpenAI相容端點, 端點依模型家族而異 ★
21
+ // 依官方文件之端點欄(2026-09-03查證):
22
+ // /zen/v1/chat/completions @ai-sdk/openai-compatible ← 本套件api-openai-compat僅支援此種
23
+ // mimo-v2.5-free / ling-3.0-flash-fin-free / nemotron-3-ultra-free /
24
+ // nemotron-3.5-lightning-free / big-pickle / glm-* / kimi-* / minimax-* / deepseek-v4-*
25
+ // /zen/v1/responses @ai-sdk/openai (OpenAI Responses API, 非chat/completions)
26
+ // muse-spark-1.2-contributor-free / muse-spark-1.3-contributor-free / GPT系 / Grok系
27
+ // /zen/v1/messages @ai-sdk/anthropic Claude系 / Qwen系
28
+ // /zen/v1/models/<model-id> @ai-sdk/google Gemini系
29
+ //
30
+ // ★ 因此: 模型出現在/models清單 ≠ 可用kind:'api-openai-compat'收錄
31
+ // dispatchApiOpenaiCompat固定POST至<baseURL>/chat/completions(那是它的定義, 非bug),
32
+ // 對走/responses或/messages的模型必然失敗, 且失敗碼是HTTP 500(不是404/400),
33
+ // 極易被誤讀為「模型故障, 等一下就好」而反覆重試——實際上再等一年也不會通。
34
+ // 殷鑑(2026-09-03): muse-spark-1.2/1.3走/chat/completions連續10次500,
35
+ // 同金鑰同模型改打/responses立即200且正常作答;
36
+ // 且1.2於2026-08-21曾以/chat/completions實測3.9s成功——即opencode「事後改過路由」,
37
+ // 故「以前能用」不構成「現在該能用」的證據, 一律回頭查文件端點欄。
38
+ //
39
+ // ★ 收錄zen:條目前之檢核(缺一不可) ★
40
+ // ① 該model id在 /zen/v1/models 清單內;
41
+ // ② 依官方文件端點欄挑對kind: /chat/completions → api-openai-compat;
42
+ // /responses → api-openai-responses; /messages與/models/<id> 本套件尚無對應kind,
43
+ // 不得硬收為既有kind(必失敗), 需要時改收其opencode CLI(oc:);
44
+ // ③ 實測至少連續數次200(端點時斷時續者仍可收, 但須於條目註解記錄可用率, 見ling條)。
45
+ //
46
+ // ★ 診斷流程(收到失敗時先分類, 不要直接歸咎模型) ★
47
+ // HTTP 500 → 先驗端點: 查文件端點欄; 該走/responses卻打了/chat/completions即為此症。
48
+ // 驗法: curl -X POST https://opencode.ai/zen/v1/responses \
49
+ // -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
50
+ // -d '{"model":"<id>","input":"hi"}' → 200即證明是端點問題非模型問題
51
+ // HTTP 503 → 上游時斷時續(server_error: Upstream request failed: Endpoint is unavailable),
52
+ // 暫時性, 遞補層換家即可; 判別法: 同時段打另一免費模型作對照組。
53
+ // HTTP 429 → 閘道容量型限流(FreeUsageLimitError), 與金鑰無關(換金鑰照樣429), 暫時性。
54
+ // HTTP 401/400 → 額度/促銷結束或模型暫時下架(訊息如Free promotion has ended、
55
+ // Upstream request failed: Model is unavailable), 屬服務端狀態非設定錯誤。
56
+ // 任一碼皆非「條目寫錯」之證據——model id寫錯時閘道回的是其他4xx且訊息明指model。
57
+ //
58
+ // ★ 走不通REST時的替代路徑: 同模型改用oc:(opencode CLI) ★
59
+ // opencode CLI內建各模型正確的端點與AI SDK, 故REST不通的模型走CLI往往正常
60
+ // (實測: muse-spark 1.2/1.3之REST 500而CLI皆秒級成功)。CLI版模型id為
61
+ // `opencode/<model-id>`, 可用 `opencode models` 列出; 兩者屬不同供應商條目(見id命名)。
62
+ //
63
+ // 【zen免費模型清單為「更新日快照」, 不保證即為當前狀態】zen:系收錄截至2026-08-21
64
+ // 經GET https://opencode.ai/zen/v1/models 查得之免費模型(*-free), 不做好用篩選——
65
+ // 新模型會上線、舊模型可能下架或限流, 且各模型能力/速度/輸出習慣差異極大
66
+ // (各條目註解記錄已測特性), 由呼叫端自行評估選用; 要查當前清單, 以OPENCODE_KEYS
67
+ // 打上述/models端點即可。暫時打不通的條目(限流/額度/上游中斷)依本套件哲學保留不移除:
68
+ // 恢復的偵測就是下次再打一次, 代價僅一次快速失敗(fallback/cooldownMs即為此而生);
69
+ // 但「端點種類不符」(如上述muse-spark走/responses)屬結構性錯配而非暫時失敗, 不適用此哲學。
70
+ // 2026-09-03複查之漂移: 新增muse-spark-1.3-contributor-free(端點為/responses,
71
+ // 同日新增api-openai-responses轉接器後已收錄zen:版, 另亦收其opencode CLI版)
72
+ // 與ling-3.0-flash-fin-free(已收錄, 上游時斷時續詳見該條); zen:x-preview-f-free與zen:hy3-free已自本檔移除——兩者同時滿足
73
+ // 「不在/models清單」與「實測回401」兩條件, 屬服務端已下架而非暫時限流(對照deepseek為
74
+ // 仍在清單之401/400故保留), 留著只會讓全取者每輪空耗兩次快速失敗。
75
+ // 註: zen:deepseek-v4-flash-free與zen:laguna-s-2.1-free未列於官方文件端點表
76
+ // (文件僅列付費版deepseek-v4-flash/pro, laguna全無), 屬未文件化之免費變體,
77
+ // 端點種類係沿用實測結果(/chat/completions), 日後若失效須優先懷疑其端點已變。
78
+ //
79
+ // 【使用方式】
80
+ // import providers from 'w-dispatch-ai/src/providers.mjs'
81
+ // import resolveProviders from 'w-dispatch-ai/src/resolveProviders.mjs'
82
+ // import readEnvFile from 'w-dispatch-ai/src/readEnvFile.mjs'
83
+ // let env = readEnvFile('./.env') //OPENCODE_KEYS/AGNES_KEYS/POOLSIDE_KEYS, 逗號分隔多把; 不污染process.env
84
+ // let { providers: ps, table, skipped } = resolveProviders(providers, { env }) //全取
85
+ // let r2 = resolveProviders(providers, { env, pick: ['agnes:agnes-2.5-flash', 'claude:sonnet'] }) //自選, pick順序即遞補優先序
86
+ //
87
+ // 【timeout規劃】各條目刻意不帶timeoutMs, 由上層依任務型態統一給定、條目僅於特例覆寫:
88
+ // 簡單任務(秒級~分鐘級): 沿用套件統一預設即可(全轉接器一律300000=5分鐘, 見dfTimeoutMs.mjs)。
89
+ // 複雜任務(單一AI工作約15分鐘、fallback須能走到最末):
90
+ // timeoutMs: 1200000 (20min=15min工作+33%餘裕, 單次嘗試上限)
91
+ // minAttemptMs: 1200000 (剩餘預算不足完整視窗即不開工——開了也不可能完成, 純浪費)
92
+ // budgetMs: 鏈長K×timeoutMs (逾時型失敗每組只燒一次timeout即跳組, 故K×20min
93
+ // 保證能走到最末; 例K=4 → 4800000=80min。無外部排程時限則可null=不限)
94
+ // agy之printTimeout由timeoutMs自動推導(−30s), 無須另設。
95
+ // 工作流層總時長: RolePipeline為各階段序列相加(M階段≈M×名額預算);
96
+ // Fanout各名額並行(≈單一名額預算+整合名額預算), 外部排程上限須據此預留。
97
+ // 外部調整四層(細者覆蓋粗者): dispatchAiWkf之defaults(全域) → 各工作流callOpt
98
+ // → 各階段/名額規格 → 各provider條目。
99
+
100
+
101
+ let providers = [
102
+
103
+ //cli版
104
+ {
105
+ id: 'oc:agnes-ai/agnes-2.5-flash',
106
+ model: 'agnes-ai/agnes-2.5-flash',
107
+ kind: 'opencode',
108
+ envVar: 'AGNES_KEYS',
109
+ provider: 'agnes-ai',
110
+ config: {
111
+ provider: {
112
+ 'agnes-ai': {
113
+ npm: '@ai-sdk/openai-compatible',
114
+ name: 'Agnes',
115
+ options: { baseURL: 'https://apihub.agnes-ai.com/v1' },
116
+ models: { 'agnes-2.5-flash': { name: 'Agnes 2.5 Flash' } },
117
+ },
118
+ },
119
+ permission: { edit: 'deny', write: 'deny', bash: 'deny' },
120
+ },
121
+ },
122
+ {
123
+ id: 'oc:poolside/poolside/laguna-s-2.1',
124
+ model: 'poolside/poolside/laguna-s-2.1',
125
+ kind: 'opencode',
126
+ envVar: 'POOLSIDE_KEYS',
127
+ provider: 'poolside',
128
+ config: {
129
+ provider: {
130
+ 'poolside': {
131
+ npm: '@ai-sdk/openai-compatible',
132
+ name: 'Poolside',
133
+ options: { baseURL: 'https://inference.poolside.ai/v1' },
134
+ models: { 'poolside/laguna-s-2.1': { name: 'Laguna S 2.1' } },
135
+ },
136
+ },
137
+ permission: { edit: 'deny', write: 'deny', bash: 'deny' },
138
+ },
139
+ },
140
+ {
141
+ id: 'oc:opencode/muse-spark-1.2-contributor-free',
142
+ model: 'opencode/muse-spark-1.2-contributor-free',
143
+ kind: 'opencode',
144
+ envVar: 'OPENCODE_KEYS',
145
+ provider: 'opencode',
146
+ config: {
147
+ permission: { edit: 'deny', write: 'deny', bash: 'deny' },
148
+ },
149
+ //2026-09-03實測8.1s(opencode CLI 1.18.27); 同模型另有zen:REST版, 額度池與故障域各自獨立
150
+ },
151
+ {
152
+ id: 'oc:opencode/muse-spark-1.3-contributor-free',
153
+ model: 'opencode/muse-spark-1.3-contributor-free',
154
+ kind: 'opencode',
155
+ envVar: 'OPENCODE_KEYS',
156
+ provider: 'opencode',
157
+ config: {
158
+ permission: { edit: 'deny', write: 'deny', bash: 'deny' },
159
+ },
160
+ //2026-09-03實測6.1s(opencode CLI 1.18.27)。註: 同日同模型走zen REST回HTTP 500,
161
+ //僅CLI路徑可用——同模型不同路徑屬不同供應商之實例(故未增zen:對應條目)
162
+ },
163
+ {
164
+ id: 'oc:opencode/deepseek-v4-flash-free',
165
+ model: 'opencode/deepseek-v4-flash-free',
166
+ kind: 'opencode',
167
+ envVar: 'OPENCODE_KEYS',
168
+ provider: 'opencode',
169
+ config: {
170
+ permission: { edit: 'deny', write: 'deny', bash: 'deny' },
171
+ },
172
+ //2026-08-21實測失敗(UnknownError, 與zen:deepseek同日之401同源); 保留理由見該條註記
173
+ },
174
+ {
175
+ id: 'agy:gemini-3.8-flash-high',
176
+ model: 'gemini-3.8-flash-high', //2026-09-03自3.7升版(agy 1.1.25): 實測12.5s vs 3.7之62.2s, 讀檔14.6s vs 57.6s
177
+ kind: 'antigravity',
178
+ addDirs: ['.'],
179
+ //保留CLI權限閘門(條目自帶防寫, 與其餘三家CLI條目一致): canary實測(2026-08-15)
180
+ //無此鎖時要求建檔會真的落地(12.5s); false之下寫入被擋且不卡逾時(6.4s正常返回)、
181
+ //唯讀工具照常(8.0s讀檔答對)。注意被擋時agy回ok:true且stdout為空(靜默拒絕非報錯),
182
+ //工作流層無害(空回覆過不了validate而自動遞補); 需要寫入能力請於條目覆寫為true
183
+ skipPermissions: false,
184
+ },
185
+ {
186
+ id: 'claude:sonnet',
187
+ model: 'sonnet',
188
+ kind: 'claude',
189
+ extraArgs: ['--disallowedTools', 'Write,Edit,NotebookEdit,Bash'],
190
+ },
191
+ {
192
+ id: 'codex:gpt-5.6-luna',
193
+ model: 'gpt-5.6-luna',
194
+ kind: 'codex',
195
+ sandbox: 'read-only',
196
+ },
197
+
198
+ //api版
199
+ //zen:系為2026-08-21快照(檔頭聲明), 各條註記當日以「請只回覆兩個字:完成」實測之結果
200
+ {
201
+ id: 'agnes:agnes-2.5-flash',
202
+ model: 'agnes-2.5-flash',
203
+ kind: 'api-openai-compat',
204
+ envVar: 'AGNES_KEYS',
205
+ baseURL: 'https://apihub.agnes-ai.com/v1',
206
+ body: { max_tokens: 8192 },
207
+ },
208
+ {
209
+ id: 'poolside:laguna-s-2.1',
210
+ model: 'poolside/laguna-s-2.1',
211
+ kind: 'api-openai-compat',
212
+ envVar: 'POOLSIDE_KEYS',
213
+ baseURL: 'https://inference.poolside.ai/v1',
214
+ body: {
215
+ max_tokens: 8192,
216
+ chat_template_kwargs: { enable_thinking: false },
217
+ },
218
+ },
219
+ {
220
+ id: 'zen:laguna-s-2.1-free',
221
+ model: 'laguna-s-2.1-free',
222
+ kind: 'api-openai-compat',
223
+ envVar: 'OPENCODE_KEYS',
224
+ baseURL: 'https://opencode.ai/zen/v1',
225
+ body: { max_tokens: 8192 },
226
+ //2026-08-21實測4.0s; 同一laguna之第三條路(Poolside官方REST/oc CLI/zen), 三者故障域獨立
227
+ },
228
+ {
229
+ id: 'zen:muse-spark-1.2-contributor-free',
230
+ model: 'muse-spark-1.2-contributor-free',
231
+ kind: 'api-openai-responses',
232
+ envVar: 'OPENCODE_KEYS',
233
+ baseURL: 'https://opencode.ai/zen/v1',
234
+ body: { max_output_tokens: 8192 },
235
+ //端點為/responses(官方文件端點欄), 故kind為api-openai-responses而非api-openai-compat:
236
+ //2026-08-21曾以/chat/completions實測3.9s成功, 2026-09-03同路徑連續500——opencode事後改過路由,
237
+ //改打/responses即200。此即檔頭「端點依模型家族而異」之實例
238
+ //2026-09-03實測ok; 使用端回報批次涵蓋率100%、術語標準、內容密度高
239
+ },
240
+ {
241
+ id: 'zen:muse-spark-1.3-contributor-free',
242
+ model: 'muse-spark-1.3-contributor-free',
243
+ kind: 'api-openai-responses',
244
+ envVar: 'OPENCODE_KEYS',
245
+ baseURL: 'https://opencode.ai/zen/v1',
246
+ body: { max_output_tokens: 8192 }, //Responses API之輸出上限欄位名(非max_tokens)
247
+ //2026-09-03實測ok(同日以/chat/completions連續10次500, 改/responses立即200);
248
+ //reasoning型模型, 實測output_tokens中多數為reasoning_tokens, 上限勿設過小否則status為incomplete
249
+ },
250
+ {
251
+ id: 'zen:deepseek-v4-flash-free',
252
+ model: 'deepseek-v4-flash-free',
253
+ kind: 'api-openai-compat',
254
+ envVar: 'OPENCODE_KEYS',
255
+ baseURL: 'https://opencode.ai/zen/v1',
256
+ body: { max_tokens: 8192 },
257
+ //2026-08-21實測回401(官方訊息: Free promotion has ended); opencode方案端仍列此模型,
258
+ //判讀為用量壓力下之暫時狀態而保留, 恢復之偵測即下次再打
259
+ },
260
+ {
261
+ id: 'zen:mimo-v2.5-free',
262
+ model: 'mimo-v2.5-free',
263
+ kind: 'api-openai-compat',
264
+ envVar: 'OPENCODE_KEYS',
265
+ baseURL: 'https://opencode.ai/zen/v1',
266
+ body: { max_tokens: 8192 },
267
+ //2026-08-21實測連續429(FreeUsageLimitError, 容量型)——429證明閘道認得此id(寫錯會回其他4xx)
268
+ },
269
+ {
270
+ id: 'zen:ling-3.0-flash-fin-free',
271
+ model: 'ling-3.0-flash-fin-free',
272
+ kind: 'api-openai-compat',
273
+ envVar: 'OPENCODE_KEYS',
274
+ baseURL: 'https://opencode.ai/zen/v1',
275
+ body: { max_tokens: 8192 },
276
+ //2026-09-03實測: 上游時斷時續, 20次量測200者僅7次(且呈段落式: 連6次成功後連13次失敗),
277
+ //失敗一律HTTP 503(server_error: Upstream request failed: Endpoint is unavailable),
278
+ //同時段對照組nemotron 7/7正常, 故屬本模型上游而非閘道或金鑰問題;
279
+ //503為暫時性且非金鑰相關, 遞補層會換下一家, 建議搭配cooldownMs降低重複踩中的成本
280
+ },
281
+ {
282
+ id: 'zen:nemotron-3-ultra-free',
283
+ model: 'nemotron-3-ultra-free',
284
+ kind: 'api-openai-compat',
285
+ envVar: 'OPENCODE_KEYS',
286
+ baseURL: 'https://opencode.ai/zen/v1',
287
+ body: { max_tokens: 8192 },
288
+ //2026-08-21實測2.2s; function calling協定實測可用(tool_calls格式標準, 但本套件api類不支援工具)
289
+ },
290
+ {
291
+ id: 'zen:nemotron-3.5-lightning-free',
292
+ model: 'nemotron-3.5-lightning-free',
293
+ kind: 'api-openai-compat',
294
+ envVar: 'OPENCODE_KEYS',
295
+ baseURL: 'https://opencode.ai/zen/v1',
296
+ body: { max_tokens: 8192 },
297
+ //2026-08-21實測27.4s——名為lightning實測卻最慢, timeout與批量規劃須留意
298
+ },
299
+
300
+ ]
301
+
302
+
303
+ export default providers
@@ -57,7 +57,7 @@ import strFindSimilar from 'wsemi/src/strFindSimilar.mjs'
57
57
  * //全取: envVar展開為keys, 缺環境變數者列入skipped
58
58
  * let { providers, table, skipped } = resolveProviders(providersAll, { env })
59
59
  * console.log(providers.length, skipped)
60
- * // => 16 []
60
+ * // => 17 []
61
61
  *
62
62
  * //pick打錯字時, missing附拼寫提示hints(最接近之可用id)
63
63
  * let rm = resolveProviders(providersAll, { env, pick: ['poolside/laguna-s-2.1'] })