Global

Members

WDispatchAi

Description:
  • AI供應商分派

Source:

AI供應商分派

Example
詳見dispatchAi、dispatchAiFallback、dispatchAiWkf、dispatchOpencode、dispatchClaude、dispatchCodex、dispatchAntigravity、dispatchApiOpenaiCompat範例

adapters

Description:
  • 各AI供應商種類(kind)對CLI轉接器函數之對照表

    本對照表為kind之唯一來源,dispatchAi以其鍵值分派,WDispatchAi以其鍵名產生KINDS, 新增供應商時僅須於此加入一個鍵值對即可

Source:

各AI供應商種類(kind)對CLI轉接器函數之對照表

本對照表為kind之唯一來源,dispatchAi以其鍵值分派,WDispatchAi以其鍵名產生KINDS, 新增供應商時僅須於此加入一個鍵值對即可

Example
import adapters from './src/adapters.mjs'

console.log(Object.keys(adapters))
// => ['opencode', 'claude', 'codex', 'antigravity', 'api-openai-compat']

Methods

buildChain(providers, spec) → {Object}

Description:
  • 依providers定義表把「名稱規格」展開成dispatchAiFallback的providers陣列

Source:
Example
import { buildChain } from './src/wkf/callAiWithFallback.mjs'

let providers = { a: { kind: 'claude' }, b: { kind: 'codex' } }
console.log(buildChain(providers, { use: 'a', fallback: ['b', 'c'] }))
// => { chain: [ { id: 'a', kind: 'claude' }, { id: 'b', kind: 'codex' } ], missing: [ 'c' ] }
Parameters:
Name Type Description
providers Object

輸入定義表物件(名稱 → 條目)

spec Object

輸入名額規格物件{ use, fallback }

Returns:

回傳物件,內含chain(條目物件陣列,id一律用名稱)與missing(查無定義之名稱字串陣列)

Type
Object

buildValidator(rule) → {function|null}

Description:
  • 建立驗證函式(規則語法同execCli之validate)

Source:
Parameters:
Name Type Description
rule String | function

輸入驗證規則字串('nonempty'、'json'、'min:100', 逗號可串接)或自訂函式

Returns:

回傳驗證函式,無有效規則回傳null

Type
function | null

(async) callAiWithFallback(prompt, optopt) → {Promise}

Description:
  • 呼叫一個AI名額(主模型+自帶遞補鏈),回覆經parse+check驗證後回傳結構化結果

    特點: spec.use為主模型名稱、spec.fallback為遞補名稱陣列,依序展開為遞補鏈,名稱查無定義即回報錯誤(fail fast); parse+check接進遞補層之validate——非法回覆視為該家失敗而自動換下一家,不把壞結果帶回來; 預設掛防寫檔前綴(promptPrefix傳空字串可關閉); 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need cli in system PATH

import callAiWithFallback from './src/wkf/callAiWithFallback.mjs'

let providers = {
    'deepseek': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
    'sonnet': { kind: 'claude', model: 'sonnet' },
}

let test = async () => {

    let r = await callAiWithFallback('只回覆JSON: {"a":1}', {
        providers,
        spec: { use: 'deepseek', fallback: ['sonnet'] },
        check: (j) => j.a === 1,
    })
    console.log(r.ok, r.json, r.providerId)
    // => true { a: 1 } 'deepseek'

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
providers Object

輸入provider定義表物件(名稱 → dispatchAiFallback條目,條目內含kind、model、keys、exe、provider、config等)

spec Object

輸入名額規格物件{ use:'主模型名稱', fallback:['遞補名稱', ...] }

check function <optional>
null

輸入結果檢核函數(json)=>Boolean,預設null代表只要能解析出JSON即通過

parse function <optional>
extractJsonLoose

輸入回覆解析函數(stdout)=>Object|null,預設寬鬆JSON抽取

rawText Boolean <optional>
false

輸入是否以純文字模式運作布林值,true代表不解析JSON(json欄位為修剪後文字、check收文字),預設false

promptPrefix String <optional>
防寫檔約束

輸入prompt前綴字串,預設為防寫檔約束,傳''關閉

timeoutMs Number <optional>
300000

輸入單次嘗試逾時毫秒正整數,預設300000

budgetMs Number <optional>
null

輸入整條遞補鏈之時間預算毫秒正整數,預設null代表不限

maxRetries Number <optional>
0

輸入同家重試次數非負整數,預設0(韌性交給遞補;端點不穩偶發空回之模型可調高令同鍵重試)

cwd String <optional>
process.cwd()

輸入子進程工作目錄字串,預設process.cwd()

store Object <optional>
null

輸入游標持久化物件{get,set},預設null代表用行程內記憶體

onEvent function <optional>
null

輸入遞補層事件回調函數,預設null

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否取得可用結果布林值)、json(解析後物件,rawText模式下為文字)、providerId(實際使用之名稱)、keyIndex、keyId、ms(總耗時毫秒)、tried(遞補嘗試歷程陣列)、error(錯誤訊息字串),本函數不會reject

Type
Promise

(async) callOnce(url, headers, body, timeoutMs, validator) → {Promise}

Description:
  • 單次HTTP呼叫(內部使用, 不含重試邏輯)

Source:
Parameters:
Name Type Description
url String

輸入完整端點網址字串

headers Object

輸入請求標頭物件

body Object

輸入請求本體物件

timeoutMs Number

輸入逾時毫秒

validator function | null

輸入驗證函式

Returns:

回傳Promise,resolve回傳結果物件

Type
Promise

defaultIntegratePrompt(candidates, optopt) → {String}

Description:
  • 預設整合提示詞模板:把成功候選JSON併入整合任務

Source:
Parameters:
Name Type Attributes Default Description
candidates Array

輸入成功候選物件陣列

opt Object <optional>
{}

輸入設定物件(取schema作為輸出格式示意),預設{}

Returns:

回傳整合提示詞字串

Type
String

(async) dispatchAi(kind, prompt, optopt) → {Promise}

Description:
  • 依供應商種類(kind)分派至對應之CLI轉接器

    三種供應商的差異(2026-08-08於本機實測確認): opencode支援逐次注入金鑰(OPENCODE_AUTH_CONTENT),故可多把金鑰輪替; claude與codex則沿用CLI既有登入狀態,無逐次金鑰概念。 故「輪替」的單位是「供應商條目」而非單純的金鑰:一個條目即一組(kind, model, 可選的key/provider), 輪到誰就用誰的CLI與模型

Source:
Example
//need claude, codex or opencode cli in system PATH

import dispatchAi from './src/dispatchAi.mjs'

let test = async () => {

    let r = await dispatchAi('claude', '請只回覆兩個字:完成', { model: 'sonnet' })
    console.log(r.ok, r.stdout.trim())
    // => true '完成'

    let re = await dispatchAi('gemini', 'abc')
    console.log(re.ok, re.error)
    // => false 'unknown ai kind: "gemini" (available: opencode, claude, codex)'

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
kind String

輸入供應商種類字串,可選'opencode'、'claude'、'codex'

prompt String

輸入提示詞字串,一律以stdin傳入子進程

opt Object <optional>
{}

輸入設定物件,原樣轉傳對應轉接器,各轉接器可用設定詳見dispatchOpencode、dispatchClaude、dispatchCodex,預設{}

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

(async) dispatchAiFallback(prompt, optopt) → {Promise}

Description:
  • 依供應商清單順序自動遞補調用AI,組內多金鑰以游標輪替

    特點: providers陣列順序即優先序,排前面的先用; 條目本身即該次調用之opt(除id與keys外原樣透傳對應轉接器),與dispatchAi「條目直接當opt」同一約定; 條目給予keys(多把金鑰)時以游標輪替,某把失敗自動換下一把,全數失敗才遞補下一組; 與金鑰無關之失敗(逾時/執行檔不存在/參數錯誤/輸出未過驗證/未知kind)直接整組跳過,不逐把空耗; 跨次執行僅記憶游標(經store注入持久化),不設金鑰停用清單——額度視窗形態多樣(5小時滾動/逐時/逐日), 停用會把已恢復的金鑰閒置,而重探的代價僅一次快速失敗; 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need opencode, claude, codex cli in system PATH

import dispatchAiFallback from './src/dispatchAiFallback.mjs'

let test = async () => {

    let r = await dispatchAiFallback('請只回覆兩個字:完成', {
        providers: [
            {
                id: 'deepseek',
                kind: 'opencode',
                model: 'opencode/deepseek-v4-flash-free',
                provider: 'opencode',
                keys: ['sk-aaa', 'sk-bbb'], //多把金鑰, 某把失敗自動換下一把
                timeoutMs: 180000,
            },
            { id: 'claude', kind: 'claude', model: 'sonnet' }, //deepseek全敗時遞補
            { id: 'codex', kind: 'codex', model: 'gpt-5.6-luna', sandbox: 'read-only' },
        ],
        budgetMs: 600000,
        onEvent: (ev) => console.log(ev.type, ev.providerId, ev.keyIndex),
    })
    console.log(r.ok, r.providerId, r.keyIndex, r.tried.length)
    // => true 'deepseek' 0 1

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,一律以stdin傳入子進程

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
providers Array

輸入供應商條目物件陣列,順序即優先序。各條目除下列鍵外,其餘鍵(kind、model、exe、provider、config、sandbox、timeoutMs等)即該條目之opt原樣透傳對應轉接器

Properties
Name Type Attributes Default Description
id String <optional>
條目索引字串

輸入群組識別字串,游標以此為鍵,多金鑰條目應給予穩定id,預設為條目索引字串

keys Array <optional>
[]

輸入同一服務之多把API key字串陣列,逐次注入輪替(kind為opencode時須同時於條目給予provider),省略代表沿用CLI既有登入狀態之單一虛擬金鑰

budgetMs Number <optional>
null

輸入整輪遞補之時間上限毫秒正整數,剩餘預算會壓進每次呼叫之timeoutMs,預設null代表不限

minAttemptMs Number <optional>
20000

輸入單次嘗試之最低剩餘預算毫秒正整數,剩餘低於此值即停止嘗試回報budget exhausted,預設20000

store Object <optional>
null

輸入狀態持久化物件{get:()=>state,set:(state)=>{}},state內含cursors(逐群組游標),省略代表用行程內記憶體(跨呼叫有效,重啟歸零)。假定單行程序列調用,並行請自行加鎖

onEvent function <optional>
null

輸入事件回調函數(ev)=>{},ev.type可為'try'、'ok'、'next-key'、'skip-group'、'budget-out',回調拋出例外不影響主流程,預設null

timeoutMs Number <optional>
120000

輸入各attempt共用之逾時毫秒正整數,條目可覆寫,預設120000

validate String | function <optional>

輸入各attempt共用之stdout驗證規則,條目可覆寫,預設undefined

maxRetries Number <optional>
0

輸入各attempt共用之同家重試次數非負整數,韌性建議交給換家而非重試同一家,預設0

Returns:

回傳Promise,resolve回傳結果物件,除execCli既有欄位(ok、stdout、stderr、code、error、durationMs、attempts、pid)外,追加providerId(實際使用之群組)、keyIndex(實際使用之金鑰索引,無keys時為null)、kind、model、tried(全部嘗試歷程陣列,成功時亦回傳),本函數不會reject

Type
Promise

dispatchAiWkf(opt) → {Object}

Description:
  • 建立AI工作流執行環境(工廠),注入provider定義表與共用預設後回傳綁定版API

    特點: providers為名稱對dispatchAiFallback條目之定義表,之後各工作流以名稱宣告主模型與遞補鏈; defaults為共用呼叫設定,各工作流之callOpt與名額規格可逐項覆寫; 回傳之各函數皆不reject;本工廠為同步函數,providers無效時throw(設定錯誤應於啟動期即失敗)

Source:
Example
//need cli in system PATH

import dispatchAiWkf from './src/dispatchAiWkf.mjs'

let wkf = dispatchAiWkf({
    providers: {
        'deepseek': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
        'sonnet': { kind: 'claude', model: 'sonnet' },
        'luna': { kind: 'codex', model: 'gpt-5.6-luna' },
    },
    defaults: { timeoutMs: 300000 },
})

let test = async () => {

    //單一名額: 主模型+遞補鏈
    let r1 = await wkf.callAi('只回覆JSON: {"a":1}', { spec: { use: 'deepseek', fallback: ['sonnet'] }, check: (j) => j.a === 1 })
    console.log(r1.ok, r1.json)
    // => true { a: 1 }

    //Fanout工作流: 多開執行+單點整合
    let r2 = await wkf.runFanout({
        task: '分析並只回覆JSON: {"essence":"..."}',
        agents: [{ use: 'deepseek', fallback: ['sonnet'] }, { use: 'sonnet' }],
        integrate: { use: 'luna' },
        check: (j) => !!j.essence,
    })
    console.log(r2.ok, r2.integrated)
    // => true true

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Description
opt Object

輸入設定物件

Properties
Name Type Attributes Default Description
providers Object

輸入provider定義表物件(名稱 → dispatchAiFallback條目:{ kind, model, keys, exe, provider, config, sandbox, extraArgs... })

defaults Object <optional>
{}

輸入共用呼叫設定物件(cwd、store、onEvent、timeoutMs、budgetMs、maxRetries、promptPrefix、parse等),預設{}

Returns:

回傳綁定版API物件,內含callAi(單一名額呼叫)、runFanout(多開+整合)、runRolePipeline(串行角色鏈)、runFanoutPipeline(多開+整合+角色鏈)、providers(定義表原樣)

Type
Object

(async) dispatchAntigravity(prompt, optopt) → {Promise}

Description:
  • 以Google Antigravity CLI(agy)呼叫AI模型

    特點: prompt作為--print旗標之值傳遞而非stdin(agy介面如此,塞stdin會進互動模式卡住), 故prompt受命令列長度上限約束,超過30000字元回傳錯誤結果物件; model須為agy models第一欄之slug(如gemini-3.6-flash-low),注意agy錯誤訊息列出的是顯示名稱而非slug; 帶檔位之slug(-high/-medium/-low結尾)與effort同時給定且檔位不一致時agy回conflicts錯誤(一致則放行), effort需agy>=1.1.11,建議搭配不帶檔位之基礎slug(如gemini-3.1-pro)使用; 預設帶--dangerously-skip-permissions令非互動print模式不卡權限確認,可給予skipPermissions為false保留權限閘門; agy自身之--print-timeout未給時由timeoutMs推導並預留30秒緩衝,令CLI先於外層逾時; 沿用agy既有OAuth登入狀態(首次須於桌面互動模式完成登入); 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need agy cli in system PATH, and OAuth login completed

import dispatchAntigravity from './src/dispatchAntigravity.mjs'

let test = async () => {

    let r = await dispatchAntigravity('請只回覆兩個字:完成', { model: 'gemini-3.6-flash-low' })
    console.log(r.ok, r.stdout.trim())
    // => true 完成

    //基礎slug搭配effort(不可用帶檔位之slug併用effort)
    let r2 = await dispatchAntigravity('請只回覆兩個字:完成', { model: 'gemini-3.1-pro', effort: 'low' })
    console.log(r2.ok)
    // => true

    let re = await dispatchAntigravity('')
    console.log(re.ok, re.error)
    // => false 'prompt must be a non-empty string'

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,作為--print旗標之值傳遞,長度上限30000字元

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
exe String <optional>
'agy'

輸入agy執行檔名稱或絕對路徑字串,命令名為agy非antigravity,給予名稱時由execCli自系統PATH解析,預設'agy'

model String <optional>
''

輸入模型slug字串,須為agy models第一欄之slug,例如'gemini-3.6-flash-low'、'gemini-3.1-pro-high',預設''代表不帶--model旗標由agy自行決定

effort String <optional>
''

輸入推理深度字串,可選'low'、'medium'、'high',需agy>=1.1.11,建議搭配不帶檔位之基礎slug;與帶檔位slug併用且檔位不一致時agy回conflicts錯誤,預設''代表不帶

skipPermissions Boolean <optional>
true

輸入是否帶--dangerously-skip-permissions旗標布林值,false代表保留CLI權限閘門,預設true

printTimeout String <optional>
''

輸入agy自身等待上限字串(如'10m'、'570s'),預設''代表由timeoutMs推導(扣30秒緩衝,下限30秒)

addDirs Array <optional>
[]

輸入加入workspace之目錄字串陣列,逐項展開為--add-dir,預設[]

extraArgs Array <optional>
[]

輸入額外命令列旗標字串陣列(如--output-format、--json-schema、--mode),將接於固定旗標之後、--print之前,預設[]

timeoutMs Number <optional>
300000

輸入逾時毫秒正整數,逾時將強制關閉子進程及其子孫程序,agy為agent型CLI故預設較長之300000,預設300000

cwd String <optional>
process.cwd()

輸入子進程工作目錄字串,預設process.cwd()

validate String | function <optional>

輸入stdout驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證

maxRetries Number <optional>
0

輸入失敗後最大重試次數非負整數,預設0

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

(async) dispatchApiOpenaiCompat(prompt, optopt) → {Promise}

Description:
  • 以fetch直呼OpenAI相容API(chat/completions)呼叫AI模型

    特點: 免安裝CLI、免預先登入,給baseURL+key+model即可呼叫(如OpenCode Zen、Agnes等OpenAI相容閘道); prompt走HTTP body,無命令列長度限制; 錯誤依HTTP狀態碼分流:4xx(429除外)為客戶端錯誤不重試,429/5xx/網路錯誤/逾時依maxRetries線性退避重試; 結果結構與逾時/驗證失敗之error字樣對齊execCli,可直接作為dispatchAi與dispatchAiFallback之kind('api-openai-compat')使用; 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need network, no cli required

import dispatchApiOpenaiCompat from './src/dispatchApiOpenaiCompat.mjs'

let test = async () => {

    //OpenCode Zen(即opencode CLI之自家閘道), 模型名不帶opencode/前綴
    let r1 = await dispatchApiOpenaiCompat('請只回覆兩個字:完成', {
        baseURL: 'https://opencode.ai/zen/v1',
        key: 'sk-xxxxxx',
        model: 'deepseek-v4-flash-free',
    })
    console.log(r1.ok, r1.stdout.trim())
    // => true 完成

    //Agnes
    let r2 = await dispatchApiOpenaiCompat('請只回覆兩個字:完成', {
        baseURL: 'https://apihub.agnes-ai.com/v1',
        key: 'sk-xxxxxx',
        model: 'agnes-2.0-flash',
    })
    console.log(r2.ok, r2.stdout.trim())
    // => true 完成

    let re = await dispatchApiOpenaiCompat('abc', { baseURL: 'https://opencode.ai/zen/v1', key: 'sk-bad', model: 'deepseek-v4-flash-free' })
    console.log(re.ok, re.code, re.error)
    // => false 401 HTTP 401

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,作為user訊息置於HTTP body

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
baseURL String

輸入API基底網址字串,例如'https://opencode.ai/zen/v1'、'https://apihub.agnes-ai.com/v1',將於尾端接上/chat/completions

model String

輸入模型ID字串,例如'deepseek-v4-flash-free'(Zen之模型名不帶opencode/前綴)、'agnes-2.0-flash'

key String <optional>
''

輸入API key字串,以Bearer置於Authorization標頭,預設''代表不帶認證標頭

system String <optional>
''

輸入system提示詞字串,將以system角色置於messages首位,預設''代表不帶

body Object <optional>
{}

輸入額外請求本體物件(如temperature、max_tokens、response_format),將併入預設body(同名鍵以此為準),預設{}

headers Object <optional>
{}

輸入額外請求標頭物件,預設{}

timeoutMs Number <optional>
120000

輸入逾時毫秒正整數,逾時將中止請求(含回應串流讀取),預設120000

validate String | function <optional>

輸入回覆內容驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證

maxRetries Number <optional>
0

輸入失敗後最大重試次數非負整數,4xx(429除外)不重試,預設0

retryDelayMs Number <optional>
5000

輸入重試間隔毫秒正整數,實際間隔為retryDelayMs乘以重試次數且上限15000ms,預設5000

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(回覆內容字串)、stderr(失敗時之原始回應本體)、code(HTTP狀態碼,網路錯誤與逾時為null)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

(async) dispatchClaude(prompt, optopt) → {Promise}

Description:
  • 以Claude Code CLI呼叫Claude模型

    特點: prompt一律走stdin而非位置參數,因摘要內文可達數萬字,當命令列參數會spawn ENAMETOOLONG; 沿用Claude Code既有登入狀態,無逐次注入API key之概念,故無key參數; 未給model時不帶--model旗標,由CLI自行決定使用模型; 預設帶--dangerously-skip-permissions令非互動之-p模式不因權限確認而卡住, 惟prompt含不可信內容(例如待摘要之網頁)時該內容之指示亦將無權限閘門執行, 可給予skipPermissions為false保留CLI權限閘門; 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need claude cli in system PATH

import dispatchClaude from './src/dispatchClaude.mjs'

let test = async () => {

    let r = await dispatchClaude('請只回覆兩個字:完成', { model: 'sonnet', timeoutMs: 120000 })
    console.log(r.ok, r.stdout.trim())
    // => true '完成'

    let re = await dispatchClaude('')
    console.log(re.ok, re.error)
    // => false 'prompt must be a non-empty string'

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,一律以stdin傳入子進程

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
exe String <optional>
'claude'

輸入claude執行檔名稱或絕對路徑字串,給予名稱時由execCli自系統PATH解析,預設'claude'

model String <optional>
''

輸入模型別名或模型ID字串,例如'sonnet'、'opus',預設''代表不帶--model旗標

skipPermissions Boolean <optional>
true

輸入是否帶--dangerously-skip-permissions旗標布林值,false代表保留CLI權限閘門,預設true

extraArgs Array <optional>
[]

輸入額外命令列旗標字串陣列,將接於固定旗標之後,預設[]

timeoutMs Number <optional>
120000

輸入逾時毫秒正整數,逾時將強制關閉子進程及其子孫程序,預設120000

cwd String <optional>
process.cwd()

輸入子進程工作目錄字串,預設process.cwd()

validate String | function <optional>

輸入stdout驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證

maxRetries Number <optional>
0

輸入失敗後最大重試次數非負整數,預設0

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

(async) dispatchCodex(prompt, optopt) → {Promise}

Description:
  • 以OpenAI Codex CLI呼叫GPT模型

    特點: prompt一律走stdin而非位置參數,因摘要內文可達數萬字,當命令列參數會spawn ENAMETOOLONG; 固定帶--skip-git-repo-check,令非git倉庫之工作目錄亦可執行; 沿用Codex CLI既有登入狀態,無逐次注入API key之概念,故無key參數; 未給model時不帶-m旗標,由CLI自行決定使用模型; 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need codex cli in system PATH

import dispatchCodex from './src/dispatchCodex.mjs'

let test = async () => {

    let r = await dispatchCodex('請只回覆兩個字:完成', { model: 'gpt-5.6-luna', sandbox: 'read-only' })
    console.log(r.ok, r.stdout.includes('完成'))
    // => true true

    let re = await dispatchCodex('abc', { exe: 'codex-not-exist' })
    console.log(re.ok, re.error.includes('ENOENT'))
    // => false true

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,一律以stdin傳入子進程

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
exe String <optional>
'codex'

輸入codex執行檔名稱或絕對路徑字串,給予名稱時由execCli自系統PATH解析,預設'codex'

model String <optional>
''

輸入模型ID字串,例如'gpt-5.6-luna',預設''代表不帶-m旗標

sandbox String <optional>
'workspace-write'

輸入沙箱模式字串,例如'read-only'、'workspace-write'、'danger-full-access',預設'workspace-write'

extraArgs Array <optional>
[]

輸入額外命令列旗標字串陣列,例如['--config', 'model_reasoning_effort="max"'],將接於固定旗標之後,預設[]

timeoutMs Number <optional>
120000

輸入逾時毫秒正整數,逾時將強制關閉子進程及其子孫程序,預設120000

cwd String <optional>
process.cwd()

輸入子進程工作目錄字串,預設process.cwd()

validate String | function <optional>

輸入stdout驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證

maxRetries Number <optional>
0

輸入失敗後最大重試次數非負整數,預設0

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

(async) dispatchOpencode(prompt, optopt) → {Promise}

Description:
  • 以opencode CLI呼叫AI模型

    特點: prompt一律走stdin而非位置參數,因摘要內文可達數萬字,當命令列參數會spawn ENAMETOOLONG, 而opencode run未帶位置message時即從stdin讀取; 同時給予key與provider時,以OPENCODE_AUTH_CONTENT環境變數逐次注入金鑰, 該注入僅作用於當次子進程且不改寫auth.json,故可多把金鑰輪替並與其他程序並行; 未給key或provider時沿用CLI既有登入狀態; 使用opencode未內建之第三方provider時,須另以config給予其provider定義; 本函數不會reject,一律以結果物件之ok與error欄位回報成敗

Source:
Example
//need opencode cli in system PATH

import dispatchOpencode from './src/dispatchOpencode.mjs'

let test = async () => {

    //沿用CLI既有登入狀態
    let r1 = await dispatchOpencode('請只回覆兩個字:完成', { model: 'opencode/deepseek-v4-flash-free' })
    console.log(r1.ok, r1.stdout.includes('完成'))
    // => true true

    //逐次注入金鑰, key與provider與model須為同一組
    let r2 = await dispatchOpencode('請只回覆兩個字:完成', {
        model: 'opencode/deepseek-v4-flash-free',
        provider: 'opencode',
        key: 'sk-xxxxxx',
    })
    console.log(r2.ok)
    // => true

    //opencode未內建之第三方provider, 須另以config給予其定義
    let r3 = await dispatchOpencode('請只回覆兩個字:完成', {
        model: 'agnes-ai/agnes-2.0-flash',
        provider: 'agnes-ai',
        key: 'sk-xxxxxx',
        config: {
            provider: {
                'agnes-ai': {
                    npm: '@ai-sdk/openai-compatible',
                    name: 'Agnes',
                    options: { baseURL: 'https://apihub.agnes-ai.com/v1' },
                    models: { 'agnes-2.0-flash': { name: 'Agnes 2.0 Flash' } },
                },
            },
        },
    })
    console.log(r3.ok)
    // => true

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
prompt String

輸入提示詞字串,一律以stdin傳入子進程

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
exe String <optional>
'opencode'

輸入opencode執行檔名稱或絕對路徑字串,給予名稱時由execCli自系統PATH解析,預設'opencode'

model String <optional>
''

輸入模型ID字串,例如'opencode/deepseek-v4-flash-free',預設''代表不帶-m旗標

key String <optional>
''

輸入該provider之API key字串,須與provider同時給予才會注入,預設''代表沿用CLI既有登入狀態

provider String <optional>
''

輸入key所屬provider名稱字串,須與key同時給予才會注入,且須與model為同一組,預設''

config Object | String <optional>
null

輸入opencode設定內容物件或其JSON字串,將以OPENCODE_CONFIG_CONTENT逐次注入,供補上第三方provider之定義,預設null代表沿用使用者既有設定檔

agent String <optional>
'build'

輸入opencode代理名稱字串,預設'build'

extraArgs Array <optional>
[]

輸入額外命令列旗標字串陣列,將接於固定旗標之後,預設[]

env Object <optional>

輸入本次調用額外注入之環境變數物件,同時給予key與provider時會再併入OPENCODE_AUTH_CONTENT,預設undefined

timeoutMs Number <optional>
120000

輸入逾時毫秒正整數,逾時將強制關閉子進程及其子孫程序,預設120000

cwd String <optional>
process.cwd()

輸入子進程工作目錄字串,預設process.cwd()

validate String | function <optional>

輸入stdout驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證

maxRetries Number <optional>
0

輸入失敗後最大重試次數非負整數,預設0

Returns:

回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(標準輸出字串)、stderr(標準錯誤字串)、code(離開碼)、error(錯誤訊息字串,成功時為空字串)、durationMs(耗時毫秒)、attempts(實際嘗試次數),本函數不會reject

Type
Promise

extractJsonLoose(text) → {Object|Array|null}

Description:
  • 從文字中抽取第一個完整的JSON物件或陣列

    特點: 先去除ANSI色碼與code fence標記後嘗試整段解析(最常見情境之最快路徑); 整段非法時自第一個{[起以括號配對(跳過字串與跳脫)取得第一個完整片段再解析; 僅接受物件與陣列,純量(字串/數字/布林)回傳null; 括號未閉合(輸出被截斷)或片段非法一律回傳null,不throw

Source:
Example
import extractJsonLoose from './src/wkf/extractJsonLoose.mjs'

console.log(extractJsonLoose('{"a":1}'))
// => { a: 1 }

console.log(extractJsonLoose('說明文字\n```json\n{"a":1}\n```\n後記'))
// => { a: 1 }

console.log(extractJsonLoose('{"a":1')) //截斷
// => null

console.log(extractJsonLoose('純文字回覆'))
// => null
Parameters:
Name Type Description
text String

輸入AI回覆文字字串

Returns:

回傳解析成功之物件或陣列,失敗回傳null

Type
Object | Array | null

getCliArgs(…args) → {Array}

Description:
  • 將各段命令列參數展平為字串陣列,並濾除非有效字串

    各轉接器之參數為「固定旗標」加「可選旗標」加「額外旗標」之組合, 其中可選旗標於未給值時須整段消失(例如未給model就不可出現懸空的--model), 故呼叫端須以「整段陣列給或不給」表達,本函數僅負責展平與濾除非有效字串,不判斷旗標配對; 過濾之必要在於Nodejs之spawn要求各參數必為字串,混入undefined或數字會直接拋出TypeError, 破壞本套件「不reject、僅以結果物件回報」之約定

Source:
Example
import getCliArgs from './src/getCliArgs.mjs'

console.log(getCliArgs('-p', ['--model', 'sonnet']))
// => ['-p', '--model', 'sonnet']

console.log(getCliArgs('-p', null, 123, ['', '--verbose']))
// => ['-p', '--verbose']
Parameters:
Name Type Attributes Description
args String | Array <repeatable>

輸入參數字串或參數字串陣列,可給多個

Returns:

回傳展平且濾除非有效字串後之參數字串陣列

Type
Array

getErrorResult(error) → {Object}

Description:
  • 產生與execCli同結構之錯誤結果物件

    本套件各dispatch函數一律不reject,參數檢核失敗時即以本函數回傳錯誤結果物件, 其欄位與wsemi之execCli回傳結構一致,故呼叫端可用同一套欄位判斷成敗, 無須區分「參數錯誤」與「CLI執行失敗」兩種來源

Source:
Example
import getErrorResult from './src/getErrorResult.mjs'

console.log(getErrorResult('prompt must be a non-empty string'))
// => { ok: false, stdout: '', stderr: '', code: null, error: 'prompt must be a non-empty string', durationMs: 0, attempts: 0 }

console.log(getErrorResult(null).error)
// => 'unknown error'
Parameters:
Name Type Description
error String

輸入錯誤訊息字串

Returns:

回傳結果物件,內含ok(布林值,恆為false)、stdout(空字串)、stderr(空字串)、code(null)、error(錯誤訊息字串)、durationMs(0)、attempts(0)

Type
Object

isKeyIndependentFail(r) → {Boolean}

Description:
  • 判斷失敗結果是否與「哪一把金鑰」無關(換組內金鑰必然再敗, 應整組跳過)

Source:
Parameters:
Name Type Description
r Object

輸入dispatchAi失敗結果物件

Returns:

回傳是否應整組跳過之布林值

Type
Boolean

(async) runFanout(optopt) → {Promise}

Description:
  • 執行Fanout工作流:多開執行與單點整合

    特點: 前段各名額並行執行同一任務,各名額可指定主模型(use)與自帶遞補鏈(fallback); 後段為單一整合名額,同樣可帶遞補鏈; 個別名額失敗不中斷整輪,成功候選未達minCandidates時以首位候選為成果(integrated:false)不硬整合; 成功候選完整保留於回傳(部分接受、便於接續重試整合); 本函數不會reject

Source:
Example
//need cli in system PATH

import runFanout from './src/wkf/runFanout.mjs'

let providers = {
    'deepseek': { kind: 'opencode', model: 'opencode/deepseek-v4-flash-free', provider: 'opencode', keys: ['sk-xxx'] },
    'sonnet': { kind: 'claude', model: 'sonnet' },
}

let test = async () => {

    let r = await runFanout({
        providers,
        task: '分析並只回覆JSON: {"essence":"..."}',
        agents: [
            { use: 'deepseek', fallback: ['sonnet'] },
            { use: 'sonnet' },
        ],
        integrate: { use: 'sonnet' },
        check: (j) => !!j.essence,
    })
    console.log(r.ok, r.integrated, r.candidates.length)
    // => true true 2

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
providers Object

輸入provider定義表物件(名稱 → 條目),透傳callAiWithFallback

task String

輸入前段各名額共用之任務提示詞字串

agents Array

輸入前段名額規格陣列,各元素{ use, fallback, maxRetries?, timeoutMs? }等(除use/fallback外之鍵覆寫該名額呼叫設定)

integrate Object

輸入整合名額規格物件{ use, fallback, prompt?, ... },prompt可為(candidates)=>String自訂整合提示詞,省略用預設模板

check function <optional>
null

輸入候選與終稿共用之檢核函數(json)=>Boolean,預設null

schema String <optional>
''

輸入輸出格式示意字串,供預設整合模板嵌入,預設''

minCandidates Number <optional>
2

輸入進入整合所需之最少成功候選數正整數,未達門檻以首位候選為成果,預設2

callOpt Object <optional>
{}

輸入透傳callAiWithFallback之共用設定(cwd、store、onEvent、timeoutMs、promptPrefix等),預設{}

Returns:

回傳Promise,resolve回傳結果物件,內含ok(布林值)、result(工作流成果)、integrated(是否經過整合布林值)、agents(各名額完整結果陣列)、candidates(成功候選陣列)、integrateDetail(整合呼叫完整結果)、totalMs(總耗時毫秒)、error(錯誤訊息字串),本函數不會reject

Type
Promise

(async) runFanoutPipeline(optopt) → {Promise}

Description:
  • 執行FanoutPipeline工作流(Fanout+RolePipeline):多開+整合+串行角色鏈

    特點: 前段同runFanout(agents各名額可自帶fallback、integrate單點整合); 後段同runRolePipeline(stages各階段可自帶AI/fallback/提示詞),其input即前段成果; 本函數不會reject

Source:
Example
//need cli in system PATH

import runFanoutPipeline from './src/wkf/runFanoutPipeline.mjs'

let providers = {
    'sonnet': { kind: 'claude', model: 'sonnet' },
    'luna': { kind: 'codex', model: 'gpt-5.6-luna' },
}

let test = async () => {

    let r = await runFanoutPipeline({
        providers,
        task: '分析並只回覆JSON: {"essence":"..."}',
        agents: [{ use: 'sonnet' }, { use: 'luna' }],
        integrate: { use: 'sonnet' },
        stages: [
            { id: 'audit', use: 'luna', prompt: (ctx) => `審計此稿並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.input)}` },
        ],
        check: (j) => !!j.essence,
    })
    console.log(r.ok, r.A.integrated, r.B.order)
    // => true true [ 'audit' ]

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
providers Object

輸入provider定義表物件(名稱 → 條目)

task String

輸入前段各名額共用之任務提示詞字串

agents Array

輸入前段名額規格陣列(同runFanout)

integrate Object

輸入前段整合名額規格物件(同runFanout)

stages Array

輸入後段階段規格陣列(同runRolePipeline),各階段以ctx.input取得前段成果

check function <optional>
null

輸入前段共用檢核函數,後段各階段自帶check,預設null

schema String <optional>
''

輸入輸出格式示意字串(供前段預設整合模板),預設''

minCandidates Number <optional>
2

輸入前段整合門檻正整數,預設2

callOpt Object <optional>
{}

輸入透傳兩段之共用呼叫設定,預設{}

Returns:

回傳Promise,resolve回傳結果物件,內含ok(布林值)、result(工作流成果)、A(前段runFanout完整結果)、B(後段runRolePipeline完整結果)、totalMs(總耗時毫秒)、error(錯誤訊息字串),本函數不會reject

Type
Promise

(async) runRolePipeline(optopt) → {Promise}

Description:
  • 執行RolePipeline工作流:多角色串行鏈

    特點: 各階段可各自指定use/fallback/prompt/check(含rawText純文字階段); 階段成果依序傳遞,最末階段成果即工作流成果; 失敗即止但已完成成果完整回傳(部分接受、便於接續重跑失敗段); 本函數不會reject

Source:
Example
//need cli in system PATH

import runRolePipeline from './src/wkf/runRolePipeline.mjs'

let providers = {
    'sonnet': { kind: 'claude', model: 'sonnet' },
    'luna': { kind: 'codex', model: 'gpt-5.6-luna' },
}

let test = async () => {

    let r = await runRolePipeline({
        providers,
        input: '原始任務',
        stages: [
            { id: 'draft', use: 'sonnet', prompt: (ctx) => `就「${ctx.input}」寫初稿, 只回覆JSON: {"text":"..."}` },
            { id: 'review', use: 'luna', prompt: (ctx) => `審閱並修訂, 只回覆同格式JSON: ${JSON.stringify(ctx.prev)}` },
        ],
    })
    console.log(r.ok, r.order, r.failedStage)
    // => true [ 'draft', 'review' ] null

}
await test()
    .catch((err) => {
        console.log(err)
    })
Parameters:
Name Type Attributes Default Description
opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
providers Object

輸入provider定義表物件(名稱 → 條目)

input * <optional>
null

輸入工作流輸入(原始任務字串或前一工作流之成果物件),提供給各階段ctx.input,預設null

stages Array

輸入階段規格陣列,各元素{ id, use, fallback, prompt:(ctx)=>String, check?, rawText?, maxRetries?, timeoutMs? }等

callOpt Object <optional>
{}

輸入透傳callAiWithFallback之共用設定,預設{}

Returns:

回傳Promise,resolve回傳結果物件,內含ok(布林值)、result(最末階段成果)、stages(id對階段完整呼叫結果之物件)、results(id對階段成果之物件)、order(階段id順序陣列)、failedStage(失敗階段id,無失敗為null)、totalMs(總耗時毫秒)、error(錯誤訊息字串),本函數不會reject

Type
Promise