@henjicc/ai-sdk 0.2.8 → 0.4.0

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 (244) hide show
  1. package/CHANGELOG.md +157 -141
  2. package/README.md +497 -455
  3. package/dist/capabilities/embedding/bailian.d.ts +23 -0
  4. package/dist/capabilities/embedding/bailian.js +10 -0
  5. package/dist/capabilities/embedding/bigmodel.d.ts +9 -0
  6. package/dist/capabilities/embedding/bigmodel.js +5 -0
  7. package/dist/capabilities/embedding/index.d.ts +1 -0
  8. package/dist/capabilities/embedding/index.js +1 -0
  9. package/dist/capabilities/embedding/ppio.d.ts +7 -0
  10. package/dist/capabilities/embedding/ppio.js +5 -0
  11. package/dist/capabilities/embedding/siliconflow.d.ts +21 -0
  12. package/dist/capabilities/embedding/siliconflow.js +10 -0
  13. package/dist/capabilities/embedding/volcengine.d.ts +10 -0
  14. package/dist/capabilities/embedding/volcengine.js +6 -0
  15. package/dist/capabilities/rerank/bailian.d.ts +21 -0
  16. package/dist/capabilities/rerank/bailian.js +14 -0
  17. package/dist/capabilities/rerank/bigmodel.d.ts +9 -0
  18. package/dist/capabilities/rerank/bigmodel.js +5 -0
  19. package/dist/capabilities/rerank/index.d.ts +1 -0
  20. package/dist/capabilities/rerank/index.js +1 -0
  21. package/dist/capabilities/rerank/ppio.d.ts +7 -0
  22. package/dist/capabilities/rerank/ppio.js +5 -0
  23. package/dist/capabilities/rerank/siliconflow.d.ts +21 -0
  24. package/dist/capabilities/rerank/siliconflow.js +10 -0
  25. package/dist/capabilities/retrieval/http.d.ts +3 -0
  26. package/dist/capabilities/retrieval/http.js +48 -0
  27. package/dist/capabilities/retrieval/module.d.ts +11 -0
  28. package/dist/capabilities/retrieval/module.js +110 -0
  29. package/dist/capabilities/retrieval/types.d.ts +54 -0
  30. package/dist/capabilities/retrieval/types.js +1 -0
  31. package/dist/capabilities/retrieval/validation.d.ts +10 -0
  32. package/dist/capabilities/retrieval/validation.js +65 -0
  33. package/dist/capabilities/types.d.ts +1 -1
  34. package/dist/catalog/apimart/gpt-image-2.5.model.d.ts +2 -0
  35. package/dist/catalog/apimart/gpt-image-2.5.model.js +51 -0
  36. package/dist/catalog/fal/gpt-image-2.5.model.d.ts +2 -0
  37. package/dist/catalog/fal/gpt-image-2.5.model.js +53 -0
  38. package/dist/catalog/fal/ic-light-v2.model.js +9 -13
  39. package/dist/catalog/grsai/gpt-image-2.5.model.d.ts +2 -0
  40. package/dist/catalog/grsai/gpt-image-2.5.model.js +54 -0
  41. package/dist/catalog/grsai/gptImage25Sizes.d.ts +1 -0
  42. package/dist/catalog/grsai/gptImage25Sizes.js +76 -0
  43. package/dist/catalog/index.js +112 -104
  44. package/dist/catalog/kie/gpt-image-2.5.model.d.ts +2 -0
  45. package/dist/catalog/kie/gpt-image-2.5.model.js +38 -0
  46. package/dist/catalog/shared/gptImage25.d.ts +16 -0
  47. package/dist/catalog/shared/gptImage25.js +48 -0
  48. package/dist/catalog/shared/gptImage25Pricing.d.ts +12 -0
  49. package/dist/catalog/shared/gptImage25Pricing.js +508 -0
  50. package/dist/llm/defaults.d.ts +1 -1
  51. package/dist/llm/defaults.js +1 -1
  52. package/dist/llm/discovery.d.ts +2 -0
  53. package/dist/llm/discovery.js +16 -5
  54. package/dist/llm/modelCatalogEntries.js +32 -0
  55. package/dist/llm/providerPresets.d.ts +3 -1
  56. package/dist/llm/providerPresets.js +6 -3
  57. package/dist/llm/providerReasoningRequest.js +14 -1
  58. package/dist/llm/siliconflow/index.d.ts +21 -0
  59. package/dist/llm/siliconflow/index.js +32 -0
  60. package/dist/llm/siliconflow/preset.d.ts +6 -0
  61. package/dist/llm/siliconflow/preset.js +33 -0
  62. package/dist/packs/models/apimart/gpt-image-2.5.d.ts +6 -0
  63. package/dist/packs/models/apimart/gpt-image-2.5.js +7 -0
  64. package/dist/packs/models/fal/gpt-image-2.5.d.ts +6 -0
  65. package/dist/packs/models/fal/gpt-image-2.5.js +7 -0
  66. package/dist/packs/models/grsai/gpt-image-2.5.d.ts +6 -0
  67. package/dist/packs/models/grsai/gpt-image-2.5.js +7 -0
  68. package/dist/packs/models/kie/gpt-image-2.5.d.ts +6 -0
  69. package/dist/packs/models/kie/gpt-image-2.5.js +7 -0
  70. package/dist/packs/provider-packs/apimart.d.ts +1 -1
  71. package/dist/packs/provider-packs/apimart.js +21 -20
  72. package/dist/packs/provider-packs/fal.d.ts +1 -1
  73. package/dist/packs/provider-packs/fal.js +37 -36
  74. package/dist/packs/provider-packs/grsai.d.ts +1 -1
  75. package/dist/packs/provider-packs/grsai.js +6 -5
  76. package/dist/packs/provider-packs/kie.d.ts +1 -1
  77. package/dist/packs/provider-packs/kie.js +28 -27
  78. package/dist/packs/tool-models/fal/{qwen-image-edit-2509-multiple-angles.d.ts → qwen-image-edit-2511-multiple-angles.d.ts} +1 -1
  79. package/dist/packs/tool-models/fal/{qwen-image-edit-2509-multiple-angles.js → qwen-image-edit-2511-multiple-angles.js} +1 -1
  80. package/dist/packs/tool-packs/fal-multi-angle-tools.js +1 -1
  81. package/dist/tool-packs/fal-multi-angle/models/qwen-image-edit-2511-multiple-angles.model.d.ts +2 -0
  82. package/dist/tool-packs/fal-multi-angle/models/{qwen-image-edit-2509-multiple-angles.model.js → qwen-image-edit-2511-multiple-angles.model.js} +20 -17
  83. package/docs/README.md +26 -26
  84. package/docs/consumers.md +56 -48
  85. package/docs/llm-adaptation/README.md +139 -137
  86. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206/DeepSeek.md +103 -91
  87. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206/Kimi.md +75 -75
  88. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206/MiniMax.md +84 -84
  89. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206//345/260/217/347/261/263MiMo.md +85 -85
  90. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206//346/231/272/350/260/261GLM.md +232 -232
  91. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206//347/201/253/345/261/261/345/274/225/346/223/216.md +87 -87
  92. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206//347/231/276/347/202/274Qwen.md +84 -84
  93. package/docs/llm-adaptation//346/226/207/346/241/243/351/207/207/351/233/206/346/211/213/345/206/214.md +88 -88
  94. package/docs/model-adaptation/Bria-Eraser/Bria-Eraser_Fal.md +32 -32
  95. package/docs/model-adaptation/Bria-/345/210/233/346/204/217/346/224/276/345/244/247/Bria-/345/210/233/346/204/217/346/224/276/345/244/247_Fal.md +31 -31
  96. package/docs/model-adaptation/ControlLight/ControlLight_Fal.md +85 -85
  97. package/docs/model-adaptation/FLUX-2-/345/244/232/350/247/222/345/272/246/FLUX-2-/345/244/232/350/247/222/345/272/246_Fal.md +107 -107
  98. package/docs/model-adaptation/Finegrain-Eraser/Finegrain-Eraser_Fal.md +31 -31
  99. package/docs/model-adaptation/Flux-Pro-Erase/Flux-Pro-Erase_Fal.md +34 -34
  100. package/docs/model-adaptation/Fun-ASR/Fun-ASR_/347/231/276/347/202/274.md +43 -43
  101. package/docs/model-adaptation/Fun-ASR-Flash-2026-06-15/Fun-ASR-Flash-2026-06-15_/347/231/276/347/202/274.md +41 -41
  102. package/docs/model-adaptation/Fun-ASR-Realtime/Fun-ASR-Realtime_/347/231/276/347/202/274.md +37 -37
  103. package/docs/model-adaptation/Fun-ASR-Realtime-2026-02-28/Fun-ASR-Realtime-2026-02-28_/347/231/276/347/202/274.md +39 -39
  104. package/docs/model-adaptation/GLM-5.3-Flash/GLM-5.3-Flash_/346/231/272/350/260/261.md +207 -207
  105. package/docs/model-adaptation/GPT-Image-2/GPT-Image-2_APIMart.md +173 -173
  106. package/docs/model-adaptation/GPT-Image-2/GPT-Image-2_Fal.md +94 -94
  107. package/docs/model-adaptation/GPT-Image-2/GPT-Image-2_Grsai.md +137 -137
  108. package/docs/model-adaptation/GPT-Image-2/GPT-Image-2_KIE.md +93 -93
  109. package/docs/model-adaptation/GPT-Image-2.5/GPT-Image-2.5_APIMart.md +66 -0
  110. package/docs/model-adaptation/GPT-Image-2.5/GPT-Image-2.5_Fal.md +55 -0
  111. package/docs/model-adaptation/GPT-Image-2.5/GPT-Image-2.5_Grsai.md +53 -0
  112. package/docs/model-adaptation/GPT-Image-2.5/GPT-Image-2.5_KIE.md +55 -0
  113. package/docs/model-adaptation/GPT-OSS-20B/GPT-OSS-20B_Groq.md +62 -62
  114. package/docs/model-adaptation/Gemini-Omni-Flash/Gemini-Omni-Flash_APIMart.md +124 -124
  115. package/docs/model-adaptation/Gemini-Omni-Flash/Gemini-Omni-Flash_Fal.md +84 -84
  116. package/docs/model-adaptation/Gemini-Omni-Flash/Gemini-Omni-Flash_KIE.md +129 -129
  117. package/docs/model-adaptation/Grok-Imagine/Grok-Imagine_KIE.md +36 -36
  118. package/docs/model-adaptation/Grok-Imagine-2.0/Grok-Imagine-2.0_APIMart.md +250 -250
  119. package/docs/model-adaptation/Grok-Imagine-2.0/Grok-Imagine-2.0_Fal.md +84 -84
  120. package/docs/model-adaptation/Grok-Imagine-2.0/Grok-Imagine-2.0_KIE.md +105 -105
  121. package/docs/model-adaptation/Hailuo-02/Hailuo-02_Fal.md +93 -93
  122. package/docs/model-adaptation/Hailuo-02/Hailuo-02_KIE.md +56 -56
  123. package/docs/model-adaptation/Hailuo-2.3/Hailuo-2.3_Fal.md +88 -88
  124. package/docs/model-adaptation/Hailuo-2.3/Hailuo-2.3_KIE.md +51 -51
  125. package/docs/model-adaptation/Hailuo-2.3/Hailuo-2.3_/346/264/276/346/254/247/344/272/221.md +70 -70
  126. package/docs/model-adaptation/IC-Light-v2/IC-Light-v2_Fal.md +97 -94
  127. package/docs/model-adaptation/Ideogram-/345/233/276/347/211/207/346/224/276/345/244/247/Ideogram-/345/233/276/347/211/207/346/224/276/345/244/247_Fal.md +41 -41
  128. package/docs/model-adaptation/Image-Apps-v2-/345/225/206/345/223/201/346/221/204/345/275/261/Image-Apps-v2-/345/225/206/345/223/201/346/221/204/345/275/261_Fal.md +72 -72
  129. package/docs/model-adaptation/Image-Apps-v2-/346/211/251/345/233/276/Image-Apps-v2-/346/211/251/345/233/276_Fal.md +93 -93
  130. package/docs/model-adaptation/Image-Apps-v2-/347/205/247/347/211/207/344/277/256/345/244/215/Image-Apps-v2-/347/205/247/347/211/207/344/277/256/345/244/215_Fal.md +86 -86
  131. package/docs/model-adaptation/Image-Apps-v2-/351/207/215/346/211/223/345/205/211/Image-Apps-v2-/351/207/215/346/211/223/345/205/211_Fal.md +84 -84
  132. package/docs/model-adaptation/Kling-3.0/Kling-3.0_APIMart.md +112 -112
  133. package/docs/model-adaptation/Kling-3.0/Kling-3.0_Fal.md +89 -89
  134. package/docs/model-adaptation/Kling-3.0/Kling-3.0_KIE.md +106 -106
  135. package/docs/model-adaptation/Kling-3.0/Kling-3.0_/346/264/276/346/254/247/344/272/221.md +119 -119
  136. package/docs/model-adaptation/Kling-3.0-Omni/Kling-3.0-Omni_APIMart.md +125 -125
  137. package/docs/model-adaptation/Kling-3.0-Omni/Kling-3.0-Omni_Fal.md +107 -107
  138. package/docs/model-adaptation/Kling-3.0-Omni/Kling-3.0-Omni_KIE.md +143 -143
  139. package/docs/model-adaptation/Kling-3.0-Turbo/Kling-3.0-Turbo_APIMart.md +85 -85
  140. package/docs/model-adaptation/Kling-3.0-Turbo/Kling-3.0-Turbo_Fal.md +83 -83
  141. package/docs/model-adaptation/Kling-3.0-Turbo/Kling-3.0-Turbo_KIE.md +84 -84
  142. package/docs/model-adaptation/Midjourney/Midjourney_APIMart.md +396 -396
  143. package/docs/model-adaptation/MiniMax-H3/MiniMax-H3_APIMart.md +234 -234
  144. package/docs/model-adaptation/MiniMax-H3/MiniMax-H3_Fal.md +108 -108
  145. package/docs/model-adaptation/MiniMax-H3/MiniMax-H3_KIE.md +111 -111
  146. package/docs/model-adaptation/MiniMax-Speech/MiniMax-Speech_/346/264/276/346/254/247/344/272/221.md +170 -170
  147. package/docs/model-adaptation/Nano-Banana-2/Nano-Banana-2_APIMart.md +89 -89
  148. package/docs/model-adaptation/Nano-Banana-2/Nano-Banana-2_Fal.md +99 -99
  149. package/docs/model-adaptation/Nano-Banana-2/Nano-Banana-2_Grsai.md +82 -82
  150. package/docs/model-adaptation/Nano-Banana-2/Nano-Banana-2_KIE.md +70 -70
  151. package/docs/model-adaptation/Nano-Banana-2-Lite/Nano-Banana-2-Lite_APIMart.md +79 -79
  152. package/docs/model-adaptation/Nano-Banana-2-Lite/Nano-Banana-2-Lite_Grsai.md +65 -65
  153. package/docs/model-adaptation/Nano-Banana-2-Lite/Nano-Banana-2-Lite_KIE.md +64 -64
  154. package/docs/model-adaptation/Nano-Banana-Pro/Nano-Banana-Pro_APIMart.md +83 -83
  155. package/docs/model-adaptation/Nano-Banana-Pro/Nano-Banana-Pro_Fal.md +89 -89
  156. package/docs/model-adaptation/Nano-Banana-Pro/Nano-Banana-Pro_Grsai.md +82 -82
  157. package/docs/model-adaptation/Nano-Banana-Pro/Nano-Banana-Pro_KIE.md +64 -64
  158. package/docs/model-adaptation/Pixelcut-/350/203/214/346/231/257/347/247/273/351/231/244/Pixelcut-/350/203/214/346/231/257/347/247/273/351/231/244_Fal.md +79 -79
  159. package/docs/model-adaptation/Qwen-Image-3.0/Qwen-Image-3.0_APIMart.md +117 -117
  160. package/docs/model-adaptation/Qwen-Image-3.0/Qwen-Image-3.0_Fal.md +84 -84
  161. package/docs/model-adaptation/Qwen-Image-3.0/Qwen-Image-3.0_KIE.md +103 -103
  162. package/docs/model-adaptation/Qwen-Image-3.0/Qwen-Image-3.0_/347/231/276/347/202/274.md +138 -138
  163. package/docs/model-adaptation/Qwen-Image-Edit-2511-/345/244/232/350/247/222/345/272/246/Qwen-Image-Edit-2511-/345/244/232/350/247/222/345/272/246_Fal.md +57 -0
  164. package/docs/model-adaptation/Qwen-MT-Flash/Qwen-MT-Flash_/347/231/276/347/202/274.md +47 -47
  165. package/docs/model-adaptation/Qwen-MT-Lite/Qwen-MT-Lite_/347/231/276/347/202/274.md +39 -39
  166. package/docs/model-adaptation/Qwen-MT-Plus/Qwen-MT-Plus_/347/231/276/347/202/274.md +39 -39
  167. package/docs/model-adaptation/Qwen3-ASR-Flash/Qwen3-ASR-Flash_/347/231/276/347/202/274.md +40 -40
  168. package/docs/model-adaptation/Qwen3-ASR-Flash-2026-02-10/Qwen3-ASR-Flash-2026-02-10_/347/231/276/347/202/274.md +33 -33
  169. package/docs/model-adaptation/Qwen3-ASR-Flash-Filetrans/Qwen3-ASR-Flash-Filetrans_/347/231/276/347/202/274.md +41 -41
  170. package/docs/model-adaptation/Qwen3-ASR-Flash-Realtime/Qwen3-ASR-Flash-Realtime_/347/231/276/347/202/274.md +35 -35
  171. package/docs/model-adaptation/Qwen3-ASR-Flash-Realtime-2026-02-10/Qwen3-ASR-Flash-Realtime-2026-02-10_/347/231/276/347/202/274.md +37 -37
  172. package/docs/model-adaptation/README.md +313 -295
  173. package/docs/model-adaptation/SeedASR-2.0-File/SeedASR-2.0-File_/347/201/253/345/261/261/345/274/225/346/223/216.md +115 -115
  174. package/docs/model-adaptation/SeedASR-2.0-Realtime/SeedASR-2.0-Realtime_/347/201/253/345/261/261/345/274/225/346/223/216.md +143 -143
  175. package/docs/model-adaptation/SeedVR2-/345/233/276/347/211/207/346/224/276/345/244/247/SeedVR2-/345/233/276/347/211/207/346/224/276/345/244/247_Fal.md +45 -45
  176. package/docs/model-adaptation/Seedance-2.0/Seedance-2.0_APIMart.md +121 -121
  177. package/docs/model-adaptation/Seedance-2.0/Seedance-2.0_Fal.md +97 -97
  178. package/docs/model-adaptation/Seedance-2.0/Seedance-2.0_KIE.md +86 -86
  179. package/docs/model-adaptation/Seedance-2.0-Fast/Seedance-2.0-Fast_APIMart.md +89 -89
  180. package/docs/model-adaptation/Seedance-2.0-Fast/Seedance-2.0-Fast_Fal.md +95 -95
  181. package/docs/model-adaptation/Seedance-2.0-Fast/Seedance-2.0-Fast_KIE.md +78 -78
  182. package/docs/model-adaptation/Seedance-2.0-Mini/Seedance-2.0-Mini_APIMart.md +89 -89
  183. package/docs/model-adaptation/Seedance-2.0-Mini/Seedance-2.0-Mini_Fal.md +96 -96
  184. package/docs/model-adaptation/Seedance-2.0-Mini/Seedance-2.0-Mini_KIE.md +78 -78
  185. package/docs/model-adaptation/Seedance-2.5/Seedance-2.5_APIMart.md +212 -212
  186. package/docs/model-adaptation/Seedance-2.5/Seedance-2.5_Fal.md +94 -94
  187. package/docs/model-adaptation/Seedance-2.5/Seedance-2.5_KIE.md +89 -89
  188. package/docs/model-adaptation/Seedream-5.0-Lite/Seedream-5.0-Lite_APIMart.md +106 -106
  189. package/docs/model-adaptation/Seedream-5.0-Lite/Seedream-5.0-Lite_Fal.md +91 -91
  190. package/docs/model-adaptation/Seedream-5.0-Lite/Seedream-5.0-Lite_KIE.md +89 -89
  191. package/docs/model-adaptation/Seedream-5.0-Lite/Seedream-5.0-Lite_/347/201/253/345/261/261/345/274/225/346/223/216.md +108 -108
  192. package/docs/model-adaptation/Seedream-5.0-Pro/Seedream-5.0-Pro_APIMart.md +194 -194
  193. package/docs/model-adaptation/Seedream-5.0-Pro/Seedream-5.0-Pro_Fal.md +100 -100
  194. package/docs/model-adaptation/Seedream-5.0-Pro/Seedream-5.0-Pro_KIE.md +141 -141
  195. package/docs/model-adaptation/Seedream-5.0-Pro/Seedream-5.0-Pro_/347/201/253/345/261/261/345/274/225/346/223/216.md +137 -137
  196. package/docs/model-adaptation/SenseVoiceSmall/SenseVoiceSmall_/347/241/205/345/237/272/346/265/201/345/212/250.md +69 -69
  197. package/docs/model-adaptation/TeleSpeechASR/TeleSpeechASR_/347/241/205/345/237/272/346/265/201/345/212/250.md +72 -72
  198. package/docs/model-adaptation/Topaz-/345/233/276/347/211/207/346/224/276/345/244/247/Topaz-/345/233/276/347/211/207/346/224/276/345/244/247_Fal.md +87 -87
  199. package/docs/model-adaptation/Topaz-/351/200/217/346/230/216/345/233/276/346/224/276/345/244/247/Topaz-/351/200/217/346/230/216/345/233/276/346/224/276/345/244/247_Fal.md +34 -34
  200. package/docs/model-adaptation/Wan-2.5-Preview/Wan-2.5-Preview_/346/264/276/346/254/247/344/272/221.md +82 -82
  201. package/docs/model-adaptation/Wan-2.6/Wan-2.6_/346/264/276/346/254/247/344/272/221.md +84 -84
  202. package/docs/model-adaptation/Wan-2.7/Wan-2.7_/346/264/276/346/254/247/344/272/221.md +122 -122
  203. package/docs/model-adaptation/Whisper-Large-v3/Whisper-Large-v3_Groq.md +76 -76
  204. package/docs/model-adaptation/Whisper-Large-v3-Turbo/Whisper-Large-v3-Turbo_Groq.md +75 -75
  205. package/docs/model-adaptation/Z-Image-Turbo/Z-Image-Turbo_APIMart.md +88 -88
  206. package/docs/model-adaptation/Z-Image-Turbo/Z-Image-Turbo_Fal.md +95 -95
  207. package/docs/model-adaptation/Z-Image-Turbo/Z-Image-Turbo_KIE.md +71 -71
  208. package/docs/model-adaptation/Z-Image-Turbo/Z-Image-Turbo_/347/231/276/347/202/274.md +122 -122
  209. package/docs/model-adaptation/Z-Image-Turbo/Z-Image-Turbo_/351/255/224/346/220/255.md +97 -97
  210. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206/APIMart.md +238 -238
  211. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206/Fal.md +172 -172
  212. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206/Groq.md +121 -121
  213. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206/Grsai.md +217 -217
  214. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206/KIE.md +131 -131
  215. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//345/200/231/351/200/211/344/276/233/345/272/224/345/225/206/350/260/203/347/240/224-/345/233/276/347/211/207/345/267/245/345/205/267.md +151 -151
  216. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//345/277/253/351/200/237/351/200/202/351/205/215/344/276/233/345/272/224/345/225/206.md +65 -65
  217. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//346/264/276/346/254/247/344/272/221.md +147 -138
  218. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//347/201/253/345/261/261/345/274/225/346/223/216.md +181 -171
  219. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//347/231/276/347/202/274.md +237 -227
  220. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//347/241/205/345/237/272/346/265/201/345/212/250.md +140 -75
  221. package/docs/model-adaptation//344/276/233/345/272/224/345/225/206//351/255/224/346/220/255.md +207 -207
  222. package/docs/model-adaptation//346/226/207/346/241/243/351/207/207/351/233/206/346/211/213/345/206/214.md +338 -311
  223. package/docs/model-adaptation//351/200/217/350/247/206/345/217/230/346/215/242//351/200/217/350/247/206/345/217/230/346/215/242_Fal.md +59 -59
  224. package/docs//346/216/245/345/205/245/346/214/207/345/215/227/Electron.md +77 -77
  225. package/docs//346/216/245/345/205/245/346/214/207/345/215/227/Tauri.md +81 -81
  226. package/docs//346/216/245/345/205/245/346/214/207/345/215/227/UXP.md +169 -169
  227. package/docs//346/216/245/345/205/245/346/214/207/345/215/227//344/276/233/345/272/224/345/225/206/345/237/237/345/220/215.md +83 -83
  228. package/docs//346/216/245/345/205/245/346/214/207/345/215/227//351/224/231/350/257/257/345/244/204/347/220/206.md +72 -72
  229. package/examples/form-renderer/README.md +17 -17
  230. package/examples/form-renderer/cli.ts +32 -32
  231. package/examples/form-renderer/index.ts +144 -144
  232. package/examples/form-renderer/package.json +16 -16
  233. package/examples/form-renderer/tsconfig.json +14 -14
  234. package/examples/llm-chat/README.md +32 -32
  235. package/examples/llm-chat/index.ts +100 -100
  236. package/examples/llm-chat/package.json +19 -19
  237. package/examples/llm-chat/tsconfig.json +14 -14
  238. package/examples/minimal-node/README.md +31 -31
  239. package/examples/minimal-node/index.ts +138 -138
  240. package/examples/minimal-node/package.json +17 -17
  241. package/examples/minimal-node/tsconfig.json +14 -14
  242. package/package.json +255 -195
  243. package/dist/tool-packs/fal-multi-angle/models/qwen-image-edit-2509-multiple-angles.model.d.ts +0 -2
  244. package/docs/model-adaptation/Qwen-Image-Edit-2509-/345/244/232/350/247/222/345/272/246/Qwen-Image-Edit-2509-/345/244/232/350/247/222/345/272/246_Fal.md +0 -116
package/README.md CHANGED
@@ -1,472 +1,514 @@
1
- # @henjicc/ai-sdk
2
-
3
- 痕迹AI 的多供应商模型 SDK:内含 8 个生成供应商、105 个图片/视频/音频模型,以及
4
- 7 LLM 供应商预设(加上派欧云聚合入口共 8 个预设项)和 15 个按需 ASR 模型。另有 12 个 FAL 图片工具使用独立按需入口,不进入默认 105 模型目录。预制 LLM 会按供应商与具体模型自动选择 Responses API 或 Chat Completions,宿主不需要暴露逐模型协议设置。SDK 负责目录、请求构建、媒体预处理、
5
- 供应商调用、轮询、SSE 与错误归一化;宿主只需注入网络、凭据、媒体读取和日志。
6
-
1
+ # @henjicc/ai-sdk
2
+
3
+ 痕迹AI 的多供应商模型 SDK:内含 8 个生成供应商、109 个图片/视频/音频模型,以及
4
+ 10 LLM 供应商预设和 15 个按需 ASR 模型。另有 12 个 FAL 图片工具使用独立按需入口,不进入默认 109 模型目录。预制 LLM 会按供应商与具体模型自动选择 Responses API 或 Chat Completions,宿主不需要暴露逐模型协议设置。SDK 负责目录、请求构建、媒体预处理、
5
+ 供应商调用、轮询、SSE 与错误归一化;宿主只需注入网络、凭据、媒体读取和日志。
6
+
7
7
  ## 5 分钟快速开始
8
8
 
9
- SDK `0.2.8` 公开发布在 npm,无需配置 registry 或访问令牌:
10
-
11
- ```bash
12
- npm install @henjicc/ai-sdk@0.2.8
13
- ```
14
-
15
- 然后提供 4 个宿主能力(`Transport` / `CredentialStore` / `MediaReader` / `Logger`),创建客户端:
16
-
17
- ```ts
18
- import { readFile } from 'node:fs/promises'
19
- import { basename } from 'node:path'
20
- import { createAIClient, type RuntimeContext } from '@henjicc/ai-sdk'
21
-
22
- const runtime: RuntimeContext = {
23
- transport: { fetch: (url, init) => fetch(url, init) },
24
- credentials: {
25
- get: (scope, providerId) =>
26
- scope === 'generation' && providerId === 'kie' ? process.env.KIE_API_KEY : undefined,
27
- },
28
- media: {
29
- read: async (ref) => ({
30
- bytes: new Uint8Array(await readFile(ref)),
31
- mimeType: 'image/png',
32
- filename: basename(ref),
33
- }),
34
- },
35
- logger: {
36
- info: console.log,
37
- warn: console.warn,
38
- error: console.error,
39
- },
40
- }
41
-
42
- const client = createAIClient({ runtime })
43
- try {
44
- const params = { prompt: 'A blue paper boat', kieZImageAspectRatio: '1:1' }
45
- const created = await client.generate({ modelId: 'kie-z-image', params })
46
- const result = created.status === 'pending' && created.taskId
47
- ? await client.continuePolling({ modelId: 'kie-z-image', taskId: created.taskId, params })
48
- : created
49
- console.log(result.url) // SDK 返回 URL;宿主决定是否下载落盘
50
- } finally {
51
- client.dispose()
52
- }
53
- ```
54
-
55
- 可直接运行的 Node 版本在 [examples/minimal-node](examples/minimal-node/README.md);它先提供零网络
56
- `dry-run`,并为付费创建请求加了单次外网闸门。
57
-
58
- ## 宿主契约
59
-
60
- | 接口 | 宿主必须保证 |
61
- |---|---|
62
- | `Transport.fetch` | 返回标准 `Response`,保留 4xx/5xx 响应,网络失败抛异常,尊重 `AbortSignal` |
63
- | `CredentialStore.get` | 按 scope/providerId 读取明文密钥;未配置或丢失时返回 `undefined` |
64
- | `MediaReader.read` | 将宿主的本地/受管引用转成 `Uint8Array + mimeType + filename` |
65
- | `Logger` | 可选;不得记录 API key/token/cookie/授权头 |
66
- | `Tracer` | 可选;缺省为 no-op |
67
-
68
- 生成和 LLM 取消都必须带命名空间:
69
- `client.cancel({ namespace: 'generation' | 'llm', taskId })`。自定义 provider 使用进程级注册表,
70
- 同 ID 并发注册会拒绝;持有它的 client 退出时必须 `dispose()`。
71
-
72
- 供应商官网与 API Key 入口由 SDK 统一提供,宿主不需要再维护一份链接表:
73
-
74
- ```ts
75
- import { findProviderMetadata } from '@henjicc/ai-sdk'
76
-
77
- const provider = findProviderMetadata('kie')
78
- console.log(provider?.websiteUrl, provider?.apiKeyUrl)
79
-
80
- // 同一供应商的区域站点通过 endpointProfile 选择。
81
- const zAi = findProviderMetadata('bigmodel', { endpointProfile: 'global' })
82
- ```
83
-
84
- LLM 预设默认使用 SDK 维护的官方地址,并按具体模型选择 Chat Completions 或 Responses。宿主若允许高级用户修改连接信息,应把主动修改写入
85
- `setup.connectionOverrides`;字段缺省时保持自动路由,不要把 SDK 的默认值复制成覆盖值。
86
-
87
- `websiteUrl` 是面向用户的实际跳转入口;派欧云、KIE、APIMart 会保留项目配置的邀请码,
88
- 其余供应商使用正常官网。未知的自定义供应商返回 `null`,SDK 不猜测地址。
89
-
90
- ## 接入文档与示例
9
+ ### 硅基流动聊天与实时模型列表
91
10
 
92
- - [SDK 消费项目清单](docs/consumers.md)
93
- - [Electron 主进程适配](docs/接入指南/Electron.md)
94
- - [Tauri 2 适配](docs/接入指南/Tauri.md)
95
- - [Photoshop UXP 适配](docs/接入指南/UXP.md)
96
- - [供应商域名与白名单](docs/接入指南/供应商域名.md)
97
- - [错误处理](docs/接入指南/错误处理.md)
98
- - [Node KIE 生成](examples/minimal-node/README.md)
99
- - [5 模型表单契约](examples/form-renderer/README.md)
100
- - [LLM 流式对话](examples/llm-chat/README.md)
101
-
102
- ## 发布形式与可移植性
103
-
104
- 发布产物是保留模块边界的 ESM + `.d.ts`,没有 CJS `require` 入口。CommonJS 项目请用
105
- 动态 `import()`。UXP/Tauri 必须在构建期用 Vite/Rollup/webpack/esbuild 打包实际使用的 ESM 依赖。
106
- SDK 源码不得依赖 `@/`、`node:`、Electron、`import.meta.glob`、`eval`/`new Function`/`node:vm`;
107
- `npm run check:sdk` 会守住这些边界。Photoshop/受限宿主只做生成时应从
108
- `@henjicc/ai-sdk/generation` 导入 `createGenerationClient`;该入口不静态带入 LLM、Vercel AI SDK、
109
- Node 内置模块或 Fal 官方客户端,发布门禁会把它打成 IIFE 并在无网络生命周期中核对 105 个模型。
110
-
111
- ## 按需装配生成模型
112
-
113
- `@henjicc/ai-sdk/generation` 是兼容入口,默认始终装入 105 个模型。真正需要缩小 Photoshop/Tauri
114
- 包体时,从不含任何内置 catalog/provider 的 `generation/core` 创建模块化客户端,并只导入完整 pack:
115
-
116
- ```ts
117
- import { createModularGenerationClient } from '@henjicc/ai-sdk/generation/core'
118
- import { pack as kieZImage } from '@henjicc/ai-sdk/models/kie/z-image'
119
-
120
- const client = createModularGenerationClient({ runtime, packs: [kieZImage] })
121
- console.log(client.catalog.list().map((model) => model.meta.id)) // ['kie-z-image']
122
- ```
123
-
124
- 完整单模型 pack 同时携带该模型的唯一真实 schema、provider adapter 与 provider-scoped 媒体预处理/
125
- 上传策略;宿主不需要知道内部上传模块。`@henjicc/ai-sdk/provider-packs/kie` 可一次装入 KIE 的全部
126
- 27 个模型;`provider-adapters/kie` 只装入 KIE 执行与上传策略、不装任何模型。所有 105 个单模型路径和
127
- 8 个供应商路径由 catalog 生成器自动产出并由 bundle 门禁穷举,新增模型不会靠手工维护 exports。
128
-
129
- 每个 `models/<provider>/<model>` 子路径也导出名为 `model` 的低层定义,供目录分析或高级自定义组合;
130
- 直接传裸 `model` 而不传同文件的 `pack` 不保证媒体上传或供应商执行完整,普通宿主应使用 `pack`。
131
- 包根 `createAIClient` 仍默认 105 模型;若确实需要根 client 的 chat 与按需生成共存,可显式传:
132
-
133
- ```ts
134
- const client = createAIClient({
135
- runtime,
136
- generation: { mode: 'modular', packs: [kieZImage] },
137
- })
138
- ```
139
-
140
- 普通 LLM 宿主可直接导入 `@henjicc/ai-sdk/llm`。Photoshop UXP 等禁止字符串代码生成的受限宿主
141
- 必须改用 `@henjicc/ai-sdk/llm/streaming`:它只提供原生 OpenAI-compatible SSE 的
142
- `runLlmChatStream`、`cancelLlmChatTask` 与必要类型/错误,不会进入 modelStep、Zod、Vercel AI SDK
143
- 或 generation 静态图。两条入口复用同一份原生流式实现,不存在功能分叉。
11
+ `llm/siliconflow` 提供四个推荐预设(DeepSeek V4 Flash、GLM-5.3、Kimi K2.7 Code、Qwen3.8-27B),并通过官方 `GET /v1/models` 获取账号当前可用模型,不受预设名单限制。
144
12
 
145
13
  ```ts
146
- import {
147
- cancelLlmChatTask,
148
- runLlmChatStream,
149
- type LlmChatRequestDto,
150
- type RuntimeContext,
151
- } from '@henjicc/ai-sdk/llm/streaming'
14
+ import { discoverSiliconflowModels, runSiliconflowChatStream } from '@henjicc/ai-sdk/llm/siliconflow'
152
15
 
153
- const request: LlmChatRequestDto = {
154
- requestId: 'chat-1', providerId: 'openai', modelId: 'gpt-5-mini',
16
+ const models = await discoverSiliconflowModels(runtime, { modelType: 'chat' })
17
+ // modelType 也支持 embedding / reranker;分别读取 llm / embedding / rerank 凭据。
18
+ const result = await runSiliconflowChatStream({
19
+ modelId: 'deepseek-ai/DeepSeek-V4-Flash',
155
20
  messages: [{ role: 'user', content: '你好' }],
156
- }
157
- const result = await runLlmChatStream(request, 'chat-1', onStreamEvent, runtime as RuntimeContext)
158
- console.log(result.output, result.reasoningOutput, result.usage, result.finishReason)
159
- cancelLlmChatTask('chat-1')
21
+ }, 'chat-1', event => console.log(event), runtime)
160
22
  ```
161
23
 
162
- ### 可选模型分发包与统一能力筛选
24
+ 动态列表不提供完整能力或价格,缺失的上下文与输出限制保持 `null`。新模型可直接传入 `modelId`;宿主按官方资料提供能力配置。硅基流动的 V4 Flash 与 DeepSeek 官方默认 `deepseek-flash`(V4.1)不同,全局默认不变。详见[硅基流动适配资料](docs/model-adaptation/供应商/硅基流动.md)。
163
25
 
164
- 当前 12 个 FAL 图片工具不会混入默认 105 模型。宿主可选择单个完整工具模型 pack,也可按用户任务装入三个聚合包:
26
+ ### 文本向量与重排序
165
27
 
166
- - `tool-packs/fal-image-edit-tools`:3 个消除工具。
167
- - `tool-packs/fal-image-utility-tools`:6 个重打光、暗光增强、扩图、商品摄影、照片修复和背景移除工具。
168
- - `tool-packs/fal-multi-angle-tools`:3 个连续镜头控制或离散方位工具。
28
+ 通过 `capabilities/embedding/<provider>` 和 `capabilities/rerank/<provider>` 按需导入。硅基流动、百炼、派欧云和智谱支持两类能力;火山目前支持单条文本向量。模型清单与限制见 [检索适配资料](docs/model-adaptation/README.md#文本-embedding--rerank2026-09-11)。输入仅支持文本;不自动切块、重试或合并多次付费请求。
169
29
 
170
30
  ```ts
171
- import { createModularGenerationClient } from '@henjicc/ai-sdk/generation/core'
172
- import { createModelCapabilityDiscovery } from '@henjicc/ai-sdk/discovery'
173
- import { pack as falImageEditTools } from '@henjicc/ai-sdk/tool-packs/fal-image-edit-tools'
174
- import { pack as falImageUtilityTools } from '@henjicc/ai-sdk/tool-packs/fal-image-utility-tools'
175
-
176
- const eraseDiscovery = createModelCapabilityDiscovery({ generationPacks: [falImageEditTools] })
177
- const utilityDiscovery = createModelCapabilityDiscovery({ generationPacks: [falImageUtilityTools] })
178
- const erasers = eraseDiscovery.search({
179
- providerIds: 'fal',
180
- outputModalities: 'image',
181
- operations: 'image-edit',
182
- features: 'erase',
183
- })
184
- const utilities = utilityDiscovery.search({ providerIds: 'fal', outputModalities: 'image' })
185
- const client = createModularGenerationClient({
186
- runtime,
187
- packs: [falImageEditTools, falImageUtilityTools],
188
- })
189
- console.log(erasers.map((item) => item.id))
190
- console.log(utilities.map((item) => item.id))
191
- ```
192
-
193
- 单模型入口按集合分为:
194
-
195
- - 消除:`tool-models/fal/flux-pro-erase`、`tool-models/fal/bria-eraser`、`tool-models/fal/finegrain-eraser`。
196
- - 图片实用工具:`tool-models/fal/relighting`、`tool-models/fal/control-light`、`tool-models/fal/outpaint`、`tool-models/fal/product-photography`、`tool-models/fal/photo-restoration`、`tool-models/fal/pixelcut-background-removal`。
197
- - 多角度:`tool-models/fal/qwen-image-edit-2509-multiple-angles`、`tool-models/fal/perspective-change`、`tool-models/fal/flux-2-multiple-angles`。
198
-
199
- 每个单模型入口只导出 `model`、`provider` 与完整 `pack`。三个聚合包只携带各自 3 / 6 / 3 个工具模型、Fal adapter 和 Fal CDN 上传,不携带其余 105 模型或 LLM。能力筛选与分发是两层:`search()` 只过滤已经导入的候选,不会让已经进入 bundle 的代码自动消失;缩小包体仍必须显式选择单模型/provider/collection pack。
200
-
201
- Henji-AI 在执行层按需装入工具 pack,但普通模型选择器、`@henjicc/ai-sdk/generation` 与默认能力发现仍只展示 105 个主目录模型。
202
-
203
- ## 两类模型的公共边界
204
-
205
- 生成模型与 LLM 共用以下基础设施:
206
-
207
- | 能力 | 统一实现 | 约束 |
208
- |---|---|---|
209
- | 凭据 | `RuntimeContext.credentials` / `CredentialStore` | 用 `generation`、`llm` scope 隔离宿主密钥空间 |
210
- | 网络 | `Transport` + `fetchProvider` | 只自动重试可证明尚未建连的错误,避免重放可能计费的请求 |
211
- | 错误 | `runtime/errors.ts` + `runtime/error-classify.ts` | 生成错误码字符串保持稳定;LLM 保留鉴权、余额、限流、上下文、内容过滤等细分类 |
212
- | 取消 | `runtime/task-registry.ts` | 单一 registry,以 `generation` / `llm` 命名空间隔离同名任务 |
213
- | 重试判断 | `shouldRetry(error, mode)` | `safe-preconnect`、`request`、`poll-query` 共用分类,但策略生命周期不同 |
214
- | 追踪 | `RuntimeContext.tracer` | SDK 只报告通用 span;助手专属 trace 由痕迹AI 宿主持有 |
215
-
216
- 以下协议刻意保持分离:
217
-
218
- - 生成模型是“创建任务 → 可选轮询 → 提取媒体结果”,允许长时间轮询,并容忍状态查询的连续瞬态失败。
219
- - LLM 是 SSE 流式或 Vercel 模型步,持续输出 token / tool call,单次请求失败按模型步策略处理。
220
-
221
- 二者的终止条件、进度含义、结果形状和可安全重试边界都不同。把它们压成一个通用 `execute()`
222
- 只会隐藏协议差异,无法形成可靠抽象;第五阶段统一客户端只应在入口层分组编排,不应合并生命周期。
31
+ import { createCapabilityClient } from '@henjicc/ai-sdk/capabilities'
32
+ import { createSiliconflowEmbeddingModule } from '@henjicc/ai-sdk/capabilities/embedding/siliconflow'
33
+ import { createSiliconflowRerankModule } from '@henjicc/ai-sdk/capabilities/rerank/siliconflow'
223
34
 
224
- ## 目录与参数表单契约
225
-
226
- 消费方从 client 私有目录读取模型,不需要自行复刻 canonical/alias 索引规则:
227
-
228
- ```ts
229
- const images = client.catalog.listByType('image')
230
- const falModels = client.catalog.listByProvider('fal')
231
- const editors = client.catalog.listByTag('supports-image-editing')
232
- const params = client.catalog.getParams('fal-ai-gpt-image-2')
233
- const defaults = client.catalog.getDefaultValues('fal-ai-gpt-image-2')
234
- const price = client.catalog.estimatePrice('fal-ai-gpt-image-2', defaults)
235
- ```
236
-
237
- 价格依赖本地图片像素或视频时长时,模型会在 `pricing.mediaContext` 声明所需指标。消费方从
238
- `@henjicc/ai-sdk/pricing` 调用 `resolvePricingMediaContext()`,只需注入自身的图片/视频元数据读取器;
239
- SDK 统一处理媒体来源优先级、首个/求和聚合、固定倍率和参数倍率换算,再把结果交给原模型 calculator。
240
- 指标无法读取时返回 `complete: false`,消费方应隐藏总价,而不是显示最低档兜底价。
241
-
242
- `getParams()` 返回纯运行时 `RuntimeParamDef[]`。参数名、选项 label、图标、分组布局、linkages 和
243
- 痕迹AI 特有 composite 面板配置属于应用 presentation,不在 SDK 目录里;通用消费方可以用参数 ID
244
- 作最小标签,也可以在宿主维护自己的本地化展示层。`composite` 只保证值类型/default/API 契约,宿主
245
- 必须按参数 ID 注入自定义组件,不能从 SDK 还原痕迹AI 专属面板。
246
-
247
- ### 参数类型 → 控件
248
-
249
- 以下 13 种是 `RuntimeParamDef` 的完整公开联合;括号内是当前真实 105 catalog 的出现数量。未出现不代表
250
- 类型无效,而是当前目录没有对应模型。
251
-
252
- | type | 105 catalog | 消费方控件 | 关键运行时字段 |
253
- |---|---:|---|---|
254
- | `dropdown` | 298 | 下拉选择 | `options[].value`、`default`、`required?` |
255
- | `switch` | 92 | 布尔开关 | `default` |
256
- | `number` | 83 | 数值输入/步进器 | `min?`、`max?`、`step?`、`default` |
257
- | `text` | 7 | 单行文本 | `maxLength?`、`default` |
258
- | `image-upload` | 5 | 图片上传 | `maxCount?`、`accept?`、`maxSize?`、`format?` |
259
- | `composite` | 4 | 宿主自定义组件钩子 | `valueType?`、`default`;panel/config 不在 SDK |
260
- | `textarea` | 3 | 多行文本 | `maxLength?`、`default` |
261
- | `file-upload` | 1 | 文件上传 | `maxCount?`、`accept?`、`maxSize?` |
262
- | `radio` | 0 | 单选组 | `options[].value`、`default` |
263
- | `panel` | 0 | 递归分组容器 | `children[]`;布局样式由宿主决定 |
264
- | `video-upload` | 0 | 视频上传 | `maxCount?`、`accept?`、`maxSize?`、时长范围 |
265
- | `resolution` | 0 | 分辨率选择 | `presets[].value`、`allowCustom?` |
266
- | `aspect-ratio` | 0 | 比例选择 | `options[].value` |
267
-
268
- 所有参数共有 `id`、`type`、`order`、`default`,并可带 `required`、`valueType`、API 映射、
269
- `transferKey`、`visible`、`disabled`。实际 105 catalog 的字段集合与数量由
270
- `packages/ai-sdk/tests/catalog-consumer-contract.test.ts` 穷举锁定,不以旧 ParamDef 文件或示例推断。
271
-
272
- ### 条件与媒体输入
273
-
274
- - `evaluateRuntimeCondition()` 是条件显隐/inputLimits/requirements 的公共判断入口。函数条件直接调用;
275
- 字符串条件使用受限 parser,支持真实 catalog 用到的标识符、`.length`、字面量、`typeof`、比较、
276
- `&&`/`||`/`!`、括号和 `Array.isArray()`。它不使用 `eval`/`new Function`;未知 token、属性或调用
277
- 会抛出明确错误,不会静默判为 false。
278
- - `resolveRuntimeInputLimits()` 解析数据型/函数型输入限制并应用条件规则。
279
- - `getRuntimeMediaInputContract()` 把 `inputLimits` 的通用图片/视频/音频入口、显式
280
- `image-upload`/`video-upload`/`file-upload` 参数,以及 `runtimeConstraints.mediaFields` 的特殊请求字段
281
- 分层返回。消费方必须据此渲染上传组件;不存在 URL 文本框 fallback。
282
-
283
- 最小无框架验证器位于 `examples/form-renderer/`。它用 5 个真实模型覆盖普通选择、数值范围、条件显隐、
284
- 通用与特殊媒体上传、composite 自定义钩子,可作为无 UI 框架的最小接入参考。
285
-
286
- 本包不发布 JSON catalog 快照。Tauri/UXP 消费端都能在构建期使用 ESM,而真实目录包含 builder、
287
- 计价、显隐和 inputLimits 函数,JSON 无法无损表达;并行发布不完整快照会形成第二份真相。未来只有出现
288
- 明确的非 JavaScript/TypeScript 消费方时,才应另行设计带版本的可序列化投影契约。
289
-
290
- ## 扩展模型类型与供应商
291
-
292
- `ModelType` 与 `ProviderId` 都采用“内置字面量 + 开放字符串”的形式:编辑器仍会提示
293
- `image` / `video` / `audio` 和 8 个内置供应商,同时消费方可以直接声明自己的类型与 provider id。
294
- 下面的 TypeScript 示例不新增真实模型或供应商,只演示完整的注册、索引与请求构建机制:
295
-
296
- ```ts
297
- import {
298
- buildRequest,
299
- createModelIndex,
300
- defineModel,
301
- registerProvider,
302
- unregisterProvider,
303
- } from '@henjicc/ai-sdk'
304
-
305
- const providerId = 'acme-transcript'
306
-
307
- async function main(): Promise<void> {
308
- registerProvider(providerId, {
309
- execute: async (input) => ({
310
- status: 'completed',
311
- url: 'memory://result',
312
- metadata: { requestBody: input.body },
313
- }),
314
- continuePolling: async () => ({
315
- status: 'failed',
316
- url: '',
317
- metadata: { reason: 'not-supported' },
318
- }),
319
- })
320
-
321
- try {
322
- const model = defineModel({
323
- meta: {
324
- id: 'acme-transcript-v1',
325
- canonicalModelId: 'acme-transcript-v1',
326
- provider: providerId,
327
- type: 'transcript',
328
- },
329
- params: [{ id: 'text', type: 'text', order: 1, default: '' }],
330
- endpoints: '/v1/transcript',
331
- request: { builder: (params) => ({ input: params.text }) },
332
- pricing: { currency: '$', fixed: 0 },
333
- })
334
-
335
- const index = createModelIndex([model])
336
- const request = await buildRequest(
337
- { text: 'hello' },
338
- index.get('acme-transcript-v1'),
339
- )
340
- console.log(request)
341
- } finally {
342
- unregisterProvider(providerId)
343
- }
344
- }
345
-
346
- void main()
347
- ```
348
-
349
- 注册表语义是确定的:`registerProvider` 遇到同名 id 会抛
350
- `provider_already_registered`,不会覆盖既有适配器;`unregisterProvider` 删除成功返回 `true`,
351
- 未登记返回 `false`;`listProviders` 返回快照,修改返回数组不会改动注册表。插件与测试应使用唯一 id,
352
- 并在 `finally` / `afterEach` 中注销。SDK 在首次访问 provider 注册表时惰性初始化 APIMart、Bailian、
353
- Volcengine、PPIO、KIE、ModelScope、Fal、Grsai 八个内置供应商;调用方无需手工初始化。惰性初始化
354
- 避免依赖仅靠模块加载保留的副作用,使 `sideEffects: false` 与 tree-shaking 语义一致。
355
-
356
- ### 跨模型类型的统一能力画像
357
-
358
- `@henjicc/ai-sdk/discovery` 只负责发现和筛选,不改变 generation、LLM 或扩展模块各自的执行协议。
359
- 画像从已导入候选的真实 schema 派生,统一提供 provider、输出模态、operation、输入/输出内容类型、
360
- features 与原始 tags。顶层查询维度默认 AND,也可设 `mode: 'any'`;单一维度可用
361
- `{ anyOf: [...] }` / `{ allOf: [...] }` 表达 OR/AND。
362
-
363
- 标准 operation 覆盖图片生成/编辑、视频文生/图生/参考/编辑、音频生成、chat、语音识别和 OCR,
364
- 同时保留开放字符串。筛选结果用 `sourceKind` 区分 `generation-model`、`llm-model`、`extension`,
365
- 调用方随后交给对应执行 handle;SDK 不提供一个掩盖协议差异的通用 `generate()`。
366
-
367
- 能力画像是运行时选择层,不是打包器。`createModelCapabilityDiscovery({ generationPacks: [...] })` 只会看
368
- 传入的 pack;它既不会隐式导入默认 105,也不会从 bundle 删除已导入代码。真正的按需分发仍以 import
369
- 单模型/provider/collection pack 为边界。
370
-
371
- ### ASR/OCR 等开放能力
372
-
373
- ASR、OCR 不属于图片/视频/音频生成的 `ModelType`,SDK 不再要求把它们伪装成媒体生成模型。
374
- `@henjicc/ai-sdk/capabilities` 提供独立的开放模块协议:
375
-
376
- ```ts
377
- import { createCapabilityClient, type CapabilityModule } from '@henjicc/ai-sdk/capabilities'
378
-
379
- const speechRecognition: CapabilityModule<{ audio: Uint8Array }, { text: string }> = {
380
- descriptor: {
381
- id: 'my.speech-recognition',
382
- kind: 'speech-recognition',
383
- source: { kind: 'external', namespace: '@example/my-asr' },
384
- contract: {
385
- input: [{ kind: 'audio', required: true }],
386
- output: [{ kind: 'text', required: true }],
387
- },
388
- },
389
- execute: async ({ audio }, { signal }) => runLocalAsr(audio, signal),
390
- }
391
-
392
- const capabilities = createCapabilityClient({ runtime })
393
- const asr = capabilities.register(speechRecognition)
394
- const result = await asr.execute({ audio: bytes }, { requestId: 'asr-1' })
395
- await capabilities.unregister(speechRecognition.descriptor.id)
396
- await capabilities.dispose()
397
- ```
398
-
399
- `CapabilityKind` 与输入/输出 `CapabilityContentKind` 都是开放字符串;`source.namespace` 是包或插件的
400
- 稳定所有者 ID,用于冲突诊断和批量卸载。模块执行上下文统一带
401
- `RuntimeContext`、`AbortSignal`、requestId、Logger 与 Tracer。client 提供注册、发现、类型化执行、取消、
402
- 注销、`unregisterSource(namespace)` 和 dispose,并统一错误边界。跨类型筛选使用上面的
403
- `ModelCapabilityProfile`;执行仍走各自稳定的轮询、流式或扩展 handle,不复制协议。
404
-
405
- 以下可选供应商入口只有显式 import 才进入消费方 bundle:
406
-
407
- - `capabilities/speech-recognition/bailian`:5 个百炼短音频/文件 ASR;
408
- - `capabilities/speech-recognition/bailian/realtime`:4 个百炼 Fun-ASR/Qwen 实时 ASR;
409
- - `capabilities/speech-recognition/volcengine`:SeedASR 2.0 文件 submit/query;官方标准版只接受公网 URL;
410
- - `capabilities/speech-recognition/volcengine/realtime`:SeedASR 2.0 gzip 二进制 WebSocket 实时识别;
411
- - `capabilities/speech-recognition/siliconflow`:SenseVoiceSmall 与 TeleSpeechASR multipart 文件转写;
412
- - `capabilities/speech-recognition/groq`:Whisper Large v3 Turbo/v3 文件转写与可选词/句时间戳;
413
- - `capabilities/translation/bailian`:Qwen-MT Flash/Plus/Lite;
414
- - `llm/groq`:Groq GPT-OSS 20B 默认配置、流式聊天和模型发现。
415
- - `llm/bigmodel`:智谱同一 provider family 下的中国大陆/Global 端点 profile、独立凭据槽与 GLM-5.3-Flash 能力。
416
- - `llm/modules`:外部包、插件与内置 LLM 共用的注册、执行、发现、取消和 namespace 卸载边界。
417
-
418
- ASR module ID 固定为 `<providerId>.speech-recognition.<modelId>`,翻译固定为
419
- `bailian.translation.<modelId>`;供应商 ID 使用 `bailian` / `volcengine` / `siliconflow` / `groq`,
420
- 没有 `funasr` 兼容供应商别名。火山文件标准版不会读取本地 bytes/media-ref;宿主必须先通过自己受控的
421
- 对象存储发布成供应商可访问 URL。SDK 不提供公共 URL 文本框或冒充上传成功的回退路径。
422
-
423
- 外部 LLM 不属于 ASR/translation `CapabilityModule`。宿主从插件 manifest 构造 `LlmModule`,插件本身
424
- 只实现宿主约定的轻量 ABI,无需导入或打包 SDK:
425
-
426
- ```ts
427
- import { createLlmModuleClient, type LlmModule } from '@henjicc/ai-sdk/llm/modules'
428
-
429
- const pluginModule: LlmModule = {
430
- descriptor: {
431
- id: 'com.example.chat',
432
- source: { kind: 'plugin', namespace: 'com.example.provider' },
433
- providerId: 'example',
434
- modelId: 'example-chat',
435
- capabilities,
436
- executionModes: ['request-response', 'event-stream'],
437
- },
438
- execute: async (request, context) => pluginAdapter.invoke(request, context),
439
- discover: async (context) => pluginAdapter.discover(context),
440
- dispose: async () => pluginAdapter.dispose(),
35
+ // runtime.credentials.get(scope, credentialId) 须支持 embedding / rerank,
36
+ // 默认 credentialId 是供应商 ID(例如 siliconflow)。其余宿主能力见下文。
37
+ const retrieval = createCapabilityClient({ runtime })
38
+ try {
39
+ const embedding = retrieval.register(createSiliconflowEmbeddingModule())
40
+ const rerank = retrieval.register(createSiliconflowRerankModule())
41
+ const vectors = await embedding.execute({ texts: ['向量检索', '图片编辑'] })
42
+ const ranked = await rerank.execute({ query: '知识库搜索', documents: ['向量检索', '图片编辑'], topN: 1 })
43
+ // vectors.embeddings: { index, vector }[];ranked.results: { index, score, document }[]
44
+ } finally {
45
+ await retrieval.dispose()
441
46
  }
442
-
443
- const llmModules = createLlmModuleClient({ runtime, modules: [pluginModule] })
444
- const result = await llmModules.execute(pluginModule.descriptor.id, { messages }, {
445
- requestId: 'chat-1',
446
- mode: 'event-stream',
447
- onEvent,
448
- })
449
- await llmModules.unregisterSource('com.example.provider')
450
47
  ```
451
48
 
452
- client 统一拥有 Usage/Finish/Done/Error 终态、Abort/timeout、结构化日志、trace、冲突诊断和资源 drain;
453
- module 只发送 Token/ReasoningToken 增量并返回最终结果。`createGroqLlmModule()` 把现有 Groq 共享内核
454
- 包装成同一注册边界,插件占用 `groq/openai/gpt-oss-20b` 时会列出双方 source 并拒绝覆盖。
455
-
456
- ## 已知限制与验证边界
457
-
458
- - SDK 从 `0.2.8` 起以公共 npm 为唯一正式分发渠道,可匿名安装;旧 GitHub Packages 版本仅保留作历史与回滚依据。
459
- - Electron 宿主已经完整构建、桌面冒烟与真实 KIE/LLM 请求验证;`0.1.2` 已在真实 macOS Tauri 2.11.0 WebView + Rust `tauri-plugin-http` 中以 loopback fixture 跑通 create/poll、multi-chunk SSE 与 AbortSignal。`0.2.0` 的 generation-only、单工具、Fal erase tool pack、ASR、翻译、Groq 与 UXP LLM streaming 入口已通过静态依赖、受限 VM 和零网络生命周期门禁;窄 LLM 入口在完全没有 `TextEncoder` / `TextDecoder` 的 VM 中覆盖 UTF-8 跨 chunk、reasoning、text、usage、stop、`[DONE]` 与取消。`0.2.7` 新增的火山文件/实时、硅基流动和 Groq ASR 四个按需入口也已纳入独立 bundle 与受限宿主门禁;百炼、火山、硅基流动、Groq 的 ASR/翻译验证均使用官方来源或明确分类的构造 fixture,没有发起真实或付费网络请求。Photoshop UXP 真机网络稳定性仍由插件集成任务验证,Grayscale/LAB/CMYK 图层字节读取也未真机复验。
460
- - Fal 官方存储上传已在 Electron/Node real profile 中用无隐私合成 PNG 跑通真实端到端:119 字节上传与 Range 回读 SHA-256 一致,未触发模型请求或费用。`0.1.4` 将同一 initiate + signed PUT 协议收口到 `RuntimeContext.transport`,不再依赖 `@fal-ai/client` 或构造 `File`,并补齐成功、失败与取消 fixture;真实证据仍来自迁移前已核对的同一官方协议。CDN URL 公开,生产代码未显式设置 lifecycle,保留期依赖 Fal 账户设置。
461
- - 四个历史 override 模型均已完成真实供应商 create/poll/result URL 验证。KIE Seedream 4.0/4.5 首轮各一次完成;Fal Seedream 4.0 首轮 create 后暴露 `0.1.2` status route 重建 405 并按首败停止,后在新的独立费用授权下,修复后 4.0 completed 才继续 4.5,两者均 completed 且无 create 重试。优先保存供应商完整 `status_url` 的修复已在私有 `0.1.3` 发布,并通过远程干净安装与标准 Vite 五入口回归。
462
- - KIE、APIMart、PPIO 的正式只读 probe 均已得到 HTTP 200 且分类为 connected/verified;KIE/APIMart 余额已在正式 Electron real-profile 设置页显示,对应截图已实际打开目视。首轮场景选择器失败仍保留在 6.6 交接,没有用后台日志冒充 UI 证据。
463
- - 8 provider fixture 中只有 Grsai 来自真实日志;其余按已核对测试断言与供应商文档构建。准确来源逐条记在 `tests/fixtures/README.md`,未冒充真实日志。
464
- - `llm-chat` 已离线验证显式关闭 reasoning 后的文本 token 路径;唯一一次 DeepSeek 真实请求只返回 reasoning,修正版未再发起付费复验。
465
- - 真实供应商的取消响应与错误 Key body 形状仅有注入 `Transport` 的契约测试,没有额外发起付费或故意失败的外网请求。
466
-
467
- ## 相关文档
468
-
469
- - 任务定义:`docs/task/模型SDK抽离/任务/第一阶段-可行性验证与基础设施/1.2-建立SDK包骨架.md`
470
- - 重要决定记录:`docs/task/模型SDK抽离/重要记录.md`
471
- - 本包内的调研资料索引:[docs/README.md](docs/README.md)
472
- - 版本记录:[CHANGELOG.md](CHANGELOG.md)
49
+ 百炼工厂必须传 `baseUrl` 为实际地域/工作空间的 API 根地址,不包含端点路径。其他供应商可以覆盖根地址与 `credentialId`;SDK 不自动切换地域或账号。不同模型的向量不能混用;切换模型通常需要重建向量索引。Rerank 分数仅在本次请求内比较。
50
+
51
+ SDK `0.4.0` 的正式分发渠道为公共 npm,无需配置 registry 或访问令牌:
52
+
53
+ ```bash
54
+ npm install @henjicc/ai-sdk@0.4.0
55
+ ```
56
+
57
+ 然后提供 4 个宿主能力(`Transport` / `CredentialStore` / `MediaReader` / `Logger`),创建客户端:
58
+
59
+ ```ts
60
+ import { readFile } from 'node:fs/promises'
61
+ import { basename } from 'node:path'
62
+ import { createAIClient, type RuntimeContext } from '@henjicc/ai-sdk'
63
+
64
+ const runtime: RuntimeContext = {
65
+ transport: { fetch: (url, init) => fetch(url, init) },
66
+ credentials: {
67
+ get: (scope, providerId) =>
68
+ scope === 'generation' && providerId === 'kie' ? process.env.KIE_API_KEY : undefined,
69
+ },
70
+ media: {
71
+ read: async (ref) => ({
72
+ bytes: new Uint8Array(await readFile(ref)),
73
+ mimeType: 'image/png',
74
+ filename: basename(ref),
75
+ }),
76
+ },
77
+ logger: {
78
+ info: console.log,
79
+ warn: console.warn,
80
+ error: console.error,
81
+ },
82
+ }
83
+
84
+ const client = createAIClient({ runtime })
85
+ try {
86
+ const params = { prompt: 'A blue paper boat', kieZImageAspectRatio: '1:1' }
87
+ const created = await client.generate({ modelId: 'kie-z-image', params })
88
+ const result = created.status === 'pending' && created.taskId
89
+ ? await client.continuePolling({ modelId: 'kie-z-image', taskId: created.taskId, params })
90
+ : created
91
+ console.log(result.url) // SDK 返回 URL;宿主决定是否下载落盘
92
+ } finally {
93
+ client.dispose()
94
+ }
95
+ ```
96
+
97
+ 可直接运行的 Node 版本在 [examples/minimal-node](examples/minimal-node/README.md);它先提供零网络
98
+ `dry-run`,并为付费创建请求加了单次外网闸门。
99
+
100
+ ## 宿主契约
101
+
102
+ | 接口 | 宿主必须保证 |
103
+ |---|---|
104
+ | `Transport.fetch` | 返回标准 `Response`,保留 4xx/5xx 响应,网络失败抛异常,尊重 `AbortSignal` |
105
+ | `CredentialStore.get` | 按 scope/providerId 读取明文密钥;未配置或丢失时返回 `undefined` |
106
+ | `MediaReader.read` | 将宿主的本地/受管引用转成 `Uint8Array + mimeType + filename` |
107
+ | `Logger` | 可选;不得记录 API key/token/cookie/授权头 |
108
+ | `Tracer` | 可选;缺省为 no-op |
109
+
110
+ 生成和 LLM 取消都必须带命名空间:
111
+ `client.cancel({ namespace: 'generation' | 'llm', taskId })`。自定义 provider 使用进程级注册表,
112
+ 同 ID 并发注册会拒绝;持有它的 client 退出时必须 `dispose()`。
113
+
114
+ 供应商官网与 API Key 入口由 SDK 统一提供,宿主不需要再维护一份链接表:
115
+
116
+ ```ts
117
+ import { findProviderMetadata } from '@henjicc/ai-sdk'
118
+
119
+ const provider = findProviderMetadata('kie')
120
+ console.log(provider?.websiteUrl, provider?.apiKeyUrl)
121
+
122
+ // 同一供应商的区域站点通过 endpointProfile 选择。
123
+ const zAi = findProviderMetadata('bigmodel', { endpointProfile: 'global' })
124
+ ```
125
+
126
+ LLM 预设默认使用 SDK 维护的官方地址,并按具体模型选择 Chat Completions 或 Responses。宿主若允许高级用户修改连接信息,应把主动修改写入
127
+ `setup.connectionOverrides`;字段缺省时保持自动路由,不要把 SDK 的默认值复制成覆盖值。
128
+
129
+ `websiteUrl` 是面向用户的实际跳转入口;派欧云、KIE、APIMart 会保留项目配置的邀请码,
130
+ 其余供应商使用正常官网。未知的自定义供应商返回 `null`,SDK 不猜测地址。
131
+
132
+ ## 接入文档与示例
133
+
134
+ - [SDK 消费项目清单](docs/consumers.md)
135
+ - [Electron 主进程适配](docs/接入指南/Electron.md)
136
+ - [Tauri 2 适配](docs/接入指南/Tauri.md)
137
+ - [Photoshop UXP 适配](docs/接入指南/UXP.md)
138
+ - [供应商域名与白名单](docs/接入指南/供应商域名.md)
139
+ - [错误处理](docs/接入指南/错误处理.md)
140
+ - [Node KIE 生成](examples/minimal-node/README.md)
141
+ - [5 模型表单契约](examples/form-renderer/README.md)
142
+ - [LLM 流式对话](examples/llm-chat/README.md)
143
+
144
+ ## 发布形式与可移植性
145
+
146
+ 发布产物是保留模块边界的 ESM + `.d.ts`,没有 CJS `require` 入口。CommonJS 项目请用
147
+ 动态 `import()`。UXP/Tauri 必须在构建期用 Vite/Rollup/webpack/esbuild 打包实际使用的 ESM 依赖。
148
+ SDK 源码不得依赖 `@/`、`node:`、Electron、`import.meta.glob`、`eval`/`new Function`/`node:vm`;
149
+ `npm run check:sdk` 会守住这些边界。Photoshop/受限宿主只做生成时应从
150
+ `@henjicc/ai-sdk/generation` 导入 `createGenerationClient`;该入口不静态带入 LLM、Vercel AI SDK、
151
+ Node 内置模块或 Fal 官方客户端,发布门禁会把它打成 IIFE 并在无网络生命周期中核对 109 个模型。
152
+
153
+ ## 按需装配生成模型
154
+
155
+ `@henjicc/ai-sdk/generation` 是兼容入口,默认始终装入 109 个模型。真正需要缩小 Photoshop/Tauri
156
+ 包体时,从不含任何内置 catalog/provider 的 `generation/core` 创建模块化客户端,并只导入完整 pack:
157
+
158
+ ```ts
159
+ import { createModularGenerationClient } from '@henjicc/ai-sdk/generation/core'
160
+ import { pack as kieZImage } from '@henjicc/ai-sdk/models/kie/z-image'
161
+
162
+ const client = createModularGenerationClient({ runtime, packs: [kieZImage] })
163
+ console.log(client.catalog.list().map((model) => model.meta.id)) // ['kie-z-image']
164
+ ```
165
+
166
+ 完整单模型 pack 同时携带该模型的唯一真实 schema、provider adapter 与 provider-scoped 媒体预处理/
167
+ 上传策略;宿主不需要知道内部上传模块。`@henjicc/ai-sdk/provider-packs/kie` 可一次装入 KIE 的全部
168
+ 28 个模型;`provider-adapters/kie` 只装入 KIE 执行与上传策略、不装任何模型。所有 109 个单模型路径和
169
+ 8 个供应商路径由 catalog 生成器自动产出并由 bundle 门禁穷举,新增模型不会靠手工维护 exports。
170
+
171
+ 每个 `models/<provider>/<model>` 子路径也导出名为 `model` 的低层定义,供目录分析或高级自定义组合;
172
+ 直接传裸 `model` 而不传同文件的 `pack` 不保证媒体上传或供应商执行完整,普通宿主应使用 `pack`。
173
+ 包根 `createAIClient` 仍默认 109 模型;若确实需要根 client 的 chat 与按需生成共存,可显式传:
174
+
175
+ ```ts
176
+ const client = createAIClient({
177
+ runtime,
178
+ generation: { mode: 'modular', packs: [kieZImage] },
179
+ })
180
+ ```
181
+
182
+ 普通 LLM 宿主可直接导入 `@henjicc/ai-sdk/llm`。Photoshop UXP 等禁止字符串代码生成的受限宿主
183
+ 必须改用 `@henjicc/ai-sdk/llm/streaming`:它只提供原生 OpenAI-compatible SSE 的
184
+ `runLlmChatStream`、`cancelLlmChatTask` 与必要类型/错误,不会进入 modelStep、Zod、Vercel AI SDK
185
+ 或 generation 静态图。两条入口复用同一份原生流式实现,不存在功能分叉。
186
+
187
+ ```ts
188
+ import {
189
+ cancelLlmChatTask,
190
+ runLlmChatStream,
191
+ type LlmChatRequestDto,
192
+ type RuntimeContext,
193
+ } from '@henjicc/ai-sdk/llm/streaming'
194
+
195
+ const request: LlmChatRequestDto = {
196
+ requestId: 'chat-1', providerId: 'openai', modelId: 'gpt-5-mini',
197
+ messages: [{ role: 'user', content: '你好' }],
198
+ }
199
+ const result = await runLlmChatStream(request, 'chat-1', onStreamEvent, runtime as RuntimeContext)
200
+ console.log(result.output, result.reasoningOutput, result.usage, result.finishReason)
201
+ cancelLlmChatTask('chat-1')
202
+ ```
203
+
204
+ ### 可选模型分发包与统一能力筛选
205
+
206
+ 当前 12 个 FAL 图片工具不会混入默认 109 模型。宿主可选择单个完整工具模型 pack,也可按用户任务装入三个聚合包:
207
+
208
+ - `tool-packs/fal-image-edit-tools`:3 个消除工具。
209
+ - `tool-packs/fal-image-utility-tools`:6 个重打光、暗光增强、扩图、商品摄影、照片修复和背景移除工具。
210
+ - `tool-packs/fal-multi-angle-tools`:3 个连续镜头控制或离散方位工具。
211
+
212
+ ```ts
213
+ import { createModularGenerationClient } from '@henjicc/ai-sdk/generation/core'
214
+ import { createModelCapabilityDiscovery } from '@henjicc/ai-sdk/discovery'
215
+ import { pack as falImageEditTools } from '@henjicc/ai-sdk/tool-packs/fal-image-edit-tools'
216
+ import { pack as falImageUtilityTools } from '@henjicc/ai-sdk/tool-packs/fal-image-utility-tools'
217
+
218
+ const eraseDiscovery = createModelCapabilityDiscovery({ generationPacks: [falImageEditTools] })
219
+ const utilityDiscovery = createModelCapabilityDiscovery({ generationPacks: [falImageUtilityTools] })
220
+ const erasers = eraseDiscovery.search({
221
+ providerIds: 'fal',
222
+ outputModalities: 'image',
223
+ operations: 'image-edit',
224
+ features: 'erase',
225
+ })
226
+ const utilities = utilityDiscovery.search({ providerIds: 'fal', outputModalities: 'image' })
227
+ const client = createModularGenerationClient({
228
+ runtime,
229
+ packs: [falImageEditTools, falImageUtilityTools],
230
+ })
231
+ console.log(erasers.map((item) => item.id))
232
+ console.log(utilities.map((item) => item.id))
233
+ ```
234
+
235
+ 单模型入口按集合分为:
236
+
237
+ - 消除:`tool-models/fal/flux-pro-erase`、`tool-models/fal/bria-eraser`、`tool-models/fal/finegrain-eraser`。
238
+ - 图片实用工具:`tool-models/fal/relighting`、`tool-models/fal/control-light`、`tool-models/fal/outpaint`、`tool-models/fal/product-photography`、`tool-models/fal/photo-restoration`、`tool-models/fal/pixelcut-background-removal`。
239
+ - 多角度:`tool-models/fal/qwen-image-edit-2511-multiple-angles`、`tool-models/fal/perspective-change`、`tool-models/fal/flux-2-multiple-angles`。
240
+
241
+ 每个单模型入口只导出 `model`、`provider` 与完整 `pack`。三个聚合包只携带各自 3 / 6 / 3 个工具模型、Fal adapter 和 Fal CDN 上传,不携带其余 109 模型或 LLM。能力筛选与分发是两层:`search()` 只过滤已经导入的候选,不会让已经进入 bundle 的代码自动消失;缩小包体仍必须显式选择单模型/provider/collection pack。
242
+
243
+ Henji-AI 在执行层按需装入工具 pack,但普通模型选择器、`@henjicc/ai-sdk/generation` 与默认能力发现仍只展示 109 个主目录模型。
244
+
245
+ ## 两类模型的公共边界
246
+
247
+ 生成模型与 LLM 共用以下基础设施:
248
+
249
+ | 能力 | 统一实现 | 约束 |
250
+ |---|---|---|
251
+ | 凭据 | `RuntimeContext.credentials` / `CredentialStore` | 用 `generation`、`llm` scope 隔离宿主密钥空间 |
252
+ | 网络 | `Transport` + `fetchProvider` | 只自动重试可证明尚未建连的错误,避免重放可能计费的请求 |
253
+ | 错误 | `runtime/errors.ts` + `runtime/error-classify.ts` | 生成错误码字符串保持稳定;LLM 保留鉴权、余额、限流、上下文、内容过滤等细分类 |
254
+ | 取消 | `runtime/task-registry.ts` | 单一 registry,以 `generation` / `llm` 命名空间隔离同名任务 |
255
+ | 重试判断 | `shouldRetry(error, mode)` | `safe-preconnect`、`request`、`poll-query` 共用分类,但策略生命周期不同 |
256
+ | 追踪 | `RuntimeContext.tracer` | SDK 只报告通用 span;助手专属 trace 由痕迹AI 宿主持有 |
257
+
258
+ 以下协议刻意保持分离:
259
+
260
+ - 生成模型是“创建任务 → 可选轮询 → 提取媒体结果”,允许长时间轮询,并容忍状态查询的连续瞬态失败。
261
+ - LLM 是 SSE 流式或 Vercel 模型步,持续输出 token / tool call,单次请求失败按模型步策略处理。
262
+
263
+ 二者的终止条件、进度含义、结果形状和可安全重试边界都不同。把它们压成一个通用 `execute()`
264
+ 只会隐藏协议差异,无法形成可靠抽象;第五阶段统一客户端只应在入口层分组编排,不应合并生命周期。
265
+
266
+ ## 目录与参数表单契约
267
+
268
+ 消费方从 client 私有目录读取模型,不需要自行复刻 canonical/alias 索引规则:
269
+
270
+ ```ts
271
+ const images = client.catalog.listByType('image')
272
+ const falModels = client.catalog.listByProvider('fal')
273
+ const editors = client.catalog.listByTag('supports-image-editing')
274
+ const params = client.catalog.getParams('fal-ai-gpt-image-2')
275
+ const defaults = client.catalog.getDefaultValues('fal-ai-gpt-image-2')
276
+ const price = client.catalog.estimatePrice('fal-ai-gpt-image-2', defaults)
277
+ ```
278
+
279
+ 价格依赖本地图片像素或视频时长时,模型会在 `pricing.mediaContext` 声明所需指标。消费方从
280
+ `@henjicc/ai-sdk/pricing` 调用 `resolvePricingMediaContext()`,只需注入自身的图片/视频元数据读取器;
281
+ SDK 统一处理媒体来源优先级、首个/求和聚合、固定倍率和参数倍率换算,再把结果交给原模型 calculator。
282
+ 指标无法读取时返回 `complete: false`,消费方应隐藏总价,而不是显示最低档兜底价。
283
+
284
+ `getParams()` 返回纯运行时 `RuntimeParamDef[]`。参数名、选项 label、图标、分组布局、linkages 和
285
+ 痕迹AI 特有 composite 面板配置属于应用 presentation,不在 SDK 目录里;通用消费方可以用参数 ID
286
+ 作最小标签,也可以在宿主维护自己的本地化展示层。`composite` 只保证值类型/default/API 契约,宿主
287
+ 必须按参数 ID 注入自定义组件,不能从 SDK 还原痕迹AI 专属面板。
288
+
289
+ ### 参数类型 → 控件
290
+
291
+ 以下 13 种是 `RuntimeParamDef` 的完整公开联合;括号内是当前真实 109 catalog 的出现数量。未出现不代表
292
+ 类型无效,而是当前目录没有对应模型。
293
+
294
+ | type | 109 catalog | 消费方控件 | 关键运行时字段 |
295
+ |---|---:|---|---|
296
+ | `dropdown` | 317 | 下拉选择 | `options[].value`、`default`、`required?` |
297
+ | `switch` | 93 | 布尔开关 | `default` |
298
+ | `number` | 85 | 数值输入/步进器 | `min?`、`max?`、`step?`、`default` |
299
+ | `text` | 7 | 单行文本 | `maxLength?`、`default` |
300
+ | `image-upload` | 6 | 图片上传 | `maxCount?`、`accept?`、`maxSize?`、`format?` |
301
+ | `composite` | 4 | 宿主自定义组件钩子 | `valueType?`、`default`;panel/config 不在 SDK |
302
+ | `textarea` | 3 | 多行文本 | `maxLength?`、`default` |
303
+ | `file-upload` | 1 | 文件上传 | `maxCount?`、`accept?`、`maxSize?` |
304
+ | `radio` | 0 | 单选组 | `options[].value`、`default` |
305
+ | `panel` | 0 | 递归分组容器 | `children[]`;布局样式由宿主决定 |
306
+ | `video-upload` | 0 | 视频上传 | `maxCount?`、`accept?`、`maxSize?`、时长范围 |
307
+ | `resolution` | 0 | 分辨率选择 | `presets[].value`、`allowCustom?` |
308
+ | `aspect-ratio` | 0 | 比例选择 | `options[].value` |
309
+
310
+ 所有参数共有 `id`、`type`、`order`、`default`,并可带 `required`、`valueType`、API 映射、
311
+ `transferKey`、`visible`、`disabled`。实际 109 catalog 的字段集合与数量由
312
+ `packages/ai-sdk/tests/catalog-consumer-contract.test.ts` 穷举锁定,不以旧 ParamDef 文件或示例推断。
313
+
314
+ ### 条件与媒体输入
315
+
316
+ - `evaluateRuntimeCondition()` 是条件显隐/inputLimits/requirements 的公共判断入口。函数条件直接调用;
317
+ 字符串条件使用受限 parser,支持真实 catalog 用到的标识符、`.length`、字面量、`typeof`、比较、
318
+ `&&`/`||`/`!`、括号和 `Array.isArray()`。它不使用 `eval`/`new Function`;未知 token、属性或调用
319
+ 会抛出明确错误,不会静默判为 false。
320
+ - `resolveRuntimeInputLimits()` 解析数据型/函数型输入限制并应用条件规则。
321
+ - `getRuntimeMediaInputContract()` 把 `inputLimits` 的通用图片/视频/音频入口、显式
322
+ `image-upload`/`video-upload`/`file-upload` 参数,以及 `runtimeConstraints.mediaFields` 的特殊请求字段
323
+ 分层返回。消费方必须据此渲染上传组件;不存在 URL 文本框 fallback。
324
+
325
+ 最小无框架验证器位于 `examples/form-renderer/`。它用 5 个真实模型覆盖普通选择、数值范围、条件显隐、
326
+ 通用与特殊媒体上传、composite 自定义钩子,可作为无 UI 框架的最小接入参考。
327
+
328
+ 本包不发布 JSON catalog 快照。Tauri/UXP 消费端都能在构建期使用 ESM,而真实目录包含 builder、
329
+ 计价、显隐和 inputLimits 函数,JSON 无法无损表达;并行发布不完整快照会形成第二份真相。未来只有出现
330
+ 明确的非 JavaScript/TypeScript 消费方时,才应另行设计带版本的可序列化投影契约。
331
+
332
+ ## 扩展模型类型与供应商
333
+
334
+ `ModelType` 与 `ProviderId` 都采用“内置字面量 + 开放字符串”的形式:编辑器仍会提示
335
+ `image` / `video` / `audio` 和 8 个内置供应商,同时消费方可以直接声明自己的类型与 provider id。
336
+ 下面的 TypeScript 示例不新增真实模型或供应商,只演示完整的注册、索引与请求构建机制:
337
+
338
+ ```ts
339
+ import {
340
+ buildRequest,
341
+ createModelIndex,
342
+ defineModel,
343
+ registerProvider,
344
+ unregisterProvider,
345
+ } from '@henjicc/ai-sdk'
346
+
347
+ const providerId = 'acme-transcript'
348
+
349
+ async function main(): Promise<void> {
350
+ registerProvider(providerId, {
351
+ execute: async (input) => ({
352
+ status: 'completed',
353
+ url: 'memory://result',
354
+ metadata: { requestBody: input.body },
355
+ }),
356
+ continuePolling: async () => ({
357
+ status: 'failed',
358
+ url: '',
359
+ metadata: { reason: 'not-supported' },
360
+ }),
361
+ })
362
+
363
+ try {
364
+ const model = defineModel({
365
+ meta: {
366
+ id: 'acme-transcript-v1',
367
+ canonicalModelId: 'acme-transcript-v1',
368
+ provider: providerId,
369
+ type: 'transcript',
370
+ },
371
+ params: [{ id: 'text', type: 'text', order: 1, default: '' }],
372
+ endpoints: '/v1/transcript',
373
+ request: { builder: (params) => ({ input: params.text }) },
374
+ pricing: { currency: '$', fixed: 0 },
375
+ })
376
+
377
+ const index = createModelIndex([model])
378
+ const request = await buildRequest(
379
+ { text: 'hello' },
380
+ index.get('acme-transcript-v1'),
381
+ )
382
+ console.log(request)
383
+ } finally {
384
+ unregisterProvider(providerId)
385
+ }
386
+ }
387
+
388
+ void main()
389
+ ```
390
+
391
+ 注册表语义是确定的:`registerProvider` 遇到同名 id 会抛
392
+ `provider_already_registered`,不会覆盖既有适配器;`unregisterProvider` 删除成功返回 `true`,
393
+ 未登记返回 `false`;`listProviders` 返回快照,修改返回数组不会改动注册表。插件与测试应使用唯一 id,
394
+ 并在 `finally` / `afterEach` 中注销。SDK 在首次访问 provider 注册表时惰性初始化 APIMart、Bailian、
395
+ Volcengine、PPIO、KIE、ModelScope、Fal、Grsai 八个内置供应商;调用方无需手工初始化。惰性初始化
396
+ 避免依赖仅靠模块加载保留的副作用,使 `sideEffects: false` 与 tree-shaking 语义一致。
397
+
398
+ ### 跨模型类型的统一能力画像
399
+
400
+ `@henjicc/ai-sdk/discovery` 只负责发现和筛选,不改变 generation、LLM 或扩展模块各自的执行协议。
401
+ 画像从已导入候选的真实 schema 派生,统一提供 provider、输出模态、operation、输入/输出内容类型、
402
+ features 与原始 tags。顶层查询维度默认 AND,也可设 `mode: 'any'`;单一维度可用
403
+ `{ anyOf: [...] }` / `{ allOf: [...] }` 表达 OR/AND。
404
+
405
+ 标准 operation 覆盖图片生成/编辑、视频文生/图生/参考/编辑、音频生成、chat、语音识别和 OCR,
406
+ 同时保留开放字符串。筛选结果用 `sourceKind` 区分 `generation-model`、`llm-model`、`extension`,
407
+ 调用方随后交给对应执行 handle;SDK 不提供一个掩盖协议差异的通用 `generate()`。
408
+
409
+ 能力画像是运行时选择层,不是打包器。`createModelCapabilityDiscovery({ generationPacks: [...] })` 只会看
410
+ 传入的 pack;它既不会隐式导入默认 109,也不会从 bundle 删除已导入代码。真正的按需分发仍以 import
411
+ 单模型/provider/collection pack 为边界。
412
+
413
+ ### ASR/OCR 等开放能力
414
+
415
+ ASR、OCR 不属于图片/视频/音频生成的 `ModelType`,SDK 不再要求把它们伪装成媒体生成模型。
416
+ `@henjicc/ai-sdk/capabilities` 提供独立的开放模块协议:
417
+
418
+ ```ts
419
+ import { createCapabilityClient, type CapabilityModule } from '@henjicc/ai-sdk/capabilities'
420
+
421
+ const speechRecognition: CapabilityModule<{ audio: Uint8Array }, { text: string }> = {
422
+ descriptor: {
423
+ id: 'my.speech-recognition',
424
+ kind: 'speech-recognition',
425
+ source: { kind: 'external', namespace: '@example/my-asr' },
426
+ contract: {
427
+ input: [{ kind: 'audio', required: true }],
428
+ output: [{ kind: 'text', required: true }],
429
+ },
430
+ },
431
+ execute: async ({ audio }, { signal }) => runLocalAsr(audio, signal),
432
+ }
433
+
434
+ const capabilities = createCapabilityClient({ runtime })
435
+ const asr = capabilities.register(speechRecognition)
436
+ const result = await asr.execute({ audio: bytes }, { requestId: 'asr-1' })
437
+ await capabilities.unregister(speechRecognition.descriptor.id)
438
+ await capabilities.dispose()
439
+ ```
440
+
441
+ `CapabilityKind` 与输入/输出 `CapabilityContentKind` 都是开放字符串;`source.namespace` 是包或插件的
442
+ 稳定所有者 ID,用于冲突诊断和批量卸载。模块执行上下文统一带
443
+ `RuntimeContext`、`AbortSignal`、requestId、Logger 与 Tracer。client 提供注册、发现、类型化执行、取消、
444
+ 注销、`unregisterSource(namespace)` 和 dispose,并统一错误边界。跨类型筛选使用上面的
445
+ `ModelCapabilityProfile`;执行仍走各自稳定的轮询、流式或扩展 handle,不复制协议。
446
+
447
+ 以下可选供应商入口只有显式 import 才进入消费方 bundle:
448
+
449
+ - `capabilities/speech-recognition/bailian`:5 个百炼短音频/文件 ASR;
450
+ - `capabilities/speech-recognition/bailian/realtime`:4 个百炼 Fun-ASR/Qwen 实时 ASR;
451
+ - `capabilities/speech-recognition/volcengine`:SeedASR 2.0 文件 submit/query;官方标准版只接受公网 URL;
452
+ - `capabilities/speech-recognition/volcengine/realtime`:SeedASR 2.0 gzip 二进制 WebSocket 实时识别;
453
+ - `capabilities/speech-recognition/siliconflow`:SenseVoiceSmall 与 TeleSpeechASR multipart 文件转写;
454
+ - `capabilities/speech-recognition/groq`:Whisper Large v3 Turbo/v3 文件转写与可选词/句时间戳;
455
+ - `capabilities/translation/bailian`:Qwen-MT Flash/Plus/Lite;
456
+ - `llm/groq`:Groq GPT-OSS 20B 默认配置、流式聊天和模型发现。
457
+ - `llm/bigmodel`:智谱同一 provider family 下的中国大陆/Global 端点 profile、独立凭据槽与 GLM-5.3-Flash 能力。
458
+ - `llm/modules`:外部包、插件与内置 LLM 共用的注册、执行、发现、取消和 namespace 卸载边界。
459
+
460
+ ASR module ID 固定为 `<providerId>.speech-recognition.<modelId>`,翻译固定为
461
+ `bailian.translation.<modelId>`;供应商 ID 使用 `bailian` / `volcengine` / `siliconflow` / `groq`,
462
+ 没有 `funasr` 兼容供应商别名。火山文件标准版不会读取本地 bytes/media-ref;宿主必须先通过自己受控的
463
+ 对象存储发布成供应商可访问 URL。SDK 不提供公共 URL 文本框或冒充上传成功的回退路径。
464
+
465
+ 外部 LLM 不属于 ASR/translation `CapabilityModule`。宿主从插件 manifest 构造 `LlmModule`,插件本身
466
+ 只实现宿主约定的轻量 ABI,无需导入或打包 SDK:
467
+
468
+ ```ts
469
+ import { createLlmModuleClient, type LlmModule } from '@henjicc/ai-sdk/llm/modules'
470
+
471
+ const pluginModule: LlmModule = {
472
+ descriptor: {
473
+ id: 'com.example.chat',
474
+ source: { kind: 'plugin', namespace: 'com.example.provider' },
475
+ providerId: 'example',
476
+ modelId: 'example-chat',
477
+ capabilities,
478
+ executionModes: ['request-response', 'event-stream'],
479
+ },
480
+ execute: async (request, context) => pluginAdapter.invoke(request, context),
481
+ discover: async (context) => pluginAdapter.discover(context),
482
+ dispose: async () => pluginAdapter.dispose(),
483
+ }
484
+
485
+ const llmModules = createLlmModuleClient({ runtime, modules: [pluginModule] })
486
+ const result = await llmModules.execute(pluginModule.descriptor.id, { messages }, {
487
+ requestId: 'chat-1',
488
+ mode: 'event-stream',
489
+ onEvent,
490
+ })
491
+ await llmModules.unregisterSource('com.example.provider')
492
+ ```
493
+
494
+ client 统一拥有 Usage/Finish/Done/Error 终态、Abort/timeout、结构化日志、trace、冲突诊断和资源 drain;
495
+ module 只发送 Token/ReasoningToken 增量并返回最终结果。`createGroqLlmModule()` 把现有 Groq 共享内核
496
+ 包装成同一注册边界,插件占用 `groq/openai/gpt-oss-20b` 时会列出双方 source 并拒绝覆盖。
497
+
498
+ ## 已知限制与验证边界
499
+
500
+ - SDK 从 `0.2.8` 起以公共 npm 为唯一正式分发渠道,可匿名安装;旧 GitHub Packages 版本仅保留作历史与回滚依据。
501
+ - Electron 宿主已经完整构建、桌面冒烟与真实 KIE/LLM 请求验证;`0.1.2` 已在真实 macOS Tauri 2.11.0 WebView + Rust `tauri-plugin-http` 中以 loopback fixture 跑通 create/poll、multi-chunk SSE 与 AbortSignal。`0.2.0` 的 generation-only、单工具、Fal erase tool pack、ASR、翻译、Groq 与 UXP LLM streaming 入口已通过静态依赖、受限 VM 和零网络生命周期门禁;窄 LLM 入口在完全没有 `TextEncoder` / `TextDecoder` 的 VM 中覆盖 UTF-8 跨 chunk、reasoning、text、usage、stop、`[DONE]` 与取消。`0.2.7` 新增的火山文件/实时、硅基流动和 Groq ASR 四个按需入口也已纳入独立 bundle 与受限宿主门禁;百炼、火山、硅基流动、Groq 的 ASR/翻译验证均使用官方来源或明确分类的构造 fixture,没有发起真实或付费网络请求。Photoshop UXP 真机网络稳定性仍由插件集成任务验证,Grayscale/LAB/CMYK 图层字节读取也未真机复验。
502
+ - Fal 官方存储上传已在 Electron/Node real profile 中用无隐私合成 PNG 跑通真实端到端:119 字节上传与 Range 回读 SHA-256 一致,未触发模型请求或费用。`0.1.4` 将同一 initiate + signed PUT 协议收口到 `RuntimeContext.transport`,不再依赖 `@fal-ai/client` 或构造 `File`,并补齐成功、失败与取消 fixture;真实证据仍来自迁移前已核对的同一官方协议。CDN URL 公开,生产代码未显式设置 lifecycle,保留期依赖 Fal 账户设置。
503
+ - 四个历史 override 模型均已完成真实供应商 create/poll/result URL 验证。KIE Seedream 4.0/4.5 首轮各一次完成;Fal Seedream 4.0 首轮 create 后暴露 `0.1.2` status route 重建 405 并按首败停止,后在新的独立费用授权下,修复后 4.0 completed 才继续 4.5,两者均 completed 且无 create 重试。优先保存供应商完整 `status_url` 的修复已在私有 `0.1.3` 发布,并通过远程干净安装与标准 Vite 五入口回归。
504
+ - KIE、APIMart、PPIO 的正式只读 probe 均已得到 HTTP 200 且分类为 connected/verified;KIE/APIMart 余额已在正式 Electron real-profile 设置页显示,对应截图已实际打开目视。首轮场景选择器失败仍保留在 6.6 交接,没有用后台日志冒充 UI 证据。
505
+ - 8 家 provider fixture 中只有 Grsai 来自真实日志;其余按已核对测试断言与供应商文档构建。准确来源逐条记在 `tests/fixtures/README.md`,未冒充真实日志。
506
+ - `llm-chat` 已离线验证显式关闭 reasoning 后的文本 token 路径;唯一一次 DeepSeek 真实请求只返回 reasoning,修正版未再发起付费复验。
507
+ - 真实供应商的取消响应与错误 Key body 形状仅有注入 `Transport` 的契约测试,没有额外发起付费或故意失败的外网请求。
508
+
509
+ ## 相关文档
510
+
511
+ - 任务定义:`docs/task/模型SDK抽离/任务/第一阶段-可行性验证与基础设施/1.2-建立SDK包骨架.md`
512
+ - 重要决定记录:`docs/task/模型SDK抽离/重要记录.md`
513
+ - 本包内的调研资料索引:[docs/README.md](docs/README.md)
514
+ - 版本记录:[CHANGELOG.md](CHANGELOG.md)