w-dispatch-ai 1.0.25 → 1.0.26

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 (60) hide show
  1. package/README.md +56 -4
  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 +6 -4
  5. package/docs/adapters.mjs.html +10 -3
  6. package/docs/budgetFor.mjs.html +2 -2
  7. package/docs/buildValidator.mjs.html +2 -2
  8. package/docs/castPintOr.mjs.html +2 -2
  9. package/docs/dfTimeoutMs.mjs.html +2 -2
  10. package/docs/dispatchAi.mjs.html +2 -2
  11. package/docs/dispatchAiFallback.mjs.html +2 -2
  12. package/docs/dispatchAiWkf.mjs.html +2 -2
  13. package/docs/dispatchAntigravity.mjs.html +2 -2
  14. package/docs/dispatchApiOpenaiCompat.mjs.html +2 -2
  15. package/docs/dispatchApiOpenaiResponses.mjs.html +2 -2
  16. package/docs/dispatchApiTypesafeSystemone.mjs.html +447 -0
  17. package/docs/dispatchClaude.mjs.html +2 -2
  18. package/docs/dispatchCodex.mjs.html +2 -2
  19. package/docs/dispatchOpencode.mjs.html +2 -2
  20. package/docs/getCliArgs.mjs.html +2 -2
  21. package/docs/getErrorResult.mjs.html +2 -2
  22. package/docs/getErrorType.mjs.html +4 -3
  23. package/docs/global.html +1221 -254
  24. package/docs/index.html +2 -2
  25. package/docs/quota_dfQuotaTimeoutMs.mjs.html +2 -2
  26. package/docs/quota_fetchQuotaJson.mjs.html +2 -2
  27. package/docs/quota_fromCodexUsageHttp.mjs.html +2 -2
  28. package/docs/quota_getQuotaAntigravity.mjs.html +2 -2
  29. package/docs/quota_getQuotaClaude.mjs.html +2 -2
  30. package/docs/quota_getQuotaCodex.mjs.html +2 -2
  31. package/docs/quota_readJsonOrNull.mjs.html +2 -2
  32. package/docs/quota_toQuotaLabel.mjs.html +2 -2
  33. package/docs/quota_toQuotaResult.mjs.html +2 -2
  34. package/docs/quota_toQuotaScopedLabel.mjs.html +2 -2
  35. package/docs/quota_toQuotaWindow.mjs.html +2 -2
  36. package/docs/readEnvFile.mjs.html +2 -2
  37. package/docs/resolveProviders.mjs.html +2 -2
  38. package/docs/wkf_callAiWithFallback.mjs.html +2 -2
  39. package/docs/wkf_createFileStore.mjs.html +2 -2
  40. package/docs/wkf_createUsageCounter.mjs.html +2 -2
  41. package/docs/wkf_extractJsonLoose.mjs.html +2 -2
  42. package/docs/wkf_noSideEffectPrefix.mjs.html +2 -2
  43. package/docs/wkf_runFanout.mjs.html +2 -2
  44. package/docs/wkf_runFanoutPipeline.mjs.html +2 -2
  45. package/docs/wkf_runRolePipeline.mjs.html +2 -2
  46. package/docs/wkf_salvageTruncatedArray.mjs.html +2 -2
  47. package/g.mjs +2 -2
  48. package/package.json +1 -1
  49. package/src/WDispatchAi.mjs +4 -2
  50. package/src/adapters.mjs +8 -1
  51. package/src/dispatchApiTypesafeSystemone.mjs +375 -0
  52. package/src/getErrorType.mjs +2 -1
  53. package/src/providers.mjs +32 -1
  54. package/test/tools/fakeServerForApiTest.mjs +75 -5
  55. package/test/unit-WDispatchAi.test.mjs +10 -6
  56. package/test/unit-adapters.test.mjs +5 -3
  57. package/test/unit-dispatchAi.test.mjs +1 -1
  58. package/test/unit-dispatchApiTypesafeSystemone.test.mjs +159 -0
  59. package/test/unit-providers.test.mjs +7 -0
  60. package/test/unit-resolveProviders.test.mjs +2 -2
@@ -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#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</a></li><li><a href="global.html#dispatchApiTypesafeSystemone">dispatchApiTypesafeSystemone</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -426,7 +426,7 @@ export default dispatchApiOpenaiCompat
426
426
  <br class="clear">
427
427
 
428
428
  <footer>
429
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Sep 14 2026 12:59:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
429
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Sep 17 2026 13:48:00 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
430
430
  </footer>
431
431
 
432
432
  <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#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</a></li><li><a href="global.html#dispatchApiTypesafeSystemone">dispatchApiTypesafeSystemone</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -485,7 +485,7 @@ export { extractOutputText }
485
485
  <br class="clear">
486
486
 
487
487
  <footer>
488
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Sep 14 2026 12:59:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
488
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Sep 17 2026 13:48:00 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
489
489
  </footer>
490
490
 
491
491
  <script>prettyPrint();</script>
@@ -0,0 +1,447 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>dispatchApiTypesafeSystemone.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#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</a></li><li><a href="global.html#dispatchApiTypesafeSystemone">dispatchApiTypesafeSystemone</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">dispatchApiTypesafeSystemone.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 isobj from 'wsemi/src/isobj.mjs'
50
+ import iseobj from 'wsemi/src/iseobj.mjs'
51
+ import isnum from 'wsemi/src/isnum.mjs'
52
+ import cint from 'wsemi/src/cint.mjs'
53
+ import isestr from 'wsemi/src/isestr.mjs'
54
+ import isp0int from 'wsemi/src/isp0int.mjs'
55
+ import delay from 'wsemi/src/delay.mjs'
56
+ import strTruncate from 'wsemi/src/strTruncate.mjs'
57
+ import castPintOr from './castPintOr.mjs'
58
+ import buildValidator from './buildValidator.mjs'
59
+ import getErrorResult from './getErrorResult.mjs'
60
+ import dfTimeoutMs from './dfTimeoutMs.mjs'
61
+
62
+
63
+ // dispatchApiTypesafeSystemone.mjs — 以fetch直呼TypeSafe AI之System One API(POST /v1/systemone)
64
+ //
65
+ // 【這不是文字生成模型(2026-09-17實測後新增)】TypeSafe之jev為「System One」決策模型:
66
+ // 不產生文字, 而是對一段state(被評估的內容)回答呼叫端定義的型別化問題(questions),
67
+ // 每題回傳受限於呼叫端選項之答案與機率。權威文件: https://docs.typesafe.ai/api
68
+ // (索引 https://docs.typesafe.ai/llms.txt)。官方僅提供Python/JavaScript SDK、Playground與
69
+ // agent skill, 無CLI(npm之@typesafe-ai/sdk無bin、PyPI之typesafe-sdk無console script), 故只有API版。
70
+ //
71
+ // 【請求】POST &lt;baseURL>/systemone, Authorization: Bearer &lt;key>, body為{ model, state, questions }:
72
+ // state ← 本轉接器之prompt(字串)。結構化內容請以JSON.stringify(物件)傳入——2026-09-17實測
73
+ // 同一組引用欄位路徑之問題, 物件state與JSON字串state之答案一致(差異≤0.01)。
74
+ // questions ← opt.questions(必填, 非空物件), 鍵為呼叫端自訂之題目id, 值為:
75
+ // { type:'noul', instructions, criteria?:{true,false} } 是非題, 回yes之機率
76
+ // { type:'choice', instructions, criteria:{選項:描述|null} } 單選題
77
+ // { type:'score', instructions, criteria:[層級描述...] } 有序量表(至少2級)
78
+ // 題型與欄位由伺服器驗證(不合規回422), 本轉接器只擋「未給questions」, 不重複伺服器規則。
79
+ // model ← opt.model, 預設'jev-latest'(官方SDK之預設; 回應之model為實際版本如'jev-1.13.0')。
80
+ //
81
+ // 【回應(實測)】{ model:'jev-1.13.0', answers:{ &lt;id>:{type,choice|score|noul,probabilities?,confidence?,legend?} },
82
+ // usage:{ input_tokens, output_tokens } }; 回應標頭帶x-typesafe-request-id。
83
+ // 本轉接器之stdout為JSON.stringify(answers)(令dispatchAiFallback與工作流層之parse/check無須修改即可用),
84
+ // 另於結果物件追加answers(已解析物件)與modelResolved(實際模型版本)。
85
+ // 請求的題目id在answers中缺任一個即視為INVALID_RESPONSE, 不讓下游取到undefined。
86
+ //
87
+ // 【錯誤(實測)】壞金鑰401 {detail:{error_type:'authentication_error'}}; 未知model 400
88
+ // {detail:{error_type:'api_usage_error', message:'Unknown model: X'}}; 題型不合規或questions為空422
89
+ // {detail:[{type,loc,msg,...}]}。皆以HTTP &lt;code>回報、原始本體置stderr; 4xx(429除外)不重試。
90
+ //
91
+ // 【混用注意】
92
+ // 1. 答案形狀與文字模型完全不同, 不可與文字生成條目混在同一條dispatchAiFallback鏈中遞補;
93
+ // 同一鏈只放本kind之條目(可多把金鑰輪替)。預設providers.mjs收有typesafe:jev-latest,
94
+ // 請以pick單獨取出; 全取做文字遞補時該條因無questions以params錯誤0ms失敗後換下一家。
95
+ // 2. questions於dispatchAiFallback可放呼叫層opt(非fallback自用鍵會透傳給各條目), 不必寫進條目。
96
+ // 3. 工作流callAi預設在prompt前掛防寫檔前綴(NO_SIDE_EFFECT), 對本kind等於把前綴混進被評估的state,
97
+ // 經工作流呼叫時務必傳promptPrefix:''。
98
+
99
+
100
+ //預設值
101
+ let DEFAULT_BASE_URL = 'https://api.typesafe.ai/v1'
102
+ let DEFAULT_MODEL = 'jev-latest'
103
+ let DEFAULT_TIMEOUT_MS = dfTimeoutMs //全套件統一預設300000
104
+ let DEFAULT_RETRY_DELAY_MS = 5000
105
+ let MAX_RETRY_DELAY_MS = 15000
106
+
107
+
108
+ //optTruncate, 裁切失敗結果之內容時於刪節號後標註原始總長度(同execCli)
109
+ let optTruncate = {
110
+ funWithMsg: (str) => `(truncated, total ${str.length} chars)`,
111
+ }
112
+
113
+
114
+ /**
115
+ * 單次HTTP呼叫(內部使用, 不含重試邏輯)
116
+ *
117
+ * @param {String} url 輸入完整端點網址字串
118
+ * @param {Object} headers 輸入請求標頭物件
119
+ * @param {Object} body 輸入請求本體物件
120
+ * @param {Array} ids 輸入請求之題目id陣列,用於檢核回應是否每題皆有答案
121
+ * @param {Number} timeoutMs 輸入逾時毫秒
122
+ * @param {Function|null} validator 輸入驗證函式
123
+ * @returns {Promise} 回傳Promise,resolve回傳結果物件
124
+ */
125
+ async function callOnce(url, headers, body, ids, timeoutMs, validator) {
126
+
127
+ let t0 = Date.now()
128
+
129
+ //mkResult, 結果形狀之單一來源(欄位對齊其他api類轉接器, 追加answers與modelResolved)
130
+ let mkResult = (patch) => ({
131
+ ok: false,
132
+ stdout: '',
133
+ stderr: '',
134
+ code: null,
135
+ error: '',
136
+ durationMs: Date.now() - t0,
137
+ usage: null,
138
+ answers: null,
139
+ modelResolved: '',
140
+ ...patch,
141
+ })
142
+
143
+ //AbortController, 逾時中止(含回應本體之讀取)
144
+ let controller = new AbortController()
145
+ let timer = setTimeout(() => {
146
+ controller.abort()
147
+ }, timeoutMs)
148
+
149
+ let res = null
150
+ let txt = ''
151
+ try {
152
+ res = await fetch(url, {
153
+ method: 'POST',
154
+ headers,
155
+ body: JSON.stringify(body),
156
+ signal: controller.signal,
157
+ })
158
+ txt = await res.text()
159
+ }
160
+ catch (err) {
161
+ clearTimeout(timer)
162
+
163
+ //逾時, error以TIMEOUT開頭令dispatchAiFallback視為與金鑰無關而跳組
164
+ if (err.name === 'AbortError') {
165
+ return mkResult({ error: `TIMEOUT after ${timeoutMs / 1000}s`, errorType: 'timeout' })
166
+ }
167
+
168
+ //網路層錯誤(DNS/連線拒絕等)
169
+ let cause = get(err, 'cause.code', '') || err.message
170
+ return mkResult({ error: `FETCH_ERROR: ${cause}`, errorType: 'fetch' })
171
+ }
172
+ clearTimeout(timer)
173
+
174
+ //HTTP非2xx, 原始回應本體放stderr(401/400之detail.message、422之detail陣列皆在其中)
175
+ if (!res.ok) {
176
+ return mkResult({
177
+ stderr: strTruncate(txt, 1000, optTruncate),
178
+ code: res.status,
179
+ error: `HTTP ${res.status}`,
180
+ errorType: 'http',
181
+ })
182
+ }
183
+
184
+ //解析answers/model/usage
185
+ let answers = null
186
+ let modelResolved = ''
187
+ let usage = null
188
+ try {
189
+ let j = JSON.parse(txt)
190
+ answers = get(j, 'answers', null)
191
+ modelResolved = get(j, 'model', '')
192
+ if (!isestr(modelResolved)) {
193
+ modelResolved = ''
194
+ }
195
+ usage = get(j, 'usage', null)
196
+ if (!isobj(usage)) {
197
+ usage = null
198
+ }
199
+ }
200
+ catch {
201
+ answers = null
202
+ }
203
+ if (!isobj(answers)) {
204
+ return mkResult({
205
+ stderr: strTruncate(txt, 500, optTruncate),
206
+ code: res.status,
207
+ error: 'INVALID_RESPONSE: missing answers object',
208
+ errorType: 'invalid-response',
209
+ usage,
210
+ modelResolved,
211
+ })
212
+ }
213
+
214
+ //每個請求之題目皆須有答案, 缺漏即不合規(避免下游取到undefined)
215
+ let missing = ids.filter((id) => !isobj(answers[id]))
216
+ if (missing.length > 0) {
217
+ return mkResult({
218
+ stderr: strTruncate(txt, 500, optTruncate),
219
+ code: res.status,
220
+ error: `INVALID_RESPONSE: missing answers for [${missing.join(', ')}]`,
221
+ errorType: 'invalid-response',
222
+ usage,
223
+ modelResolved,
224
+ })
225
+ }
226
+
227
+ //content, answers序列化為stdout(令遞補層與工作流層之parse/check通用)
228
+ let content = JSON.stringify(answers)
229
+
230
+ //validator, error與execCli一致令dispatchAiFallback可統一分流
231
+ if (validator &amp;&amp; !validator(content)) {
232
+ return mkResult({
233
+ stdout: strTruncate(content, 500, optTruncate),
234
+ code: res.status,
235
+ error: 'OUTPUT_VALIDATION_FAILED',
236
+ errorType: 'validation',
237
+ usage,
238
+ modelResolved,
239
+ })
240
+ }
241
+
242
+ return mkResult({
243
+ ok: true,
244
+ stdout: content,
245
+ code: res.status,
246
+ usage,
247
+ answers,
248
+ modelResolved,
249
+ })
250
+ }
251
+
252
+
253
+ //本轉接器不使用execCli, 全部設定鍵自理, 未知鍵一律忽略
254
+
255
+
256
+ /**
257
+ * 以fetch直呼TypeSafe AI之System One API(POST /v1/systemone),對prompt(即state)回答型別化問題
258
+ *
259
+ * 特點:
260
+ * 非文字生成——jev等System One模型對state回答呼叫端定義之questions(noul是非題、choice單選題、score量表),
261
+ * 每題回傳受限於選項之答案與機率;官方無CLI,僅此API路徑;
262
+ * prompt即state,結構化內容以JSON.stringify(物件)傳入(實測答案與物件state一致);
263
+ * stdout為answers之JSON字串,另於結果追加answers(已解析物件)與modelResolved(實際模型版本);
264
+ * 請求之題目id於回應缺任一即以INVALID_RESPONSE回報;
265
+ * 不可與文字生成條目混在同一條遞補鏈,經工作流callAi呼叫時須傳promptPrefix:''(理由見檔頭);
266
+ * 本函數不會reject,一律以結果物件之ok與error欄位回報成敗
267
+ *
268
+ * @param {String} prompt 輸入被評估之內容字串,作為state置於HTTP body,結構化內容請先JSON.stringify
269
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
270
+ * @param {Object} opt.questions 輸入題目物件(必填且非空),鍵為自訂題目id,值為{type:'noul'|'choice'|'score', instructions, criteria},格式見檔頭與https://docs.typesafe.ai/api
271
+ * @param {String} [opt.baseURL='https://api.typesafe.ai/v1'] 輸入API基底網址字串,將於尾端接上/systemone,預設官方端點
272
+ * @param {String} [opt.model='jev-latest'] 輸入模型名稱字串,預設'jev-latest'(另有'jev-preview')
273
+ * @param {String} [opt.key=''] 輸入API key字串,以Bearer置於Authorization標頭,預設''代表不帶認證標頭
274
+ * @param {Object} [opt.body={}] 輸入額外請求本體物件,將併入預設body(同名鍵以此為準),預設{}
275
+ * @param {Object} [opt.headers={}] 輸入額外請求標頭物件,預設{}
276
+ * @param {Number} [opt.timeoutMs=300000] 輸入逾時毫秒正整數,逾時將中止請求,全套件統一預設300000
277
+ * @param {String|Function} [opt.validate=undefined] 輸入stdout(answers之JSON字串)驗證規則字串或自訂驗證函數,規則字串支援'nonempty'、'json'、'min:100',多規則可用逗號串接,預設undefined代表不驗證
278
+ * @param {Number} [opt.maxRetries=0] 輸入失敗後最大重試次數非負整數,4xx(429除外)不重試,預設0
279
+ * @param {Number} [opt.retryDelayMs=5000] 輸入重試間隔毫秒正整數,實際間隔為retryDelayMs乘以重試次數且上限15000ms,預設5000
280
+ * @returns {Promise} 回傳Promise,resolve回傳結果物件,內含ok(是否成功布林值)、stdout(answers之JSON字串)、stderr(失敗時之原始回應本體)、code(HTTP狀態碼,網路錯誤與逾時為null)、error(錯誤訊息字串,成功時為空字串)、errorType(僅失敗時,機器可讀錯誤類別字串,一覽見getErrorType.mjs檔頭)、durationMs(耗時毫秒)、attempts(實際嘗試次數)、usage(原始回應之token用量物件原樣透傳,欄位名為input_tokens/output_tokens,無則null)、answers(成功時為已解析之答案物件,否則null)、modelResolved(回應所載之實際模型版本字串,如'jev-1.13.0',無則''),本函數不會reject
281
+ * @example
282
+ * //need network and a TypeSafe api key, no cli required
283
+ *
284
+ * import dispatchApiTypesafeSystemone from './src/dispatchApiTypesafeSystemone.mjs'
285
+ *
286
+ * let test = async () => {
287
+ *
288
+ * let r = await dispatchApiTypesafeSystemone('房間浴室水龍頭一直滴水,吵到睡不著', {
289
+ * key: 'apikey_xxxxxx',
290
+ * questions: {
291
+ * category: {
292
+ * type: 'choice',
293
+ * instructions: '這則客房訊息屬於哪一類?',
294
+ * criteria: {
295
+ * '設備故障報修': '客人回報房間硬體設備損壞、水電問題或故障',
296
+ * '索取備品': '客人需要毛巾、牙刷、礦泉水等客房備品',
297
+ * '其他': null,
298
+ * },
299
+ * },
300
+ * urgent: { type: 'noul', instructions: '客人是否表達急迫性?' },
301
+ * },
302
+ * })
303
+ * console.log(r.ok, r.answers.category.choice, r.answers.urgent.noul)
304
+ * // => true 設備故障報修 0.86 (2026-09-17實測; noul為機率, 每次可能差0.01)
305
+ *
306
+ * let re = await dispatchApiTypesafeSystemone('abc', { key: 'apikey_bad', questions: { a: { type: 'noul', instructions: 'x?' } } })
307
+ * console.log(re.ok, re.code, re.errorType)
308
+ * // => false 401 http
309
+ *
310
+ * }
311
+ * await test()
312
+ * .catch((err) => {
313
+ * console.log(err)
314
+ * })
315
+ *
316
+ */
317
+ async function dispatchApiTypesafeSystemone(prompt, opt = {}) {
318
+
319
+ //check prompt, 不reject故以錯誤結果物件回報
320
+ if (!isestr(prompt)) {
321
+ return getErrorResult('prompt must be a non-empty string')
322
+ }
323
+
324
+ //questions必填且非空, 題型細節交伺服器驗證(回422)
325
+ let questions = get(opt, 'questions', null)
326
+ if (!iseobj(questions)) {
327
+ return getErrorResult('questions must be a non-empty object')
328
+ }
329
+
330
+ //baseURL, 無效回退官方端點
331
+ let baseURL = get(opt, 'baseURL', null)
332
+ if (!isestr(baseURL)) {
333
+ baseURL = DEFAULT_BASE_URL
334
+ }
335
+
336
+ //model, 無效回退官方預設
337
+ let model = get(opt, 'model', null)
338
+ if (!isestr(model)) {
339
+ model = DEFAULT_MODEL
340
+ }
341
+
342
+ //key, 無效代表不帶認證標頭
343
+ let key = get(opt, 'key', null)
344
+
345
+ //bodyExtra
346
+ let bodyExtra = get(opt, 'body', null)
347
+ if (!isobj(bodyExtra)) {
348
+ bodyExtra = {}
349
+ }
350
+
351
+ //headersExtra
352
+ let headersExtra = get(opt, 'headers', null)
353
+ if (!isobj(headersExtra)) {
354
+ headersExtra = {}
355
+ }
356
+
357
+ //timeoutMs
358
+ let timeoutMs = castPintOr(get(opt, 'timeoutMs', null), DEFAULT_TIMEOUT_MS)
359
+
360
+ //maxRetries
361
+ let maxRetries = get(opt, 'maxRetries', null)
362
+ if (!isp0int(maxRetries)) {
363
+ maxRetries = 0
364
+ }
365
+ else {
366
+ maxRetries = cint(maxRetries)
367
+ }
368
+
369
+ //retryDelayMs
370
+ let retryDelayMs = castPintOr(get(opt, 'retryDelayMs', null), DEFAULT_RETRY_DELAY_MS)
371
+
372
+ //validator
373
+ let validator = buildValidator(get(opt, 'validate', null))
374
+
375
+ //url, baseURL尾端斜線正規化後接上端點
376
+ let url = baseURL.replace(/\/+$/, '') + '/systemone'
377
+
378
+ //body, prompt即state; 額外鍵以bodyExtra為準
379
+ let body = { model, state: prompt, questions, ...bodyExtra }
380
+
381
+ //ids, 用於檢核回應是否每題皆有答案(以實際送出之questions為準)
382
+ let ids = Object.keys(isobj(body.questions) ? body.questions : questions)
383
+
384
+ //headers
385
+ let headers = { 'Content-Type': 'application/json', ...headersExtra }
386
+ if (isestr(key)) {
387
+ headers['Authorization'] = `Bearer ${key}`
388
+ }
389
+
390
+ let lastResult = null
391
+ let totalAttempts = 0
392
+
393
+ for (let attempt = 0; attempt &lt;= maxRetries; attempt++) {
394
+
395
+ //delay, 重試間隔隨次數遞增, 上限15000ms(同execCli)
396
+ if (attempt > 0) {
397
+ await delay(Math.min(retryDelayMs * attempt, MAX_RETRY_DELAY_MS))
398
+ }
399
+
400
+ lastResult = await callOnce(url, headers, body, ids, timeoutMs, validator)
401
+ totalAttempts = attempt + 1
402
+
403
+ if (lastResult.ok) {
404
+ lastResult.attempts = totalAttempts
405
+ return lastResult
406
+ }
407
+
408
+ //不可重試: 4xx(429除外)為客戶端錯誤, 重試無意義
409
+ let c = lastResult.code
410
+ if (isnum(c) &amp;&amp; c >= 400 &amp;&amp; c &lt; 500 &amp;&amp; c !== 429) {
411
+ break
412
+ }
413
+
414
+ }
415
+
416
+ lastResult.attempts = totalAttempts
417
+
418
+ return lastResult
419
+ }
420
+
421
+
422
+ export default dispatchApiTypesafeSystemone
423
+ </code></pre>
424
+ </article>
425
+ </section>
426
+
427
+
428
+
429
+
430
+
431
+
432
+ </div>
433
+
434
+ <br class="clear">
435
+
436
+ <footer>
437
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Sep 17 2026 13:48:00 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
438
+ </footer>
439
+
440
+ <script>prettyPrint();</script>
441
+ <script src="scripts/polyfill.js"></script>
442
+ <script src="scripts/linenumber.js"></script>
443
+
444
+
445
+
446
+ </body>
447
+ </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#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#NO_SIDE_EFFECT">NO_SIDE_EFFECT</a></li><li><a href="global.html#WDispatchAi">WDispatchAi</a></li><li><a href="global.html#adapters">adapters</a></li><li><a href="global.html#agyPrint">agyPrint</a></li><li><a href="global.html#attachErrorType">attachErrorType</a></li><li><a href="global.html#budgetFor">budgetFor</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#castPintOr">castPintOr</a></li><li><a href="global.html#collectAdditional">collectAdditional</a></li><li><a href="global.html#createFileStore">createFileStore</a></li><li><a href="global.html#createUsageCounter">createUsageCounter</a></li><li><a href="global.html#decodeJwtPayload">decodeJwtPayload</a></li><li><a href="global.html#defaultIntegratePrompt">defaultIntegratePrompt</a></li><li><a href="global.html#dfQuotaTimeoutMs">dfQuotaTimeoutMs</a></li><li><a href="global.html#dfTimeoutMs">dfTimeoutMs</a></li><li><a href="global.html#directWindow">directWindow</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#dispatchApiOpenaiResponses">dispatchApiOpenaiResponses</a></li><li><a href="global.html#dispatchApiTypesafeSystemone">dispatchApiTypesafeSystemone</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#extractOutputText">extractOutputText</a></li><li><a href="global.html#fetchQuotaJson">fetchQuotaJson</a></li><li><a href="global.html#firstStr">firstStr</a></li><li><a href="global.html#fromBucket">fromBucket</a></li><li><a href="global.html#fromCodexUsageHttp">fromCodexUsageHttp</a></li><li><a href="global.html#fromLimitItem">fromLimitItem</a></li><li><a href="global.html#fromRpcWindow">fromRpcWindow</a></li><li><a href="global.html#fromTopField">fromTopField</a></li><li><a href="global.html#fromWindow">fromWindow</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#getErrorType">getErrorType</a></li><li><a href="global.html#getQuotaAntigravity">getQuotaAntigravity</a></li><li><a href="global.html#getQuotaClaude">getQuotaClaude</a></li><li><a href="global.html#getQuotaCodex">getQuotaCodex</a></li><li><a href="global.html#initState">initState</a></li><li><a href="global.html#isKeyIndependentFail">isKeyIndependentFail</a></li><li><a href="global.html#pickWindow">pickWindow</a></li><li><a href="global.html#readBodyCapped">readBodyCapped</a></li><li><a href="global.html#readEnvFile">readEnvFile</a></li><li><a href="global.html#readJsonOrNull">readJsonOrNull</a></li><li><a href="global.html#redactText">redactText</a></li><li><a href="global.html#reorderByCooling">reorderByCooling</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><li><a href="global.html#salvageTruncatedArray">salvageTruncatedArray</a></li><li><a href="global.html#toQuotaLabel">toQuotaLabel</a></li><li><a href="global.html#toQuotaResult">toQuotaResult</a></li><li><a href="global.html#toQuotaScopedLabel">toQuotaScopedLabel</a></li><li><a href="global.html#toQuotaWindow">toQuotaWindow</a></li><li><a href="global.html#viaAppServer">viaAppServer</a></li><li><a href="global.html#viaHttp">viaHttp</a></li><li><a href="global.html#windowToSeconds">windowToSeconds</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -185,7 +185,7 @@ export default dispatchClaude
185
185
  <br class="clear">
186
186
 
187
187
  <footer>
188
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Sep 14 2026 12:59:17 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
188
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Thu Sep 17 2026 13:48:00 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
189
189
  </footer>
190
190
 
191
191
  <script>prettyPrint();</script>