w-dispatch-ai 1.0.3 → 1.0.5

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 (50) hide show
  1. package/README.md +153 -43
  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 +8 -4
  5. package/docs/adapters.mjs.html +36 -2
  6. package/docs/dfTimeoutMs.mjs.html +98 -0
  7. package/docs/dispatchAi.mjs.html +2 -2
  8. package/docs/dispatchAiFallback.mjs.html +55 -16
  9. package/docs/dispatchAiWkf.mjs.html +42 -8
  10. package/docs/dispatchAntigravity.mjs.html +23 -12
  11. package/docs/dispatchApiOpenaiCompat.mjs.html +40 -6
  12. package/docs/dispatchClaude.mjs.html +17 -4
  13. package/docs/dispatchCodex.mjs.html +16 -3
  14. package/docs/dispatchOpencode.mjs.html +16 -3
  15. package/docs/getCliArgs.mjs.html +2 -2
  16. package/docs/getErrorResult.mjs.html +2 -2
  17. package/docs/global.html +511 -66
  18. package/docs/index.html +2 -2
  19. package/docs/resolveProviders.mjs.html +189 -0
  20. package/docs/wkf_callAiWithFallback.mjs.html +22 -11
  21. package/docs/wkf_extractJsonLoose.mjs.html +2 -2
  22. package/docs/wkf_runFanout.mjs.html +7 -7
  23. package/docs/wkf_runFanoutPipeline.mjs.html +7 -7
  24. package/docs/wkf_runRolePipeline.mjs.html +6 -6
  25. package/g.mjs +30 -23
  26. package/package.json +1 -1
  27. package/src/WDispatchAi.mjs +6 -2
  28. package/src/adapters.mjs +34 -0
  29. package/src/dfTimeoutMs.mjs +26 -0
  30. package/src/dispatchAiFallback.mjs +53 -14
  31. package/src/dispatchAiWkf.mjs +40 -6
  32. package/src/dispatchAntigravity.mjs +21 -10
  33. package/src/dispatchApiOpenaiCompat.mjs +38 -4
  34. package/src/dispatchClaude.mjs +15 -2
  35. package/src/dispatchCodex.mjs +14 -1
  36. package/src/dispatchOpencode.mjs +14 -1
  37. package/src/providers.mjs +133 -0
  38. package/src/resolveProviders.mjs +117 -0
  39. package/src/wkf/callAiWithFallback.mjs +20 -9
  40. package/src/wkf/runFanout.mjs +5 -5
  41. package/src/wkf/runFanoutPipeline.mjs +5 -5
  42. package/src/wkf/runRolePipeline.mjs +4 -4
  43. package/test/tools/fakeServerForApiTest.mjs +14 -0
  44. package/test/unit-WDispatchAi.test.mjs +9 -3
  45. package/test/unit-dispatchAi.test.mjs +1 -1
  46. package/test/unit-dispatchAiFallback.test.mjs +25 -0
  47. package/test/unit-dispatchAntigravity.test.mjs +25 -5
  48. package/test/unit-dispatchApiOpenaiCompat.test.mjs +31 -0
  49. package/test/unit-providers.test.mjs +66 -0
  50. package/test/unit-resolveProviders.test.mjs +85 -0
package/docs/index.html CHANGED
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -71,7 +71,7 @@
71
71
  <br class="clear">
72
72
 
73
73
  <footer>
74
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
75
  </footer>
76
76
 
77
77
  <script>prettyPrint();</script>
@@ -0,0 +1,189 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>resolveProviders.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">resolveProviders.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import get from 'lodash-es/get.js'
49
+ import omit from 'lodash-es/omit.js'
50
+ import isarr from 'wsemi/src/isarr.mjs'
51
+ import isobj from 'wsemi/src/isobj.mjs'
52
+ import isestr from 'wsemi/src/isestr.mjs'
53
+ import isearr from 'wsemi/src/isearr.mjs'
54
+
55
+
56
+ // resolveProviders.mjs — 把providers定義檔展開為可直接使用的條目
57
+ //
58
+ // 【為何需要】providers.mjs之條目以envVar間接引用金鑰(機密不落設定檔, 只寫變數名),
59
+ // 而dispatchAiFallback只認keys陣列——本函數負責envVar → keys之展開,
60
+ // 缺對應環境變數者停用該條目並列入skipped回報(不中斷、不throw),
61
+ // 訂閱登入態條目(claude/codex等無envVar)原樣通過。
62
+ //
63
+ // 【自選】opt.pick給id陣列即可只取用部分條目, 且依pick之順序回傳
64
+ // (順序即dispatchAiFallback之優先序); 查無之id列入missing回報。
65
+
66
+
67
+ /**
68
+ * 展開providers定義條目:envVar → keys,並可依id自選子集
69
+ *
70
+ * 特點:
71
+ * 條目之envVar依env來源(預設process.env)展開為keys陣列(變數值以逗號分隔多把),envVar欄位自輸出移除;
72
+ * 缺對應環境變數(或值為空)之條目停用並列入skipped,不中斷不throw;
73
+ * 無envVar之條目(訂閱登入態CLI)原樣通過;條目已自帶有效keys者以keys為準;
74
+ * opt.pick可依id自選子集並以pick順序回傳(順序即遞補優先序);
75
+ * 輸入陣列與條目皆不被改動(輸出為淺拷貝)
76
+ *
77
+ * @param {Array} providers 輸入providers條目物件陣列(如providers.mjs之預設匯出)
78
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
79
+ * @param {Object} [opt.env=process.env] 輸入金鑰來源物件(變數名 → 逗號分隔之金鑰字串),預設process.env
80
+ * @param {Array} [opt.pick=null] 輸入自選id字串陣列,依此順序回傳對應條目,查無之id列入missing,預設null代表全取(依原順序)
81
+ * @returns {Object} 回傳物件,內含providers(可直接餵dispatchAiFallback之條目陣列)、table(id對條目之物件,可直接餵dispatchAiWkf)、skipped(缺環境變數而停用之{id,envVar}陣列)、missing(pick查無之id字串陣列)
82
+ * @example
83
+ *
84
+ * import resolveProviders from './src/resolveProviders.mjs'
85
+ * import providersAll from './src/providers.mjs'
86
+ *
87
+ * process.loadEnvFile('./.env') //金鑰放.env, 變數值以逗號分隔多把
88
+ *
89
+ * //全取: envVar展開為keys, 缺環境變數者列入skipped
90
+ * let { providers, table, skipped } = resolveProviders(providersAll)
91
+ * console.log(providers.length, skipped)
92
+ * // => 10 []
93
+ *
94
+ * //自選: 依pick順序回傳(順序即遞補優先序), 可直接餵dispatchAiFallback
95
+ * let r2 = resolveProviders(providersAll, { pick: ['agnes:agnes-2.5-flash', 'claude:sonnet'] })
96
+ * console.log(r2.providers.map((p) => p.id))
97
+ * // => [ 'agnes:agnes-2.5-flash', 'claude:sonnet' ]
98
+ *
99
+ * //table可直接餵dispatchAiWkf之providers定義表
100
+ * //let wkf = dispatchAiWkf({ providers: r2.table, defaults: { timeoutMs: 1200000 } })
101
+ *
102
+ */
103
+ function resolveProviders(providers, opt = {}) {
104
+
105
+ //env, 無效回退process.env(瀏覽器環境無process則空物件)
106
+ let env = get(opt, 'env', null)
107
+ if (!isobj(env)) {
108
+ env = (typeof process !== 'undefined' &amp;&amp; process &amp;&amp; isobj(process.env)) ? process.env : {}
109
+ }
110
+
111
+ //providersRaw
112
+ let providersRaw = isarr(providers) ? providers.filter(isobj) : []
113
+
114
+ //pick, 依id自選並依pick順序回傳
115
+ let pick = get(opt, 'pick', null)
116
+ let missing = []
117
+ let selected = providersRaw
118
+ if (isearr(pick)) {
119
+ selected = []
120
+ for (let id of pick) {
121
+ let entry = providersRaw.find((p) => get(p, 'id', null) === id)
122
+ if (entry) {
123
+ selected.push(entry)
124
+ }
125
+ else {
126
+ missing.push(String(id))
127
+ }
128
+ }
129
+ }
130
+
131
+ //展開envVar → keys
132
+ let out = []
133
+ let skipped = []
134
+ for (let entry of selected) {
135
+ let envVar = get(entry, 'envVar', null)
136
+
137
+ //無envVar(訂閱登入態CLI)或已自帶有效keys, 原樣通過(僅移除envVar欄位)
138
+ if (!isestr(envVar) || isearr(get(entry, 'keys', null))) {
139
+ out.push(omit(entry, ['envVar']))
140
+ continue
141
+ }
142
+
143
+ //envVar → keys, 變數值以逗號分隔多把
144
+ let keys = String(get(env, envVar, '') || '').split(',').map((k) => k.trim()).filter(Boolean)
145
+ if (keys.length === 0) {
146
+
147
+ //缺環境變數: 停用該條目並回報, 不中斷(設計providers原則§四.4)
148
+ skipped.push({ id: get(entry, 'id', ''), envVar })
149
+ continue
150
+ }
151
+ out.push({ ...omit(entry, ['envVar']), keys })
152
+ }
153
+
154
+ //table, id → 條目, 可直接作dispatchAiWkf之providers定義表
155
+ let table = {}
156
+ for (let entry of out) {
157
+ table[entry.id] = entry
158
+ }
159
+
160
+ return { providers: out, table, skipped, missing }
161
+ }
162
+
163
+
164
+ export default resolveProviders
165
+ </code></pre>
166
+ </article>
167
+ </section>
168
+
169
+
170
+
171
+
172
+
173
+
174
+ </div>
175
+
176
+ <br class="clear">
177
+
178
+ <footer>
179
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
180
+ </footer>
181
+
182
+ <script>prettyPrint();</script>
183
+ <script src="scripts/polyfill.js"></script>
184
+ <script src="scripts/linenumber.js"></script>
185
+
186
+
187
+
188
+ </body>
189
+ </html>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -51,6 +51,7 @@ import isestr from 'wsemi/src/isestr.mjs'
51
51
  import isfun from 'wsemi/src/isfun.mjs'
52
52
  import isobj from 'wsemi/src/isobj.mjs'
53
53
  import dispatchAiFallback from '../dispatchAiFallback.mjs'
54
+ import dfTimeoutMs from '../dfTimeoutMs.mjs'
54
55
  import extractJsonLoose from './extractJsonLoose.mjs'
55
56
 
56
57
 
@@ -70,13 +71,22 @@ import extractJsonLoose from './extractJsonLoose.mjs'
70
71
  // 【防寫檔前綴】agentic CLI對cwd隔離免疫(會自行解析專案根目錄寫檔),
71
72
  // 故預設在prompt前掛「禁止建檔」約束(實測有效); 不需要時傳promptPrefix:''關閉。
72
73
  // 殷鑑: 2026-08-10執行任務歷史.md遭AI覆寫、評比腳本繞過前綴又產生根目錄孤兒檔。
74
+ //
75
+ // 措辭須豁免「唯讀查閱」(2026-08-13 A/B實測): 各CLI取得檔案內容的途徑不同——
76
+ // opencode與claude有獨立的read/grep工具, 不受「禁止執行指令」約束;
77
+ // 但codex讀檔即是執行shell指令, 舊措辭「禁止執行任何指令」對它等同「禁止讀檔」,
78
+ // 凡需讀專案的任務會得到一句「請貼上檔案內容」而非成果, 且該拒答是合法字串,
79
+ // 會通過驗證被遞補層當成「成功」, 整條fallback鏈就此停住——兜底地位被靜默廢掉。
80
+ // 實測: 舊措辭下codex回「無法讀取該檔案」, 改為下列措辭後正常讀檔作答(11.1s),
81
+ // 防副作用(建檔/改檔/刪檔/改動系統狀態)之本旨不變。
73
82
 
74
83
 
75
- //預設防寫檔前綴
84
+ //預設防寫檔前綴(禁副作用, 但豁免唯讀查閱——codex以shell讀檔, 一律禁指令等同禁讀檔)
76
85
  let NO_SIDE_EFFECT = [
77
86
  '【執行約束】你只需把結果輸出在回覆內容中。',
78
- '禁止建立、修改或刪除任何檔案,禁止執行任何指令——呼叫端只讀取你的回覆文字,',
79
- '任何寫入磁碟的動作都不會被採用,只會製造無人讀取的垃圾檔。',
87
+ '禁止建立、修改或刪除任何檔案,也不要執行任何會改動磁碟或系統狀態的指令——',
88
+ '呼叫端只讀取你的回覆文字,任何寫入磁碟的動作都不會被採用,只會製造無人讀取的垃圾檔。',
89
+ '唯讀查閱(讀取檔案、搜尋內容、列出目錄)不在此限,需要時請照常使用。',
80
90
  '', '',
81
91
  ].join('\n')
82
92
 
@@ -134,7 +144,7 @@ function buildChain(providers, spec) {
134
144
  * @param {Function} [opt.parse=extractJsonLoose] 輸入回覆解析函數(stdout)=>Object|null,預設寬鬆JSON抽取
135
145
  * @param {Boolean} [opt.rawText=false] 輸入是否以純文字模式運作布林值,true代表不解析JSON(json欄位為修剪後文字、check收文字),預設false
136
146
  * @param {String} [opt.promptPrefix=防寫檔約束] 輸入prompt前綴字串,預設為防寫檔約束,傳''關閉
137
- * @param {Number} [opt.timeoutMs=300000] 輸入單次嘗試逾時毫秒正整數,預設300000
147
+ * @param {Number} [opt.timeoutMs=300000] 輸入單次嘗試逾時毫秒正整數,全套件統一預設300000
138
148
  * @param {Number} [opt.budgetMs=null] 輸入整條遞補鏈之時間預算毫秒正整數,預設null代表不限
139
149
  * @param {Number} [opt.maxRetries=0] 輸入同家重試次數非負整數,預設0(韌性交給遞補;端點不穩偶發空回之模型可調高令同鍵重試)
140
150
  * @param {String} [opt.cwd=process.cwd()] 輸入子進程工作目錄字串,預設process.cwd()
@@ -146,20 +156,21 @@ function buildChain(providers, spec) {
146
156
  *
147
157
  * import callAiWithFallback from './src/wkf/callAiWithFallback.mjs'
148
158
  *
159
+ * //鍵名須區分到模型並帶上路徑, 詳見dispatchAiFallback.mjs檔頭之id設計規則
149
160
  * let providers = {
150
- * 'deepseek': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
151
- * 'sonnet': { kind: 'claude', model: 'sonnet' },
161
+ * 'zen:deepseek-v4-flash-free': { kind: 'api-openai-compat', baseURL: 'https://opencode.ai/zen/v1', model: 'deepseek-v4-flash-free', keys: ['sk-xxx'] },
162
+ * 'claude:sonnet': { kind: 'claude', model: 'sonnet' },
152
163
  * }
153
164
  *
154
165
  * let test = async () => {
155
166
  *
156
167
  * let r = await callAiWithFallback('只回覆JSON: {"a":1}', {
157
168
  * providers,
158
- * spec: { use: 'deepseek', fallback: ['sonnet'] },
169
+ * spec: { use: 'zen:deepseek-v4-flash-free', fallback: ['claude:sonnet'] },
159
170
  * check: (j) => j.a === 1,
160
171
  * })
161
172
  * console.log(r.ok, r.json, r.providerId)
162
- * // => true { a: 1 } 'deepseek'
173
+ * // => true { a: 1 } 'zen:deepseek-v4-flash-free'
163
174
  *
164
175
  * }
165
176
  * await test()
@@ -224,7 +235,7 @@ async function callAiWithFallback(prompt, opt = {}) {
224
235
  let r = await dispatchAiFallback(promptPrefix + prompt, {
225
236
  providers: chain,
226
237
  validate,
227
- timeoutMs: get(opt, 'timeoutMs', null) || 300000,
238
+ timeoutMs: get(opt, 'timeoutMs', null) || dfTimeoutMs, //全套件統一預設300000
228
239
  budgetMs: get(opt, 'budgetMs', null) || undefined,
229
240
  maxRetries: get(opt, 'maxRetries', null) || 0,
230
241
  cwd: get(opt, 'cwd', null) || process.cwd(),
@@ -268,7 +279,7 @@ export { buildChain, NO_SIDE_EFFECT }
268
279
  <br class="clear">
269
280
 
270
281
  <footer>
271
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
282
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
272
283
  </footer>
273
284
 
274
285
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -167,7 +167,7 @@ export default extractJsonLoose
167
167
  <br class="clear">
168
168
 
169
169
  <footer>
170
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
170
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
171
171
  </footer>
172
172
 
173
173
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -110,8 +110,8 @@ ${candidates.map((c, i) => `【候選 ${i + 1}】\n${JSON.stringify(c)}`).join('
110
110
  * import runFanout from './src/wkf/runFanout.mjs'
111
111
  *
112
112
  * let providers = {
113
- * 'deepseek': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
114
- * 'sonnet': { kind: 'claude', model: 'sonnet' },
113
+ * 'zen:deepseek-v4-flash-free': { kind: 'api-openai-compat', baseURL: 'https://opencode.ai/zen/v1', model: 'deepseek-v4-flash-free', keys: ['sk-xxx'] },
114
+ * 'claude:sonnet': { kind: 'claude', model: 'sonnet' },
115
115
  * }
116
116
  *
117
117
  * let test = async () => {
@@ -120,10 +120,10 @@ ${candidates.map((c, i) => `【候選 ${i + 1}】\n${JSON.stringify(c)}`).join('
120
120
  * providers,
121
121
  * task: '分析並只回覆JSON: {"essence":"..."}',
122
122
  * agents: [
123
- * { use: 'deepseek', fallback: ['sonnet'] },
124
- * { use: 'sonnet' },
123
+ * { use: 'zen:deepseek-v4-flash-free', fallback: ['claude:sonnet'] },
124
+ * { use: 'claude:sonnet' },
125
125
  * ],
126
- * integrate: { use: 'sonnet' },
126
+ * integrate: { use: 'claude:sonnet' },
127
127
  * check: (j) => !!j.essence,
128
128
  * })
129
129
  * console.log(r.ok, r.integrated, r.candidates.length)
@@ -214,7 +214,7 @@ export { defaultIntegratePrompt }
214
214
  <br class="clear">
215
215
 
216
216
  <footer>
217
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
217
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
218
218
  </footer>
219
219
 
220
220
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -87,8 +87,8 @@ import runRolePipeline from './runRolePipeline.mjs'
87
87
  * import runFanoutPipeline from './src/wkf/runFanoutPipeline.mjs'
88
88
  *
89
89
  * let providers = {
90
- * 'sonnet': { kind: 'claude', model: 'sonnet' },
91
- * 'luna': { kind: 'codex', model: 'gpt-5.6-luna' },
90
+ * 'claude:sonnet': { kind: 'claude', model: 'sonnet' },
91
+ * 'codex:gpt-5.6-luna': { kind: 'codex', model: 'gpt-5.6-luna' },
92
92
  * }
93
93
  *
94
94
  * let test = async () => {
@@ -96,10 +96,10 @@ import runRolePipeline from './runRolePipeline.mjs'
96
96
  * let r = await runFanoutPipeline({
97
97
  * providers,
98
98
  * task: '分析並只回覆JSON: {"essence":"..."}',
99
- * agents: [{ use: 'sonnet' }, { use: 'luna' }],
100
- * integrate: { use: 'sonnet' },
99
+ * agents: [{ use: 'claude:sonnet' }, { use: 'codex:gpt-5.6-luna' }],
100
+ * integrate: { use: 'claude:sonnet' },
101
101
  * stages: [
102
- * { id: 'audit', use: 'luna', prompt: (ctx) => `審計此稿並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.input)}` },
102
+ * { id: 'audit', use: 'codex:gpt-5.6-luna', prompt: (ctx) => `審計此稿並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.input)}` },
103
103
  * ],
104
104
  * check: (j) => !!j.essence,
105
105
  * })
@@ -165,7 +165,7 @@ export default runFanoutPipeline
165
165
  <br class="clear">
166
166
 
167
167
  <footer>
168
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
168
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
169
169
  </footer>
170
170
 
171
171
  <script>prettyPrint();</script>
@@ -29,7 +29,7 @@
29
29
  <nav >
30
30
 
31
31
 
32
- <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#buildChain">buildChain</a></li><li><a href="global.html#buildValidator">buildValidator</a></li><li><a href="global.html#callAiWithFallback">callAiWithFallback</a></li><li><a href="global.html#callOnce">callOnce</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#dispatchAi">dispatchAi</a></li><li><a href="global.html#dispatchAiFallback">dispatchAiFallback</a></li><li><a href="global.html#dispatchAiWkf">dispatchAiWkf</a></li><li><a href="global.html#dispatchAntigravity">dispatchAntigravity</a></li><li><a href="global.html#dispatchApiOpenaiCompat">dispatchApiOpenaiCompat</a></li><li><a href="global.html#dispatchClaude">dispatchClaude</a></li><li><a href="global.html#dispatchCodex">dispatchCodex</a></li><li><a href="global.html#dispatchOpencode">dispatchOpencode</a></li><li><a href="global.html#extractJsonLoose">extractJsonLoose</a></li><li><a href="global.html#getCliArgs">getCliArgs</a></li><li><a href="global.html#getErrorResult">getErrorResult</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#resolveProviders">resolveProviders</a></li><li><a href="global.html#runFanout">runFanout</a></li><li><a href="global.html#runFanoutPipeline">runFanoutPipeline</a></li><li><a href="global.html#runRolePipeline">runRolePipeline</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -95,8 +95,8 @@ let STAGE_KEYS = ['id', 'use', 'fallback', 'prompt', 'check']
95
95
  * import runRolePipeline from './src/wkf/runRolePipeline.mjs'
96
96
  *
97
97
  * let providers = {
98
- * 'sonnet': { kind: 'claude', model: 'sonnet' },
99
- * 'luna': { kind: 'codex', model: 'gpt-5.6-luna' },
98
+ * 'claude:sonnet': { kind: 'claude', model: 'sonnet' },
99
+ * 'codex:gpt-5.6-luna': { kind: 'codex', model: 'gpt-5.6-luna' },
100
100
  * }
101
101
  *
102
102
  * let test = async () => {
@@ -105,8 +105,8 @@ let STAGE_KEYS = ['id', 'use', 'fallback', 'prompt', 'check']
105
105
  * providers,
106
106
  * input: '原始任務',
107
107
  * stages: [
108
- * { id: 'draft', use: 'sonnet', prompt: (ctx) => `就「${ctx.input}」寫初稿, 只回覆JSON: {"text":"..."}` },
109
- * { id: 'review', use: 'luna', prompt: (ctx) => `審閱並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.prev)}` },
108
+ * { id: 'draft', use: 'claude:sonnet', prompt: (ctx) => `就「${ctx.input}」寫初稿, 只回覆JSON: {"text":"..."}` },
109
+ * { id: 'review', use: 'codex:gpt-5.6-luna', prompt: (ctx) => `審閱並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.prev)}` },
110
110
  * ],
111
111
  * })
112
112
  * console.log(r.ok, r.order, r.failedStage)
@@ -182,7 +182,7 @@ export default runRolePipeline
182
182
  <br class="clear">
183
183
 
184
184
  <footer>
185
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Tue Aug 11 2026 13:18:34 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
185
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Aug 14 2026 12:01:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
186
186
  </footer>
187
187
 
188
188
  <script>prettyPrint();</script>
package/g.mjs CHANGED
@@ -91,29 +91,36 @@ let test = async () => {
91
91
  console.log('invalid prompt:', r5.ok, r5.error)
92
92
  // => invalid prompt: false prompt must be a non-empty string
93
93
 
94
- //CLI執行失敗時, 由ok、code、error與stderr判斷原因
95
- let r6 = await wdi.dispatchOpencode(prompt, {
96
- model: 'opencode/deepseek-v4-flash-free',
97
- provider: 'opencode',
94
+ //執行失敗時, 由ok、code、error與stderr判斷原因
95
+ //REST路徑之錯誤依HTTP狀態碼分流(401金鑰無效、429限流、5xx服務端), 判別比CLI之stderr字串可靠
96
+ let r6 = await wdi.dispatchApiOpenaiCompat(prompt, {
97
+ baseURL: 'https://apihub.agnes-ai.com/v1',
98
+ model: 'agnes-2.0-flash',
98
99
  key: 'sk-invalid-key',
99
100
  })
100
- console.log('invalid key:', r6.ok, r6.code, r6.error, r6.stderr.includes('Invalid API key'))
101
- // => invalid key: false 1 Exit code 1 true
101
+ console.log('invalid key:', r6.ok, r6.code, r6.error, r6.stderr.includes('无效的令牌'))
102
+ // => invalid key: false 401 HTTP 401 true
102
103
 
103
104
  //多供應商自動遞補: providers順序即優先序, 組內keys以游標輪替
104
- //此例第1把金鑰無效 → 自動換組內下一把成功; 若整組用盡會遞補下一組(claude), 再失敗遞補codex
105
+ //此例第1把金鑰無效 → 自動換組內下一把成功; 若整組用盡會遞補下一組, 依序往下
106
+ //
107
+ //【id命名】id為游標鍵與日誌標籤, 須區分到「模型」而非只到「廠商」——
108
+ // 取'claude'則日後無法同時掛sonnet與opus, 且日誌看不出實際用了哪個模型;
109
+ // 同一模型經不同路徑(REST/CLI/不同閘道)取得時額度池與故障域各自獨立,
110
+ // 屬不同供應商, 故id須帶上路徑前綴加以區分
105
111
  let r7 = await wdi.dispatchAiFallback(prompt, {
106
112
  providers: [
113
+ //REST版排前面: 免CLI、快3~5倍, 純文字任務優先走此路
107
114
  {
108
- id: 'deepseek',
109
- kind: 'opencode',
110
- model: 'opencode/deepseek-v4-flash-free',
111
- provider: 'opencode',
112
- keys: ['sk-invalid-key-demo', opencodeKeys[0]], //第1把無效, 示範組內輪替
113
- timeoutMs: 180000,
115
+ id: 'agnes:agnes-2.0-flash',
116
+ kind: 'api-openai-compat',
117
+ baseURL: 'https://apihub.agnes-ai.com/v1',
118
+ model: 'agnes-2.0-flash',
119
+ keys: ['sk-invalid-key-demo', agnesKeys[0]], //第1把無效, 示範組內輪替
114
120
  },
121
+ //同一個agnes模型之CLI版: 有工具能力但較慢, 額度池亦不同, 屬另一個供應商
115
122
  {
116
- id: 'agnes',
123
+ id: 'oc:agnes-ai/agnes-2.0-flash',
117
124
  kind: 'opencode',
118
125
  model: 'agnes-ai/agnes-2.0-flash',
119
126
  provider: 'agnes-ai',
@@ -121,21 +128,21 @@ let test = async () => {
121
128
  config: configAgnes, //第三方provider須另給定義
122
129
  timeoutMs: 180000,
123
130
  },
124
- { id: 'claude', kind: 'claude', model: 'sonnet' },
125
- { id: 'codex', kind: 'codex', model: 'gpt-5.6-luna', sandbox: 'read-only' },
126
- { id: 'antigravity', kind: 'antigravity', model: 'gemini-3.6-flash-low' },
131
+ { id: 'claude:sonnet', kind: 'claude', model: 'sonnet' },
132
+ { id: 'codex:gpt-5.6-luna', kind: 'codex', model: 'gpt-5.6-luna', sandbox: 'read-only' },
133
+ { id: 'agy:gemini-3.6-flash-low', kind: 'antigravity', model: 'gemini-3.6-flash-low' },
127
134
  ],
128
135
  budgetMs: 600000,
129
136
  onEvent: (ev) => console.log(' event:', ev.type, ev.keyId, ev.error || ''),
130
137
  })
131
138
  console.log('fallback:', r7.ok, r7.providerId, r7.keyIndex, r7.stdout.trim())
132
139
  console.log('tried:', r7.tried.map((x) => `${x.keyId}:${x.outcome}`).join(', '))
133
- // => event: try deepseek#0
134
- // => event: next-key deepseek#0 Exit code 1
135
- // => event: try deepseek#1
136
- // => event: ok deepseek#1
137
- // => fallback: true deepseek 1 完成
138
- // => tried: deepseek#0:next-key, deepseek#1:ok
140
+ // => event: try agnes:agnes-2.0-flash#0
141
+ // => event: next-key agnes:agnes-2.0-flash#0 HTTP 401
142
+ // => event: try agnes:agnes-2.0-flash#1
143
+ // => event: ok agnes:agnes-2.0-flash#1
144
+ // => fallback: true agnes:agnes-2.0-flash 1 完成
145
+ // => tried: agnes:agnes-2.0-flash#0:next-key, agnes:agnes-2.0-flash#1:ok
139
146
 
140
147
  }
141
148
  await test()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "w-dispatch-ai",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "main": "dist/w-dispatch-ai.umd.js",
5
5
  "dependencies": {
6
6
  "wsemi": "^1.8.70"