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.
- package/README.md +153 -43
- package/dist/w-dispatch-ai.umd.js +2 -2
- package/dist/w-dispatch-ai.umd.js.map +1 -1
- package/docs/WDispatchAi.mjs.html +8 -4
- package/docs/adapters.mjs.html +36 -2
- package/docs/dfTimeoutMs.mjs.html +98 -0
- package/docs/dispatchAi.mjs.html +2 -2
- package/docs/dispatchAiFallback.mjs.html +55 -16
- package/docs/dispatchAiWkf.mjs.html +42 -8
- package/docs/dispatchAntigravity.mjs.html +23 -12
- package/docs/dispatchApiOpenaiCompat.mjs.html +40 -6
- package/docs/dispatchClaude.mjs.html +17 -4
- package/docs/dispatchCodex.mjs.html +16 -3
- package/docs/dispatchOpencode.mjs.html +16 -3
- package/docs/getCliArgs.mjs.html +2 -2
- package/docs/getErrorResult.mjs.html +2 -2
- package/docs/global.html +511 -66
- package/docs/index.html +2 -2
- package/docs/resolveProviders.mjs.html +189 -0
- package/docs/wkf_callAiWithFallback.mjs.html +22 -11
- package/docs/wkf_extractJsonLoose.mjs.html +2 -2
- package/docs/wkf_runFanout.mjs.html +7 -7
- package/docs/wkf_runFanoutPipeline.mjs.html +7 -7
- package/docs/wkf_runRolePipeline.mjs.html +6 -6
- package/g.mjs +30 -23
- package/package.json +1 -1
- package/src/WDispatchAi.mjs +6 -2
- package/src/adapters.mjs +34 -0
- package/src/dfTimeoutMs.mjs +26 -0
- package/src/dispatchAiFallback.mjs +53 -14
- package/src/dispatchAiWkf.mjs +40 -6
- package/src/dispatchAntigravity.mjs +21 -10
- package/src/dispatchApiOpenaiCompat.mjs +38 -4
- package/src/dispatchClaude.mjs +15 -2
- package/src/dispatchCodex.mjs +14 -1
- package/src/dispatchOpencode.mjs +14 -1
- package/src/providers.mjs +133 -0
- package/src/resolveProviders.mjs +117 -0
- package/src/wkf/callAiWithFallback.mjs +20 -9
- package/src/wkf/runFanout.mjs +5 -5
- package/src/wkf/runFanoutPipeline.mjs +5 -5
- package/src/wkf/runRolePipeline.mjs +4 -4
- package/test/tools/fakeServerForApiTest.mjs +14 -0
- package/test/unit-WDispatchAi.test.mjs +9 -3
- package/test/unit-dispatchAi.test.mjs +1 -1
- package/test/unit-dispatchAiFallback.test.mjs +25 -0
- package/test/unit-dispatchAntigravity.test.mjs +25 -5
- package/test/unit-dispatchApiOpenaiCompat.test.mjs +31 -0
- package/test/unit-providers.test.mjs +66 -0
- package/test/unit-resolveProviders.test.mjs +85 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>dfTimeoutMs.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">dfTimeoutMs.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>// dfTimeoutMs.mjs — 全套件統一之預設逾時毫秒(單一來源)
|
|
49
|
+
//
|
|
50
|
+
// 【為何統一】各轉接器與各層若各有預設(曾為CLI 120s/agy 300s/api 120s),
|
|
51
|
+
// 呼叫方難以理解為何不一致; 統一後呼叫方只需記一個數字, 要改就由opt傳入覆寫。
|
|
52
|
+
//
|
|
53
|
+
// 【為何取300000(5分鐘)】對齊agy自身print-timeout之預設5m0s;
|
|
54
|
+
// agy為agent型CLI, 實測合法執行可達116秒, 統一成120秒會誤殺;
|
|
55
|
+
// 快速任務有需要可自行下調, 複雜任務(如單一AI工作15分鐘)依README之Timeout規劃上調。
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 全套件統一之預設逾時毫秒
|
|
60
|
+
*
|
|
61
|
+
* @returns {Number} 回傳預設逾時毫秒整數300000(5分鐘)
|
|
62
|
+
* @example
|
|
63
|
+
*
|
|
64
|
+
* import dfTimeoutMs from './src/dfTimeoutMs.mjs'
|
|
65
|
+
*
|
|
66
|
+
* console.log(dfTimeoutMs)
|
|
67
|
+
* // => 300000
|
|
68
|
+
*
|
|
69
|
+
*/
|
|
70
|
+
let dfTimeoutMs = 300000
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
export default dfTimeoutMs
|
|
74
|
+
</code></pre>
|
|
75
|
+
</article>
|
|
76
|
+
</section>
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<br class="clear">
|
|
86
|
+
|
|
87
|
+
<footer>
|
|
88
|
+
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.
|
|
89
|
+
</footer>
|
|
90
|
+
|
|
91
|
+
<script>prettyPrint();</script>
|
|
92
|
+
<script src="scripts/polyfill.js"></script>
|
|
93
|
+
<script src="scripts/linenumber.js"></script>
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
</body>
|
|
98
|
+
</html>
|
package/docs/dispatchAi.mjs.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
|
|
|
@@ -120,7 +120,7 @@ export default dispatchAi
|
|
|
120
120
|
<br class="clear">
|
|
121
121
|
|
|
122
122
|
<footer>
|
|
123
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
123
|
+
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.
|
|
124
124
|
</footer>
|
|
125
125
|
|
|
126
126
|
<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
|
|
|
@@ -55,6 +55,7 @@ import ispint from 'wsemi/src/ispint.mjs'
|
|
|
55
55
|
import cint from 'wsemi/src/cint.mjs'
|
|
56
56
|
import dispatchAi from './dispatchAi.mjs'
|
|
57
57
|
import getErrorResult from './getErrorResult.mjs'
|
|
58
|
+
import dfTimeoutMs from './dfTimeoutMs.mjs'
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
// dispatchAiFallback.mjs — 多供應商自動遞補層
|
|
@@ -75,6 +76,34 @@ import getErrorResult from './getErrorResult.mjs'
|
|
|
75
76
|
//
|
|
76
77
|
// 【時間預算】budgetMs限制整輪遞補的總時長, 剩餘預算會壓進每次呼叫的timeoutMs,
|
|
77
78
|
// 防止多家連續卡逾時而撞破外部排程的執行上限。
|
|
79
|
+
//
|
|
80
|
+
// ══ 條目id之設計規則(呼叫端負責, 本套件不解讀其內容) ══
|
|
81
|
+
//
|
|
82
|
+
// id於本套件內只有兩個用途: 游標的物件鍵(state.cursors[id])與日誌標籤
|
|
83
|
+
// (providerId、keyId=`${id}#${keyIndex}`)。不查表、不比對、無格式要求,
|
|
84
|
+
// 純粹是呼叫端的命名空間——故「什麼算同一個供應商」由呼叫端定義, 本套件不猜。
|
|
85
|
+
//
|
|
86
|
+
// ① id須能區分到「模型」而非只到「廠商」
|
|
87
|
+
// ✗ id:'claude' —— 日後要同時掛sonnet與opus就無法並存, 且日誌看不出用了哪個模型
|
|
88
|
+
// ✓ id:'claude:sonnet' / id:'claude:opus'
|
|
89
|
+
//
|
|
90
|
+
// ② 同一模型經不同路徑取得時, id須帶上路徑, 且前綴用「具體路徑名」不用泛稱
|
|
91
|
+
// 同一個laguna可經Poolside官方REST、OpenRouter、opencode CLI三條路,
|
|
92
|
+
// 三者額度池與故障域各自獨立, 屬三個供應商:
|
|
93
|
+
// ✓ 'poolside:laguna-s-2.1' / 'or:poolside/laguna-s-2.1:free' / 'oc:poolside/poolside/laguna-s-2.1'
|
|
94
|
+
// ✗ 'api:laguna-s-2.1' —— 泛稱api:在同模型有多個REST閘道時會撞名, 且日誌看不出走哪個閘道
|
|
95
|
+
// 慣用前綴: CLI類=oc:/agy:/claude:/codex:(即kind或CLI名); REST類=閘道名(zen:/agnes:/poolside:/or:/nv:)
|
|
96
|
+
//
|
|
97
|
+
// ③ id務必給且務必唯一
|
|
98
|
+
// 未給時本套件回退為「陣列索引字串」——索引是位置不是身分, 日後於鏈中插入條目
|
|
99
|
+
// 會讓後續條目繼承他人的游標進度(輪替張冠李戴), 故正式設定一律明給。
|
|
100
|
+
// 兩個條目同id則共用同一游標且日誌無法區分, 屬設定錯誤。
|
|
101
|
+
//
|
|
102
|
+
// ④ 同一組金鑰用於多個條目時, 各條目游標獨立
|
|
103
|
+
// 例如agnes的CLI版與REST版共用同一批金鑰時, 兩者各自從游標起點輪替,
|
|
104
|
+
// 同一把金鑰可能被連續使用而另一把閒置(帳號額度未均攤)。
|
|
105
|
+
// 要讓它們共享輪替進度就給相同id(代價: 日誌無法區分兩者);
|
|
106
|
+
// 要能區分就分開命名(代價: 額度不均攤)。此取捨由呼叫端依實際需求決定。
|
|
78
107
|
|
|
79
108
|
|
|
80
109
|
//fallback層自用之設定鍵, 其餘鍵作為各attempt之共用預設原樣轉傳
|
|
@@ -87,7 +116,7 @@ let ENTRY_KEYS = ['id', 'keys']
|
|
|
87
116
|
|
|
88
117
|
//預設值
|
|
89
118
|
let DEFAULT_MIN_ATTEMPT_MS = 20000
|
|
90
|
-
let DEFAULT_TIMEOUT_MS =
|
|
119
|
+
let DEFAULT_TIMEOUT_MS = dfTimeoutMs //全套件統一預設300000
|
|
91
120
|
|
|
92
121
|
|
|
93
122
|
//memoryState, 未注入store時之行程內預設狀態(跨呼叫有效, 重啟歸零)
|
|
@@ -153,16 +182,16 @@ function isKeyIndependentFail(r) {
|
|
|
153
182
|
* @param {String} prompt 輸入提示詞字串,一律以stdin傳入子進程
|
|
154
183
|
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
155
184
|
* @param {Array} opt.providers 輸入供應商條目物件陣列,順序即優先序。各條目除下列鍵外,其餘鍵(kind、model、exe、provider、config、sandbox、timeoutMs等)即該條目之opt原樣透傳對應轉接器
|
|
156
|
-
* @param {String} [opt.providers[].id=條目索引字串]
|
|
185
|
+
* @param {String} [opt.providers[].id=條目索引字串] 輸入群組識別字串,游標以此為鍵、亦為日誌標籤,本套件不解讀其內容。須區分到「模型」而非只到「廠商」(如'claude:sonnet'而非'claude'),同一模型經不同路徑取得時須帶上路徑(如'poolside:laguna-s-2.1'與'or:poolside/laguna-s-2.1:free'),且務必唯一。省略時回退為陣列索引字串——索引是位置不是身分,日後插入條目會令後續條目繼承他人游標進度,故正式設定一律明給。詳見本檔檔頭之id設計規則
|
|
157
186
|
* @param {Array} [opt.providers[].keys=[]] 輸入同一服務之多把API key字串陣列,逐次注入輪替(kind為opencode時須同時於條目給予provider),省略代表沿用CLI既有登入狀態之單一虛擬金鑰
|
|
158
187
|
* @param {Number} [opt.budgetMs=null] 輸入整輪遞補之時間上限毫秒正整數,剩餘預算會壓進每次呼叫之timeoutMs,預設null代表不限
|
|
159
188
|
* @param {Number} [opt.minAttemptMs=20000] 輸入單次嘗試之最低剩餘預算毫秒正整數,剩餘低於此值即停止嘗試回報budget exhausted,預設20000
|
|
160
189
|
* @param {Object} [opt.store=null] 輸入狀態持久化物件{get:()=>state,set:(state)=>{}},state內含cursors(逐群組游標),省略代表用行程內記憶體(跨呼叫有效,重啟歸零)。假定單行程序列調用,並行請自行加鎖
|
|
161
|
-
* @param {Function} [opt.onEvent=null] 輸入事件回調函數(ev)=>{},ev.type可為'try'、'ok'、'next-key'、'skip-group'、'budget-out'
|
|
162
|
-
* @param {Number} [opt.timeoutMs=
|
|
190
|
+
* @param {Function} [opt.onEvent=null] 輸入事件回調函數(ev)=>{},ev.type可為'try'、'ok'、'next-key'、'skip-group'、'budget-out';失敗事件(next-key/skip-group)另帶stdout(被拒回覆)與stderr(錯誤輸出)供診斷,兩者於失敗路徑已由轉接器截斷;回調拋出例外不影響主流程,預設null
|
|
191
|
+
* @param {Number} [opt.timeoutMs=300000] 輸入各attempt共用之逾時毫秒正整數,條目可覆寫,全套件統一預設300000
|
|
163
192
|
* @param {String|Function} [opt.validate=undefined] 輸入各attempt共用之stdout驗證規則,條目可覆寫,預設undefined
|
|
164
193
|
* @param {Number} [opt.maxRetries=0] 輸入各attempt共用之同家重試次數非負整數,韌性建議交給換家而非重試同一家,預設0
|
|
165
|
-
* @returns {Promise} 回傳Promise,resolve回傳結果物件,除execCli既有欄位(ok、stdout、stderr、code、error、durationMs、attempts、pid)外,追加providerId(實際使用之群組)、keyIndex(實際使用之金鑰索引,無keys時為null)、kind、model、tried(
|
|
194
|
+
* @returns {Promise} 回傳Promise,resolve回傳結果物件,除execCli既有欄位(ok、stdout、stderr、code、error、durationMs、attempts、pid)外,追加providerId(實際使用之群組)、keyIndex(實際使用之金鑰索引,無keys時為null)、kind、model、tried(全部嘗試歷程陣列,成功時亦回傳;失敗項含stdout與stderr供診斷被拒原因),本函數不會reject
|
|
166
195
|
* @example
|
|
167
196
|
* //need opencode, claude, codex cli in system PATH
|
|
168
197
|
*
|
|
@@ -173,21 +202,29 @@ function isKeyIndependentFail(r) {
|
|
|
173
202
|
* let r = await dispatchAiFallback('請只回覆兩個字:完成', {
|
|
174
203
|
* providers: [
|
|
175
204
|
* {
|
|
176
|
-
* id
|
|
205
|
+
* //id區分到模型且帶路徑: 同一模型經REST與CLI取得屬兩個供應商
|
|
206
|
+
* id: 'zen:deepseek-v4-flash-free',
|
|
207
|
+
* kind: 'api-openai-compat',
|
|
208
|
+
* baseURL: 'https://opencode.ai/zen/v1',
|
|
209
|
+
* model: 'deepseek-v4-flash-free',
|
|
210
|
+
* keys: ['sk-aaa', 'sk-bbb'], //多把金鑰, 某把失敗自動換下一把
|
|
211
|
+
* },
|
|
212
|
+
* {
|
|
213
|
+
* id: 'oc:opencode/deepseek-v4-flash-free', //同一模型之CLI版(有工具, 較慢)
|
|
177
214
|
* kind: 'opencode',
|
|
178
215
|
* model: 'opencode/deepseek-v4-flash-free',
|
|
179
216
|
* provider: 'opencode',
|
|
180
|
-
* keys: ['sk-aaa', 'sk-bbb'],
|
|
217
|
+
* keys: ['sk-aaa', 'sk-bbb'],
|
|
181
218
|
* timeoutMs: 180000,
|
|
182
219
|
* },
|
|
183
|
-
* { id: 'claude', kind: 'claude', model: 'sonnet' },
|
|
184
|
-
* { id: 'codex', kind: 'codex', model: 'gpt-5.6-luna', sandbox: 'read-only' },
|
|
220
|
+
* { id: 'claude:sonnet', kind: 'claude', model: 'sonnet' }, //以上全敗時遞補
|
|
221
|
+
* { id: 'codex:gpt-5.6-luna', kind: 'codex', model: 'gpt-5.6-luna', sandbox: 'read-only' },
|
|
185
222
|
* ],
|
|
186
223
|
* budgetMs: 600000,
|
|
187
224
|
* onEvent: (ev) => console.log(ev.type, ev.providerId, ev.keyIndex),
|
|
188
225
|
* })
|
|
189
226
|
* console.log(r.ok, r.providerId, r.keyIndex, r.tried.length)
|
|
190
|
-
* // => true 'deepseek' 0 1
|
|
227
|
+
* // => true 'zen:deepseek-v4-flash-free' 0 1
|
|
191
228
|
*
|
|
192
229
|
* }
|
|
193
230
|
* await test()
|
|
@@ -355,18 +392,20 @@ async function dispatchAiFallback(prompt, opt = {}) {
|
|
|
355
392
|
//失敗分流
|
|
356
393
|
lastResult = r
|
|
357
394
|
lastMeta = { providerId: id, keyIndex, kind, model }
|
|
395
|
+
//失敗事件與tried一併帶被拒回覆(stdout)與錯誤輸出(stderr), 供呼叫端診斷失敗原因
|
|
396
|
+
//(如驗證失敗時模型究竟回了什麼); 兩者於失敗路徑已由轉接器截斷(≤500/1000字元), 不會過大
|
|
358
397
|
if (isKeyIndependentFail(r)) {
|
|
359
398
|
|
|
360
399
|
//與金鑰無關, 整組跳過
|
|
361
|
-
emit({ type: 'skip-group', providerId: id, keyIndex, keyId, error: r.error })
|
|
362
|
-
tried.push({ providerId: id, keyIndex, keyId, outcome: 'skip-group', error: r.error, durationMs: r.durationMs })
|
|
400
|
+
emit({ type: 'skip-group', providerId: id, keyIndex, keyId, error: r.error, stdout: r.stdout, stderr: r.stderr })
|
|
401
|
+
tried.push({ providerId: id, keyIndex, keyId, outcome: 'skip-group', error: r.error, stdout: r.stdout, stderr: r.stderr, durationMs: r.durationMs })
|
|
363
402
|
skipGroup = true
|
|
364
403
|
}
|
|
365
404
|
else {
|
|
366
405
|
|
|
367
406
|
//其餘(含額度上限/金鑰無效/未分類), 換組內下一把, 不記憶不停用
|
|
368
|
-
emit({ type: 'next-key', providerId: id, keyIndex, keyId, error: r.error })
|
|
369
|
-
tried.push({ providerId: id, keyIndex, keyId, outcome: 'next-key', error: r.error, durationMs: r.durationMs })
|
|
407
|
+
emit({ type: 'next-key', providerId: id, keyIndex, keyId, error: r.error, stdout: r.stdout, stderr: r.stderr })
|
|
408
|
+
tried.push({ providerId: id, keyIndex, keyId, outcome: 'next-key', error: r.error, stdout: r.stdout, stderr: r.stderr, durationMs: r.durationMs })
|
|
370
409
|
}
|
|
371
410
|
|
|
372
411
|
}
|
|
@@ -393,7 +432,7 @@ export default dispatchAiFallback
|
|
|
393
432
|
<br class="clear">
|
|
394
433
|
|
|
395
434
|
<footer>
|
|
396
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
435
|
+
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.
|
|
397
436
|
</footer>
|
|
398
437
|
|
|
399
438
|
<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
|
|
|
@@ -64,6 +64,32 @@ import runFanoutPipeline from './wkf/runFanoutPipeline.mjs'
|
|
|
64
64
|
//
|
|
65
65
|
// 【本函數為同步工廠會throw】providers無效屬設定錯誤, 應於啟動期即失敗(fail fast),
|
|
66
66
|
// 與各dispatch函數「不reject」之約定不衝突——後者是執行期呼叫, 前者是組裝期設定。
|
|
67
|
+
//
|
|
68
|
+
// 【定義表之鍵名即條目id】該鍵名會成為dispatchAiFallback之條目id(游標鍵與日誌標籤),
|
|
69
|
+
// 須區分到「模型」而非只到「廠商」——鍵名取'claude'則日後無法同時掛sonnet與opus,
|
|
70
|
+
// 且日誌看不出實際用了哪個模型; 同一模型經不同路徑(REST/CLI/不同閘道)取得時,
|
|
71
|
+
// 額度池與故障域各自獨立而屬不同供應商, 鍵名須帶上路徑加以區分。
|
|
72
|
+
// 命名規則與取捨詳見dispatchAiFallback.mjs檔頭之「條目id之設計規則」。
|
|
73
|
+
//
|
|
74
|
+
// 【timeout速覽】(完整說明見README之「Timeout 總覽」)
|
|
75
|
+
// 單次AI嘗試: timeoutMs, 全套件統一預設300000(5分鐘, 單一來源dfTimeoutMs.mjs),
|
|
76
|
+
// 直接呼叫轉接器與工作流內皆同一數字;
|
|
77
|
+
// 單一名額(遞補鏈): budgetMs, 預設null不限; minAttemptMs開工門檻預設20000(無budget時不作用);
|
|
78
|
+
// 工作流總時長: 無獨立參數(刻意)——由結構推導: Fanout≈最慢名額+整合(並行),
|
|
79
|
+
// RolePipeline≈Σ各階段(序列); 要上限就對每名額設budgetMs。
|
|
80
|
+
// 最壞情況公式: 名額≤K×timeoutMs(K=鏈組數, 逾時每組只燒一次即跳組)。
|
|
81
|
+
// 調整四層(細者覆蓋粗者): defaults(此處) → 各工作流callOpt → 階段/名額規格 → provider條目。
|
|
82
|
+
//
|
|
83
|
+
// 【定義providers時如何選kind: CLI或API】判準是「該階段需不需要工具」:
|
|
84
|
+
// 需要讀本機檔案、grep、執行指令、抓網頁 → CLI類kind(opencode/claude/codex/antigravity);
|
|
85
|
+
// 純文字生成(素材皆已在prompt內) → API類kind(api-openai-compat), 免安裝免登入且較快。
|
|
86
|
+
// 工作流常態是混用: runFanout之候選生成與整合、runRolePipeline之審計修訂等
|
|
87
|
+
// 多屬純文字階段可走API; 唯獨需要實際翻閱專案檔案的階段必須走CLI。
|
|
88
|
+
// API類不支援工具且不會自建工具迴圈, 理由詳見adapters.mjs檔頭之選型判準區塊。
|
|
89
|
+
//
|
|
90
|
+
// 【工具無法向上層轉送】工作流各名額(如runFanout之agents)只是同行程之async函數呼叫,
|
|
91
|
+
// 非獨立agent; 模型回傳之tool_calls受會話束縛而無法外傳給上層agent(如hermes)代跑,
|
|
92
|
+
// 故「讓外殼提供工具給工作流內的模型使用」在本架構下不成立——需要工具就選CLI類kind。
|
|
67
93
|
|
|
68
94
|
|
|
69
95
|
/**
|
|
@@ -83,11 +109,15 @@ import runFanoutPipeline from './wkf/runFanoutPipeline.mjs'
|
|
|
83
109
|
*
|
|
84
110
|
* import dispatchAiWkf from './src/dispatchAiWkf.mjs'
|
|
85
111
|
*
|
|
112
|
+
* //定義表之鍵名即dispatchAiFallback之條目id, 須區分到模型而非只到廠商,
|
|
113
|
+
* //同一模型經不同路徑取得時須帶上路徑(REST與CLI屬兩個供應商, 能力與速度皆不同)
|
|
86
114
|
* let wkf = dispatchAiWkf({
|
|
87
115
|
* providers: {
|
|
88
|
-
* 'deepseek': { kind: 'opencode', model: '
|
|
89
|
-
* '
|
|
90
|
-
* '
|
|
116
|
+
* 'zen:deepseek-v4-flash-free': { kind: 'api-openai-compat', baseURL: 'https://opencode.ai/zen/v1', model: 'deepseek-v4-flash-free', keys: ['sk-xxx'] },
|
|
117
|
+
* 'oc:opencode/deepseek-v4-flash-free': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
|
|
118
|
+
* 'claude:sonnet': { kind: 'claude', model: 'sonnet' },
|
|
119
|
+
* 'claude:opus': { kind: 'claude', model: 'opus' },
|
|
120
|
+
* 'codex:gpt-5.6-luna': { kind: 'codex', model: 'gpt-5.6-luna' },
|
|
91
121
|
* },
|
|
92
122
|
* defaults: { timeoutMs: 300000 },
|
|
93
123
|
* })
|
|
@@ -95,15 +125,19 @@ import runFanoutPipeline from './wkf/runFanoutPipeline.mjs'
|
|
|
95
125
|
* let test = async () => {
|
|
96
126
|
*
|
|
97
127
|
* //單一名額: 主模型+遞補鏈
|
|
98
|
-
* let r1 = await wkf.callAi('只回覆JSON: {"a":1}', { spec: { use: 'deepseek', fallback: ['sonnet'] }, check: (j) => j.a === 1 })
|
|
128
|
+
* let r1 = await wkf.callAi('只回覆JSON: {"a":1}', { spec: { use: 'zen:deepseek-v4-flash-free', fallback: ['claude:sonnet'] }, check: (j) => j.a === 1 })
|
|
99
129
|
* console.log(r1.ok, r1.json)
|
|
100
130
|
* // => true { a: 1 }
|
|
101
131
|
*
|
|
102
132
|
* //Fanout工作流: 多開執行+單點整合
|
|
133
|
+
* //純文字階段用REST(快), 需要讀專案檔案之階段才用CLI(有工具)
|
|
103
134
|
* let r2 = await wkf.runFanout({
|
|
104
135
|
* task: '分析並只回覆JSON: {"essence":"..."}',
|
|
105
|
-
* agents: [
|
|
106
|
-
*
|
|
136
|
+
* agents: [
|
|
137
|
+
* { use: 'zen:deepseek-v4-flash-free', fallback: ['claude:sonnet'] },
|
|
138
|
+
* { use: 'claude:sonnet' },
|
|
139
|
+
* ],
|
|
140
|
+
* integrate: { use: 'codex:gpt-5.6-luna' },
|
|
107
141
|
* check: (j) => !!j.essence,
|
|
108
142
|
* })
|
|
109
143
|
* console.log(r2.ok, r2.integrated)
|
|
@@ -159,7 +193,7 @@ export default dispatchAiWkf
|
|
|
159
193
|
<br class="clear">
|
|
160
194
|
|
|
161
195
|
<footer>
|
|
162
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
196
|
+
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.
|
|
163
197
|
</footer>
|
|
164
198
|
|
|
165
199
|
<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
|
|
|
@@ -55,6 +55,7 @@ import cint from 'wsemi/src/cint.mjs'
|
|
|
55
55
|
import execCli from 'wsemi/src/execCli.mjs'
|
|
56
56
|
import getCliArgs from './getCliArgs.mjs'
|
|
57
57
|
import getErrorResult from './getErrorResult.mjs'
|
|
58
|
+
import dfTimeoutMs from './dfTimeoutMs.mjs'
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
// dispatchAntigravity.mjs — 以Google Antigravity CLI(agy)呼叫AI模型
|
|
@@ -84,7 +85,7 @@ import getErrorResult from './getErrorResult.mjs'
|
|
|
84
85
|
|
|
85
86
|
//預設值
|
|
86
87
|
let DEFAULT_EXE = 'agy'
|
|
87
|
-
let DEFAULT_TIMEOUT_MS = 300000
|
|
88
|
+
let DEFAULT_TIMEOUT_MS = dfTimeoutMs //全套件統一預設300000(恰對齊agy自身print-timeout預設5m0s)
|
|
88
89
|
let MAX_PROMPT_LENGTH = 30000 //命令列上限32767扣除exe路徑與旗標後之保守值
|
|
89
90
|
let PRINT_TIMEOUT_BUFFER_S = 30
|
|
90
91
|
let MIN_PRINT_TIMEOUT_S = 30
|
|
@@ -115,10 +116,10 @@ let OWN_KEYS = ['exe', 'model', 'effort', 'skipPermissions', 'printTimeout', 'ad
|
|
|
115
116
|
* @param {String} [opt.effort=''] 輸入推理深度字串,可選'low'、'medium'、'high',需agy>=1.1.11,建議搭配不帶檔位之基礎slug;與帶檔位slug併用且檔位不一致時agy回conflicts錯誤,預設''代表不帶
|
|
116
117
|
* @param {Boolean} [opt.skipPermissions=true] 輸入是否帶`--dangerously-skip-permissions`旗標布林值,false代表保留CLI權限閘門,預設true
|
|
117
118
|
* @param {String} [opt.printTimeout=''] 輸入agy自身等待上限字串(如'10m'、'570s'),預設''代表由timeoutMs推導(扣30秒緩衝,下限30秒)
|
|
118
|
-
* @param {Array} [opt.addDirs
|
|
119
|
+
* @param {Array} [opt.addDirs=自動納入cwd] 輸入加入workspace之目錄字串陣列,逐項展開為`--add-dir`。agy以自身scratch目錄為工作區而不採子進程cwd,故未給本參數時自動納入有效cwd令檔案可視範圍與其他CLI轉接器一致;明示給陣列(含空陣列[]代表不揭露任何目錄)則完全尊重呼叫端
|
|
119
120
|
* @param {Array} [opt.extraArgs=[]] 輸入額外命令列旗標字串陣列(如--output-format、--json-schema、--mode),將接於固定旗標之後、`--print`之前,預設[]
|
|
120
|
-
* @param {Number} [opt.timeoutMs=300000]
|
|
121
|
-
* @param {String} [opt.cwd=process.cwd()] 輸入子進程工作目錄字串,預設process.cwd()
|
|
121
|
+
* @param {Number} [opt.timeoutMs=300000] 輸入逾時毫秒正整數,逾時將強制關閉子進程及其子孫程序,全套件統一預設300000(恰對齊agy自身print-timeout預設5m0s)
|
|
122
|
+
* @param {String} [opt.cwd=process.cwd()] 輸入子進程工作目錄字串,預設process.cwd()。注意本參數不影響agy之檔案可視範圍(agy以自身scratch目錄為工作區),可視範圍由addDirs決定(未給addDirs時自動納入本目錄)
|
|
122
123
|
* @param {String|Function} [opt.validate=undefined] 輸入stdout驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證
|
|
123
124
|
* @param {Number} [opt.maxRetries=0] 輸入失敗後最大重試次數非負整數,預設0
|
|
124
125
|
* @returns {Promise} 回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject
|
|
@@ -179,7 +180,7 @@ async function dispatchAntigravity(prompt, opt = {}) {
|
|
|
179
180
|
skipPermissions = true
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
//timeoutMs, 先行取值以供printTimeout推導,
|
|
183
|
+
//timeoutMs, 先行取值以供printTimeout推導, 無效回退全套件統一預設300000
|
|
183
184
|
let timeoutMs = get(opt, 'timeoutMs', null)
|
|
184
185
|
if (!ispint(timeoutMs)) {
|
|
185
186
|
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
@@ -195,13 +196,23 @@ async function dispatchAntigravity(prompt, opt = {}) {
|
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
//addDirs, 逐項展開為--add-dir(agy該旗標可重複)
|
|
199
|
+
//未給時自動納入有效cwd(明給的或預設process.cwd()): agy以自身scratch目錄為工作區,
|
|
200
|
+
//不採子進程之cwd, 僅--add-dir能擴其檔案可視範圍——僅給cwd時弱模型直接回「找不到檔案」、
|
|
201
|
+
//強模型得自行摸索(實測116s vs 帶--add-dir僅6s), 且兩者皆ok:true屬靜默失敗,
|
|
202
|
+
//極易被誤判為模型能力不足(2026-08-13以隨機token實測確認)。
|
|
203
|
+
//明示addDirs(含空陣列[]代表不揭露任何目錄)則完全尊重呼叫端, 不自動加入
|
|
198
204
|
let addDirs = get(opt, 'addDirs', null)
|
|
205
|
+
if (!isarr(addDirs)) {
|
|
206
|
+
let cwdEff = get(opt, 'cwd', null)
|
|
207
|
+
if (!isestr(cwdEff)) {
|
|
208
|
+
cwdEff = process.cwd()
|
|
209
|
+
}
|
|
210
|
+
addDirs = [cwdEff]
|
|
211
|
+
}
|
|
199
212
|
let addDirArgs = []
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
addDirArgs.push('--add-dir', d)
|
|
204
|
-
}
|
|
213
|
+
for (let d of addDirs) {
|
|
214
|
+
if (isestr(d)) {
|
|
215
|
+
addDirArgs.push('--add-dir', d)
|
|
205
216
|
}
|
|
206
217
|
}
|
|
207
218
|
|
|
@@ -251,7 +262,7 @@ export default dispatchAntigravity
|
|
|
251
262
|
<br class="clear">
|
|
252
263
|
|
|
253
264
|
<footer>
|
|
254
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
265
|
+
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.
|
|
255
266
|
</footer>
|
|
256
267
|
|
|
257
268
|
<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
|
|
|
@@ -58,6 +58,7 @@ import strleft from 'wsemi/src/strleft.mjs'
|
|
|
58
58
|
import strdelleft from 'wsemi/src/strdelleft.mjs'
|
|
59
59
|
import strTruncate from 'wsemi/src/strTruncate.mjs'
|
|
60
60
|
import getErrorResult from './getErrorResult.mjs'
|
|
61
|
+
import dfTimeoutMs from './dfTimeoutMs.mjs'
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
// dispatchApiOpenaiCompat.mjs — 以fetch直呼OpenAI相容API(chat/completions)
|
|
@@ -74,6 +75,19 @@ import getErrorResult from './getErrorResult.mjs'
|
|
|
74
75
|
// 能力(不讀檔不跑指令), 天然無寫檔風險。
|
|
75
76
|
// 注意: claude與codex走訂閱帳號登入態而非API金鑰, 無法比照, 仍須CLI轉接器。
|
|
76
77
|
//
|
|
78
|
+
// 【本轉接器不支援工具, 需要工具請改用CLI類kind(2026-08-11實測後之決策)】
|
|
79
|
+
// 閘道端零內建工具: 實測Zen與Agnes皆對`tools:[{type:'web_search'}]`回400並要求
|
|
80
|
+
// function.parameters, 即只接受「呼叫端自行定義且自行執行」之function工具;
|
|
81
|
+
// 協定層雖支援function calling(Zen之nemotron-3-ultra-free與Agnes皆實測回
|
|
82
|
+
// finish_reason:'tool_calls'且tool_calls格式標準), 但工具之定義、執行、錯誤處理與
|
|
83
|
+
// 安全邊界全須本套件自行實作與維護, 等同重造CLI已提供之harness, 故不做。
|
|
84
|
+
// 又tool_calls有會話束縛(tool_call_id須於同一條messages串內回填, 且須保留前文),
|
|
85
|
+
// 該messages串活在本函數單次呼叫之生命週期內, 無法暫停後跨行程外傳給上層agent代跑
|
|
86
|
+
// ——工作流是被上層阻塞呼叫的函式, 沒有反向請求工具的通道; 同理工作流(如runFanout)
|
|
87
|
+
// 之各名額亦只是同行程之async函數呼叫, 無法把tool_calls往上層轉送。
|
|
88
|
+
// 故呼叫端若於body帶入tools, 本函數一律以TOOL_CALLS_UNSUPPORTED回報失敗而不假裝成功
|
|
89
|
+
// (實測Agnes於tool_calls時content為"\n\n"而非null, 不特別處理會靜默回傳空白內容)。
|
|
90
|
+
//
|
|
77
91
|
// 【重試語意對齊execCli】4xx(429除外)為客戶端錯誤不可重試而立即中止;
|
|
78
92
|
// 429/5xx/網路錯誤/逾時依maxRetries線性退避重試(間隔retryDelayMs*次數, 上限15000ms)。
|
|
79
93
|
//
|
|
@@ -84,7 +98,7 @@ import getErrorResult from './getErrorResult.mjs'
|
|
|
84
98
|
|
|
85
99
|
|
|
86
100
|
//預設值
|
|
87
|
-
let DEFAULT_TIMEOUT_MS =
|
|
101
|
+
let DEFAULT_TIMEOUT_MS = dfTimeoutMs //全套件統一預設300000
|
|
88
102
|
let DEFAULT_RETRY_DELAY_MS = 5000
|
|
89
103
|
let MAX_RETRY_DELAY_MS = 15000
|
|
90
104
|
|
|
@@ -231,13 +245,31 @@ async function callOnce(url, headers, body, timeoutMs, validator) {
|
|
|
231
245
|
}
|
|
232
246
|
}
|
|
233
247
|
|
|
234
|
-
//取出choices[0]
|
|
248
|
+
//取出choices[0]
|
|
235
249
|
let content = null
|
|
250
|
+
let finishReason = ''
|
|
251
|
+
let toolCalls = null
|
|
236
252
|
try {
|
|
237
253
|
let j = JSON.parse(txt)
|
|
238
254
|
content = get(j, 'choices.0.message.content', null)
|
|
255
|
+
finishReason = get(j, 'choices.0.finish_reason', '')
|
|
256
|
+
toolCalls = get(j, 'choices.0.message.tool_calls', null)
|
|
239
257
|
}
|
|
240
258
|
catch {}
|
|
259
|
+
|
|
260
|
+
//tool_calls, 本轉接器不支援工具迴圈(見檔頭), 明確回報而不假裝成功
|
|
261
|
+
//(Agnes於tool_calls時content為"\n\n"非null, 不攔截會靜默回傳空白內容)
|
|
262
|
+
if (finishReason === 'tool_calls' || (toolCalls !== null && toolCalls !== undefined)) {
|
|
263
|
+
return {
|
|
264
|
+
ok: false,
|
|
265
|
+
stdout: '',
|
|
266
|
+
stderr: strTruncate(txt, 1000, optTruncate),
|
|
267
|
+
code: res.status,
|
|
268
|
+
error: 'TOOL_CALLS_UNSUPPORTED: use a cli kind (opencode/claude/codex/antigravity) when tools are needed',
|
|
269
|
+
durationMs,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
241
273
|
if (content === null || content === undefined) {
|
|
242
274
|
return {
|
|
243
275
|
ok: false,
|
|
@@ -283,6 +315,8 @@ async function callOnce(url, headers, body, timeoutMs, validator) {
|
|
|
283
315
|
*
|
|
284
316
|
* 特點:
|
|
285
317
|
* 免安裝CLI、免預先登入,給baseURL+key+model即可呼叫(如OpenCode Zen、Agnes等OpenAI相容閘道);
|
|
318
|
+
* 僅供純文字生成(摘要、分析、改寫、產出JSON等素材已在prompt內之任務)——
|
|
319
|
+
* 需要讀本機檔案、grep、執行指令、抓網頁等工具能力時,請改用CLI類kind(opencode/claude/codex/antigravity);
|
|
286
320
|
* prompt走HTTP body,無命令列長度限制;
|
|
287
321
|
* 錯誤依HTTP狀態碼分流:4xx(429除外)為客戶端錯誤不重試,429/5xx/網路錯誤/逾時依maxRetries線性退避重試;
|
|
288
322
|
* 結果結構與逾時/驗證失敗之error字樣對齊execCli,可直接作為dispatchAi與dispatchAiFallback之kind('api-openai-compat')使用;
|
|
@@ -294,9 +328,9 @@ async function callOnce(url, headers, body, timeoutMs, validator) {
|
|
|
294
328
|
* @param {String} opt.model 輸入模型ID字串,例如'deepseek-v4-flash-free'(Zen之模型名不帶opencode/前綴)、'agnes-2.0-flash'
|
|
295
329
|
* @param {String} [opt.key=''] 輸入API key字串,以Bearer置於Authorization標頭,預設''代表不帶認證標頭
|
|
296
330
|
* @param {String} [opt.system=''] 輸入system提示詞字串,將以system角色置於messages首位,預設''代表不帶
|
|
297
|
-
* @param {Object} [opt.body={}] 輸入額外請求本體物件(如temperature、max_tokens、response_format),將併入預設body(同名鍵以此為準),預設{}
|
|
331
|
+
* @param {Object} [opt.body={}] 輸入額外請求本體物件(如temperature、max_tokens、response_format),將併入預設body(同名鍵以此為準),預設{}。注意本轉接器不支援工具,帶入tools而模型回tool_calls時一律以TOOL_CALLS_UNSUPPORTED回報失敗,需要工具請改用CLI類kind
|
|
298
332
|
* @param {Object} [opt.headers={}] 輸入額外請求標頭物件,預設{}
|
|
299
|
-
* @param {Number} [opt.timeoutMs=
|
|
333
|
+
* @param {Number} [opt.timeoutMs=300000] 輸入逾時毫秒正整數,逾時將中止請求(含回應串流讀取),全套件統一預設300000
|
|
300
334
|
* @param {String|Function} [opt.validate=undefined] 輸入回覆內容驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證
|
|
301
335
|
* @param {Number} [opt.maxRetries=0] 輸入失敗後最大重試次數非負整數,4xx(429除外)不重試,預設0
|
|
302
336
|
* @param {Number} [opt.retryDelayMs=5000] 輸入重試間隔毫秒正整數,實際間隔為retryDelayMs乘以重試次數且上限15000ms,預設5000
|
|
@@ -470,7 +504,7 @@ export default dispatchApiOpenaiCompat
|
|
|
470
504
|
<br class="clear">
|
|
471
505
|
|
|
472
506
|
<footer>
|
|
473
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
507
|
+
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.
|
|
474
508
|
</footer>
|
|
475
509
|
|
|
476
510
|
<script>prettyPrint();</script>
|