@midscene/core 1.16.5 → 1.17.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 (252) hide show
  1. package/dist/es/agent/agent.mjs +11 -11
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/insight.mjs.map +1 -1
  4. package/dist/es/agent/tasks.mjs +72 -39
  5. package/dist/es/agent/tasks.mjs.map +1 -1
  6. package/dist/es/agent/utils.mjs +1 -1
  7. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs +27 -22
  8. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs.map +1 -1
  9. package/dist/es/ai-model/index.mjs +2 -2
  10. package/dist/es/ai-model/model-adapter/resolve.mjs +4 -2
  11. package/dist/es/ai-model/model-adapter/resolve.mjs.map +1 -1
  12. package/dist/es/ai-model/models/jev/adapter.mjs +6 -110
  13. package/dist/es/ai-model/models/jev/adapter.mjs.map +1 -1
  14. package/dist/es/ai-model/models/jev/boolean.mjs +48 -0
  15. package/dist/es/ai-model/models/jev/boolean.mjs.map +1 -0
  16. package/dist/es/ai-model/models/jev/image.mjs +39 -36
  17. package/dist/es/ai-model/models/jev/image.mjs.map +1 -1
  18. package/dist/es/ai-model/models/jev/locate.mjs +48 -0
  19. package/dist/es/ai-model/models/jev/locate.mjs.map +1 -0
  20. package/dist/es/ai-model/models/jev/planning-action.mjs +35 -0
  21. package/dist/es/ai-model/models/jev/planning-action.mjs.map +1 -0
  22. package/dist/es/ai-model/models/jev/planning-context.mjs +38 -0
  23. package/dist/es/ai-model/models/jev/planning-context.mjs.map +1 -0
  24. package/dist/es/ai-model/models/jev/planning-decision.mjs +68 -0
  25. package/dist/es/ai-model/models/jev/planning-decision.mjs.map +1 -0
  26. package/dist/es/ai-model/models/jev/planning.mjs +19 -131
  27. package/dist/es/ai-model/models/jev/planning.mjs.map +1 -1
  28. package/dist/es/ai-model/models/model-fallback.mjs +28 -0
  29. package/dist/es/ai-model/models/model-fallback.mjs.map +1 -0
  30. package/dist/es/ai-model/service-caller/call-ai.mjs +27 -24
  31. package/dist/es/ai-model/service-caller/call-ai.mjs.map +1 -1
  32. package/dist/es/ai-model/service-caller/codex/call-codex.mjs.map +1 -1
  33. package/dist/es/ai-model/service-caller/index.mjs +2 -2
  34. package/dist/es/ai-model/service-caller/model-call.mjs +3 -3
  35. package/dist/es/ai-model/service-caller/model-call.mjs.map +1 -1
  36. package/dist/es/ai-model/service-caller/openai/call-openai.mjs +1 -1
  37. package/dist/es/ai-model/service-caller/openai/call-openai.mjs.map +1 -1
  38. package/dist/es/ai-model/service-caller/openai/chat-completion/chat-completion.mjs.map +1 -1
  39. package/dist/es/ai-model/service-caller/openai/openai-client.mjs.map +1 -1
  40. package/dist/es/ai-model/service-caller/openai/responses/responses.mjs.map +1 -1
  41. package/dist/es/ai-model/service-caller/system-one/call-system-one.mjs +69 -0
  42. package/dist/es/ai-model/service-caller/system-one/call-system-one.mjs.map +1 -0
  43. package/dist/es/ai-model/service-caller/system-one/index.mjs +3 -0
  44. package/dist/es/ai-model/service-caller/system-one/prepare-system-one.mjs +44 -0
  45. package/dist/es/ai-model/service-caller/system-one/prepare-system-one.mjs.map +1 -0
  46. package/dist/es/ai-model/service-caller/system-one/schema.mjs +32 -0
  47. package/dist/es/ai-model/service-caller/system-one/schema.mjs.map +1 -0
  48. package/dist/es/ai-model/service-caller/system-one/utils.mjs +34 -0
  49. package/dist/es/ai-model/service-caller/system-one/utils.mjs.map +1 -0
  50. package/dist/es/ai-model/service-caller/utils.mjs +2 -2
  51. package/dist/es/ai-model/service-caller/utils.mjs.map +1 -1
  52. package/dist/es/ai-model/shared/model-locate-result/factory.mjs +7 -3
  53. package/dist/es/ai-model/shared/model-locate-result/factory.mjs.map +1 -1
  54. package/dist/es/ai-model/shared/model-locate-result/pixel-mapper.mjs +10 -4
  55. package/dist/es/ai-model/shared/model-locate-result/pixel-mapper.mjs.map +1 -1
  56. package/dist/es/ai-model/shared/model-locate-result/types.mjs.map +1 -1
  57. package/dist/es/ai-model/shared/model-locate-result/validation.mjs +4 -0
  58. package/dist/es/ai-model/shared/model-locate-result/validation.mjs.map +1 -1
  59. package/dist/es/ai-model/workflows/grounding/locate.mjs +2 -2
  60. package/dist/es/ai-model/workflows/grounding/locate.mjs.map +1 -1
  61. package/dist/es/ai-model/workflows/grounding/section-locate.mjs +2 -2
  62. package/dist/es/ai-model/workflows/grounding/section-locate.mjs.map +1 -1
  63. package/dist/es/ai-model/workflows/insight/boolean.mjs +1 -1
  64. package/dist/es/ai-model/workflows/insight/boolean.mjs.map +1 -1
  65. package/dist/es/ai-model/workflows/insight/extraction.mjs +3 -3
  66. package/dist/es/ai-model/workflows/insight/extraction.mjs.map +1 -1
  67. package/dist/es/ai-model/workflows/planning/standard-planning.mjs +4 -3
  68. package/dist/es/ai-model/workflows/planning/standard-planning.mjs.map +1 -1
  69. package/dist/es/ai-model/workflows/recorder-generation/playwright.mjs +2 -2
  70. package/dist/es/ai-model/workflows/recorder-generation/playwright.mjs.map +1 -1
  71. package/dist/es/ai-model/workflows/recorder-generation/yaml.mjs +2 -2
  72. package/dist/es/ai-model/workflows/recorder-generation/yaml.mjs.map +1 -1
  73. package/dist/es/device/index.mjs +7 -0
  74. package/dist/es/device/index.mjs.map +1 -1
  75. package/dist/es/report-html-template.mjs +1 -1
  76. package/dist/es/service/index.mjs +2 -1
  77. package/dist/es/service/index.mjs.map +1 -1
  78. package/dist/es/types.mjs.map +1 -1
  79. package/dist/es/utils.mjs +1 -1
  80. package/dist/lib/agent/agent.js +11 -11
  81. package/dist/lib/agent/agent.js.map +1 -1
  82. package/dist/lib/agent/insight.js.map +1 -1
  83. package/dist/lib/agent/tasks.js +72 -39
  84. package/dist/lib/agent/tasks.js.map +1 -1
  85. package/dist/lib/agent/utils.js +1 -1
  86. package/dist/lib/ai-model/connectivity/run-connectivity-test.js +27 -22
  87. package/dist/lib/ai-model/connectivity/run-connectivity-test.js.map +1 -1
  88. package/dist/lib/ai-model/index.js +6 -3
  89. package/dist/lib/ai-model/model-adapter/resolve.js +4 -2
  90. package/dist/lib/ai-model/model-adapter/resolve.js.map +1 -1
  91. package/dist/lib/ai-model/models/jev/adapter.js +6 -110
  92. package/dist/lib/ai-model/models/jev/adapter.js.map +1 -1
  93. package/dist/lib/ai-model/models/jev/boolean.js +82 -0
  94. package/dist/lib/ai-model/models/jev/boolean.js.map +1 -0
  95. package/dist/lib/ai-model/models/jev/image.js +41 -35
  96. package/dist/lib/ai-model/models/jev/image.js.map +1 -1
  97. package/dist/lib/ai-model/models/jev/locate.js +82 -0
  98. package/dist/lib/ai-model/models/jev/locate.js.map +1 -0
  99. package/dist/lib/ai-model/models/jev/planning-action.js +69 -0
  100. package/dist/lib/ai-model/models/jev/planning-action.js.map +1 -0
  101. package/dist/lib/ai-model/models/jev/planning-context.js +72 -0
  102. package/dist/lib/ai-model/models/jev/planning-context.js.map +1 -0
  103. package/dist/lib/ai-model/models/jev/planning-decision.js +102 -0
  104. package/dist/lib/ai-model/models/jev/planning-decision.js.map +1 -0
  105. package/dist/lib/ai-model/models/jev/planning.js +19 -131
  106. package/dist/lib/ai-model/models/jev/planning.js.map +1 -1
  107. package/dist/lib/ai-model/models/{task-routing.js → model-fallback.js} +11 -11
  108. package/dist/lib/ai-model/models/model-fallback.js.map +1 -0
  109. package/dist/lib/ai-model/service-caller/call-ai.js +32 -26
  110. package/dist/lib/ai-model/service-caller/call-ai.js.map +1 -1
  111. package/dist/lib/ai-model/service-caller/codex/call-codex.js.map +1 -1
  112. package/dist/lib/ai-model/service-caller/index.js +6 -3
  113. package/dist/lib/ai-model/service-caller/model-call.js +2 -2
  114. package/dist/lib/ai-model/service-caller/model-call.js.map +1 -1
  115. package/dist/lib/ai-model/service-caller/openai/call-openai.js +1 -1
  116. package/dist/lib/ai-model/service-caller/openai/call-openai.js.map +1 -1
  117. package/dist/lib/ai-model/service-caller/openai/chat-completion/chat-completion.js.map +1 -1
  118. package/dist/lib/ai-model/service-caller/openai/openai-client.js.map +1 -1
  119. package/dist/lib/ai-model/service-caller/openai/responses/responses.js.map +1 -1
  120. package/dist/lib/ai-model/service-caller/system-one/call-system-one.js +103 -0
  121. package/dist/lib/ai-model/service-caller/system-one/call-system-one.js.map +1 -0
  122. package/dist/lib/ai-model/service-caller/system-one/index.js +42 -0
  123. package/dist/lib/ai-model/service-caller/system-one/index.js.map +1 -0
  124. package/dist/lib/ai-model/service-caller/system-one/prepare-system-one.js +78 -0
  125. package/dist/lib/ai-model/service-caller/system-one/prepare-system-one.js.map +1 -0
  126. package/dist/lib/ai-model/service-caller/system-one/schema.js +69 -0
  127. package/dist/lib/ai-model/service-caller/system-one/schema.js.map +1 -0
  128. package/dist/lib/ai-model/service-caller/system-one/utils.js +68 -0
  129. package/dist/lib/ai-model/service-caller/system-one/utils.js.map +1 -0
  130. package/dist/lib/ai-model/service-caller/utils.js +2 -2
  131. package/dist/lib/ai-model/service-caller/utils.js.map +1 -1
  132. package/dist/lib/ai-model/shared/model-locate-result/factory.js +7 -3
  133. package/dist/lib/ai-model/shared/model-locate-result/factory.js.map +1 -1
  134. package/dist/lib/ai-model/shared/model-locate-result/pixel-mapper.js +10 -4
  135. package/dist/lib/ai-model/shared/model-locate-result/pixel-mapper.js.map +1 -1
  136. package/dist/lib/ai-model/shared/model-locate-result/types.js.map +1 -1
  137. package/dist/lib/ai-model/shared/model-locate-result/validation.js +4 -0
  138. package/dist/lib/ai-model/shared/model-locate-result/validation.js.map +1 -1
  139. package/dist/lib/ai-model/workflows/grounding/locate.js +1 -1
  140. package/dist/lib/ai-model/workflows/grounding/locate.js.map +1 -1
  141. package/dist/lib/ai-model/workflows/grounding/section-locate.js +1 -1
  142. package/dist/lib/ai-model/workflows/grounding/section-locate.js.map +1 -1
  143. package/dist/lib/ai-model/workflows/insight/boolean.js +1 -1
  144. package/dist/lib/ai-model/workflows/insight/boolean.js.map +1 -1
  145. package/dist/lib/ai-model/workflows/insight/extraction.js +2 -2
  146. package/dist/lib/ai-model/workflows/insight/extraction.js.map +1 -1
  147. package/dist/lib/ai-model/workflows/planning/standard-planning.js +3 -2
  148. package/dist/lib/ai-model/workflows/planning/standard-planning.js.map +1 -1
  149. package/dist/lib/ai-model/workflows/recorder-generation/playwright.js +1 -1
  150. package/dist/lib/ai-model/workflows/recorder-generation/playwright.js.map +1 -1
  151. package/dist/lib/ai-model/workflows/recorder-generation/yaml.js +1 -1
  152. package/dist/lib/ai-model/workflows/recorder-generation/yaml.js.map +1 -1
  153. package/dist/lib/device/index.js +7 -0
  154. package/dist/lib/device/index.js.map +1 -1
  155. package/dist/lib/report-html-template.js +1 -1
  156. package/dist/lib/service/index.js +2 -1
  157. package/dist/lib/service/index.js.map +1 -1
  158. package/dist/lib/types.js.map +1 -1
  159. package/dist/lib/utils.js +1 -1
  160. package/dist/types/agent/agent.d.ts.map +1 -1
  161. package/dist/types/agent/insight.d.ts +2 -2
  162. package/dist/types/agent/insight.d.ts.map +1 -1
  163. package/dist/types/agent/tasks.d.ts.map +1 -1
  164. package/dist/types/ai-model/connectivity/run-connectivity-test.d.ts.map +1 -1
  165. package/dist/types/ai-model/index.d.ts +1 -1
  166. package/dist/types/ai-model/index.d.ts.map +1 -1
  167. package/dist/types/ai-model/model-adapter/resolve.d.ts +2 -1
  168. package/dist/types/ai-model/model-adapter/resolve.d.ts.map +1 -1
  169. package/dist/types/ai-model/model-adapter/types.d.ts +8 -5
  170. package/dist/types/ai-model/model-adapter/types.d.ts.map +1 -1
  171. package/dist/types/ai-model/models/gpt.d.ts +2 -2
  172. package/dist/types/ai-model/models/jev/adapter.d.ts +4 -5
  173. package/dist/types/ai-model/models/jev/adapter.d.ts.map +1 -1
  174. package/dist/types/ai-model/models/jev/boolean.d.ts +3 -0
  175. package/dist/types/ai-model/models/jev/boolean.d.ts.map +1 -0
  176. package/dist/types/ai-model/models/jev/image.d.ts +11 -11
  177. package/dist/types/ai-model/models/jev/image.d.ts.map +1 -1
  178. package/dist/types/ai-model/models/jev/locate.d.ts +3 -0
  179. package/dist/types/ai-model/models/jev/locate.d.ts.map +1 -0
  180. package/dist/types/ai-model/models/jev/planning-action.d.ts +6 -0
  181. package/dist/types/ai-model/models/jev/planning-action.d.ts.map +1 -0
  182. package/dist/types/ai-model/models/jev/planning-context.d.ts +23 -0
  183. package/dist/types/ai-model/models/jev/planning-context.d.ts.map +1 -0
  184. package/dist/types/ai-model/models/jev/planning-decision.d.ts +35 -0
  185. package/dist/types/ai-model/models/jev/planning-decision.d.ts.map +1 -0
  186. package/dist/types/ai-model/models/jev/planning.d.ts.map +1 -1
  187. package/dist/types/ai-model/models/model-fallback.d.ts +6 -0
  188. package/dist/types/ai-model/models/model-fallback.d.ts.map +1 -0
  189. package/dist/types/ai-model/models/registry.d.ts +4 -3
  190. package/dist/types/ai-model/models/registry.d.ts.map +1 -1
  191. package/dist/types/ai-model/service-caller/call-ai.d.ts +3 -1
  192. package/dist/types/ai-model/service-caller/call-ai.d.ts.map +1 -1
  193. package/dist/types/ai-model/service-caller/codex/call-codex.d.ts +5 -3
  194. package/dist/types/ai-model/service-caller/codex/call-codex.d.ts.map +1 -1
  195. package/dist/types/ai-model/service-caller/index.d.ts +1 -1
  196. package/dist/types/ai-model/service-caller/index.d.ts.map +1 -1
  197. package/dist/types/ai-model/service-caller/model-call.d.ts +2 -2
  198. package/dist/types/ai-model/service-caller/model-call.d.ts.map +1 -1
  199. package/dist/types/ai-model/service-caller/openai/call-openai.d.ts +2 -2
  200. package/dist/types/ai-model/service-caller/openai/call-openai.d.ts.map +1 -1
  201. package/dist/types/ai-model/service-caller/openai/chat-completion/chat-completion.d.ts +4 -2
  202. package/dist/types/ai-model/service-caller/openai/chat-completion/chat-completion.d.ts.map +1 -1
  203. package/dist/types/ai-model/service-caller/openai/responses/responses.d.ts +4 -2
  204. package/dist/types/ai-model/service-caller/openai/responses/responses.d.ts.map +1 -1
  205. package/dist/types/ai-model/service-caller/system-one/call-system-one.d.ts +4 -0
  206. package/dist/types/ai-model/service-caller/system-one/call-system-one.d.ts.map +1 -0
  207. package/dist/types/ai-model/service-caller/system-one/index.d.ts +3 -0
  208. package/dist/types/ai-model/service-caller/system-one/index.d.ts.map +1 -0
  209. package/dist/types/ai-model/service-caller/system-one/prepare-system-one.d.ts +21 -0
  210. package/dist/types/ai-model/service-caller/system-one/prepare-system-one.d.ts.map +1 -0
  211. package/dist/types/ai-model/service-caller/{system-one.d.ts → system-one/schema.d.ts} +1 -22
  212. package/dist/types/ai-model/service-caller/system-one/schema.d.ts.map +1 -0
  213. package/dist/types/ai-model/service-caller/system-one/utils.d.ts +6 -0
  214. package/dist/types/ai-model/service-caller/system-one/utils.d.ts.map +1 -0
  215. package/dist/types/ai-model/service-caller/types.d.ts +0 -3
  216. package/dist/types/ai-model/service-caller/types.d.ts.map +1 -1
  217. package/dist/types/ai-model/service-caller/utils.d.ts +3 -3
  218. package/dist/types/ai-model/shared/model-locate-result/factory.d.ts.map +1 -1
  219. package/dist/types/ai-model/shared/model-locate-result/index.d.ts +1 -1
  220. package/dist/types/ai-model/shared/model-locate-result/index.d.ts.map +1 -1
  221. package/dist/types/ai-model/shared/model-locate-result/pixel-mapper.d.ts +3 -3
  222. package/dist/types/ai-model/shared/model-locate-result/pixel-mapper.d.ts.map +1 -1
  223. package/dist/types/ai-model/shared/model-locate-result/types.d.ts +4 -0
  224. package/dist/types/ai-model/shared/model-locate-result/types.d.ts.map +1 -1
  225. package/dist/types/ai-model/shared/model-locate-result/validation.d.ts.map +1 -1
  226. package/dist/types/ai-model/workflows/grounding/locate.d.ts.map +1 -1
  227. package/dist/types/ai-model/workflows/grounding/section-locate.d.ts.map +1 -1
  228. package/dist/types/ai-model/workflows/insight/boolean.d.ts.map +1 -1
  229. package/dist/types/ai-model/workflows/insight/extraction.d.ts +2 -0
  230. package/dist/types/ai-model/workflows/insight/extraction.d.ts.map +1 -1
  231. package/dist/types/ai-model/workflows/planning/standard-planning.d.ts.map +1 -1
  232. package/dist/types/ai-model/workflows/planning/types.d.ts +2 -1
  233. package/dist/types/ai-model/workflows/planning/types.d.ts.map +1 -1
  234. package/dist/types/ai-model/workflows/recorder-generation/playwright.d.ts.map +1 -1
  235. package/dist/types/ai-model/workflows/recorder-generation/yaml.d.ts.map +1 -1
  236. package/dist/types/device/index.d.ts +1 -0
  237. package/dist/types/device/index.d.ts.map +1 -1
  238. package/dist/types/service/index.d.ts +1 -1
  239. package/dist/types/service/index.d.ts.map +1 -1
  240. package/dist/types/types.d.ts +14 -3
  241. package/dist/types/types.d.ts.map +1 -1
  242. package/package.json +2 -2
  243. package/dist/es/ai-model/models/task-routing.mjs +0 -28
  244. package/dist/es/ai-model/models/task-routing.mjs.map +0 -1
  245. package/dist/es/ai-model/service-caller/system-one.mjs +0 -163
  246. package/dist/es/ai-model/service-caller/system-one.mjs.map +0 -1
  247. package/dist/lib/ai-model/models/task-routing.js.map +0 -1
  248. package/dist/lib/ai-model/service-caller/system-one.js +0 -206
  249. package/dist/lib/ai-model/service-caller/system-one.js.map +0 -1
  250. package/dist/types/ai-model/models/task-routing.d.ts +0 -6
  251. package/dist/types/ai-model/models/task-routing.d.ts.map +0 -1
  252. package/dist/types/ai-model/service-caller/system-one.d.ts.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { assert } from "@midscene/shared/utils";
2
2
  import { assertJsonObject } from "../shared/json.mjs";
3
- import { callAI } from "./call-ai.mjs";
3
+ import { callGenerativeAI } from "./call-ai.mjs";
4
4
  import { callAiAndParseWithRetry, withSemanticRetryFeedback } from "./semantic-retry.mjs";
5
5
  import { AIResponseParseError } from "./utils.mjs";
6
6
  function parseAIObjectResponse(response, modelRuntime, jsonParserSource = 'generic-object') {
@@ -21,7 +21,7 @@ function parseAIObjectResponse(response, modelRuntime, jsonParserSource = 'gener
21
21
  async function callAIWithObjectResponse(messages, modelRuntime, options) {
22
22
  const { config: modelConfig } = modelRuntime;
23
23
  return callAiAndParseWithRetry({
24
- callAi: (retryAttempt, previousParseError)=>callAI(withSemanticRetryFeedback(messages, previousParseError), modelRuntime, {
24
+ callAi: (retryAttempt, previousParseError)=>callGenerativeAI(withSemanticRetryFeedback(messages, previousParseError), modelRuntime, {
25
25
  abortSignal: options?.abortSignal,
26
26
  expectedJsonObjectResponse: true,
27
27
  semanticRetryAttempt: retryAttempt
@@ -37,7 +37,7 @@ async function callAIWithObjectResponse(messages, modelRuntime, options) {
37
37
  });
38
38
  }
39
39
  async function callAIWithStringResponse(msgs, modelRuntime, options) {
40
- const { content, usage, rawAssistantOutput } = await callAI(msgs, modelRuntime, options);
40
+ const { content, usage, rawAssistantOutput } = await callGenerativeAI(msgs, modelRuntime, options);
41
41
  return {
42
42
  content,
43
43
  usage,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/model-call.mjs","sources":["../../../../src/ai-model/service-caller/model-call.ts"],"sourcesContent":["import type { RawAssistantOutput } from '@/types';\nimport type { AIUsageInfo } from '@/types';\nimport { assert } from '@midscene/shared/utils';\nimport type { ModelRuntime } from '../models';\nimport { type JsonParserSource, assertJsonObject } from '../shared/json';\nimport { callAI } from './call-ai';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from './semantic-retry';\nimport type { CallAIOptions } from './types';\nimport type { ModelCallMessages } from './types';\nimport { AIResponseParseError } from './utils';\n\nexport type AIObjectResponse<T> = {\n // TODO: `content` is a misleading name here because this is already the parsed object response. Consider renaming it to `object` or `data`.\n content: T;\n contentString: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n rawAssistantOutput?: RawAssistantOutput;\n};\n\nexport function parseAIObjectResponse<T>(\n response: Awaited<ReturnType<typeof callAI>>,\n modelRuntime: ModelRuntime,\n jsonParserSource: JsonParserSource = 'generic-object',\n): AIObjectResponse<T> {\n const { adapter } = modelRuntime;\n assert(response, 'empty response');\n const jsonContent = adapter.jsonParser(response.content, {\n source: jsonParserSource,\n });\n assertJsonObject(jsonContent);\n return {\n content: jsonContent as T,\n contentString: response.content,\n usage: response.usage,\n reasoning_content: response.reasoning_content,\n rawAssistantOutput: response.rawAssistantOutput,\n };\n}\n\nexport async function callAIWithObjectResponse<T>(\n messages: ModelCallMessages,\n modelRuntime: ModelRuntime,\n options?: {\n abortSignal?: AbortSignal;\n jsonParserSource?: JsonParserSource;\n retryTimes?: number;\n retryInterval?: number;\n },\n): Promise<AIObjectResponse<T>> {\n const { config: modelConfig } = modelRuntime;\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callAI(\n withSemanticRetryFeedback(messages, previousParseError),\n modelRuntime,\n {\n abortSignal: options?.abortSignal,\n expectedJsonObjectResponse: true,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) =>\n parseAIObjectResponse<T>(\n response,\n modelRuntime,\n options?.jsonParserSource,\n ),\n toParseError: (error, response) => {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return new AIResponseParseError(\n errorMessage,\n response.content,\n response.usage,\n response.rawAssistantOutput,\n response.reasoning_content,\n );\n },\n parseRetryTimes: options?.retryTimes ?? modelConfig.retryCount,\n parseRetryInterval: options?.retryInterval ?? modelConfig.retryInterval,\n abortSignal: options?.abortSignal,\n });\n}\n\nexport async function callAIWithStringResponse(\n msgs: ModelCallMessages,\n modelRuntime: ModelRuntime,\n options?: Pick<CallAIOptions, 'abortSignal' | 'requiresOriginalImageDetail'>,\n): Promise<{\n content: string;\n usage?: AIUsageInfo;\n rawAssistantOutput?: RawAssistantOutput;\n}> {\n const { content, usage, rawAssistantOutput } = await callAI(\n msgs,\n modelRuntime,\n options,\n );\n return { content, usage, rawAssistantOutput };\n}\n"],"names":["parseAIObjectResponse","response","modelRuntime","jsonParserSource","adapter","assert","jsonContent","assertJsonObject","callAIWithObjectResponse","messages","options","modelConfig","callAiAndParseWithRetry","retryAttempt","previousParseError","callAI","withSemanticRetryFeedback","error","errorMessage","Error","String","AIResponseParseError","callAIWithStringResponse","msgs","content","usage","rawAssistantOutput"],"mappings":";;;;;AAuBO,SAASA,sBACdC,QAA4C,EAC5CC,YAA0B,EAC1BC,mBAAqC,gBAAgB;IAErD,MAAM,EAAEC,OAAO,EAAE,GAAGF;IACpBG,OAAOJ,UAAU;IACjB,MAAMK,cAAcF,QAAQ,UAAU,CAACH,SAAS,OAAO,EAAE;QACvD,QAAQE;IACV;IACAI,iBAAiBD;IACjB,OAAO;QACL,SAASA;QACT,eAAeL,SAAS,OAAO;QAC/B,OAAOA,SAAS,KAAK;QACrB,mBAAmBA,SAAS,iBAAiB;QAC7C,oBAAoBA,SAAS,kBAAkB;IACjD;AACF;AAEO,eAAeO,yBACpBC,QAA2B,EAC3BP,YAA0B,EAC1BQ,OAKC;IAED,MAAM,EAAE,QAAQC,WAAW,EAAE,GAAGT;IAChC,OAAOU,wBAAwB;QAC7B,QAAQ,CAACC,cAAcC,qBACrBC,OACEC,0BAA0BP,UAAUK,qBACpCZ,cACA;gBACE,aAAaQ,SAAS;gBACtB,4BAA4B;gBAC5B,sBAAsBG;YACxB;QAEJ,eAAe,CAACZ,WACdD,sBACEC,UACAC,cACAQ,SAAS;QAEb,cAAc,CAACO,OAAOhB;YACpB,MAAMiB,eACJD,iBAAiBE,QAAQF,MAAM,OAAO,GAAGG,OAAOH;YAClD,OAAO,IAAII,qBACTH,cACAjB,SAAS,OAAO,EAChBA,SAAS,KAAK,EACdA,SAAS,kBAAkB,EAC3BA,SAAS,iBAAiB;QAE9B;QACA,iBAAiBS,SAAS,cAAcC,YAAY,UAAU;QAC9D,oBAAoBD,SAAS,iBAAiBC,YAAY,aAAa;QACvE,aAAaD,SAAS;IACxB;AACF;AAEO,eAAeY,yBACpBC,IAAuB,EACvBrB,YAA0B,EAC1BQ,OAA4E;IAM5E,MAAM,EAAEc,OAAO,EAAEC,KAAK,EAAEC,kBAAkB,EAAE,GAAG,MAAMX,OACnDQ,MACArB,cACAQ;IAEF,OAAO;QAAEc;QAASC;QAAOC;IAAmB;AAC9C"}
1
+ {"version":3,"file":"ai-model/service-caller/model-call.mjs","sources":["../../../../src/ai-model/service-caller/model-call.ts"],"sourcesContent":["import type { RawAssistantOutput } from '@/types';\nimport type { AIUsageInfo } from '@/types';\nimport { assert } from '@midscene/shared/utils';\nimport type { ModelRuntime } from '../models';\nimport { type JsonParserSource, assertJsonObject } from '../shared/json';\nimport { callGenerativeAI } from './call-ai';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from './semantic-retry';\nimport type { CallAIOptions } from './types';\nimport type { ModelCallMessages } from './types';\nimport { AIResponseParseError } from './utils';\n\nexport type AIObjectResponse<T> = {\n // TODO: `content` is a misleading name here because this is already the parsed object response. Consider renaming it to `object` or `data`.\n content: T;\n contentString: string;\n usage?: AIUsageInfo;\n reasoning_content?: string;\n rawAssistantOutput?: RawAssistantOutput;\n};\n\nexport function parseAIObjectResponse<T>(\n response: Awaited<ReturnType<typeof callGenerativeAI>>,\n modelRuntime: ModelRuntime,\n jsonParserSource: JsonParserSource = 'generic-object',\n): AIObjectResponse<T> {\n const { adapter } = modelRuntime;\n assert(response, 'empty response');\n const jsonContent = adapter.jsonParser(response.content, {\n source: jsonParserSource,\n });\n assertJsonObject(jsonContent);\n return {\n content: jsonContent as T,\n contentString: response.content,\n usage: response.usage,\n reasoning_content: response.reasoning_content,\n rawAssistantOutput: response.rawAssistantOutput,\n };\n}\n\nexport async function callAIWithObjectResponse<T>(\n messages: ModelCallMessages,\n modelRuntime: ModelRuntime,\n options?: {\n abortSignal?: AbortSignal;\n jsonParserSource?: JsonParserSource;\n retryTimes?: number;\n retryInterval?: number;\n },\n): Promise<AIObjectResponse<T>> {\n const { config: modelConfig } = modelRuntime;\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callGenerativeAI(\n withSemanticRetryFeedback(messages, previousParseError),\n modelRuntime,\n {\n abortSignal: options?.abortSignal,\n expectedJsonObjectResponse: true,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) =>\n parseAIObjectResponse<T>(\n response,\n modelRuntime,\n options?.jsonParserSource,\n ),\n toParseError: (error, response) => {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return new AIResponseParseError(\n errorMessage,\n response.content,\n response.usage,\n response.rawAssistantOutput,\n response.reasoning_content,\n );\n },\n parseRetryTimes: options?.retryTimes ?? modelConfig.retryCount,\n parseRetryInterval: options?.retryInterval ?? modelConfig.retryInterval,\n abortSignal: options?.abortSignal,\n });\n}\n\nexport async function callAIWithStringResponse(\n msgs: ModelCallMessages,\n modelRuntime: ModelRuntime,\n options?: Pick<CallAIOptions, 'abortSignal' | 'requiresOriginalImageDetail'>,\n): Promise<{\n content: string;\n usage?: AIUsageInfo;\n rawAssistantOutput?: RawAssistantOutput;\n}> {\n const { content, usage, rawAssistantOutput } = await callGenerativeAI(\n msgs,\n modelRuntime,\n options,\n );\n return { content, usage, rawAssistantOutput };\n}\n"],"names":["parseAIObjectResponse","response","modelRuntime","jsonParserSource","adapter","assert","jsonContent","assertJsonObject","callAIWithObjectResponse","messages","options","modelConfig","callAiAndParseWithRetry","retryAttempt","previousParseError","callGenerativeAI","withSemanticRetryFeedback","error","errorMessage","Error","String","AIResponseParseError","callAIWithStringResponse","msgs","content","usage","rawAssistantOutput"],"mappings":";;;;;AAuBO,SAASA,sBACdC,QAAsD,EACtDC,YAA0B,EAC1BC,mBAAqC,gBAAgB;IAErD,MAAM,EAAEC,OAAO,EAAE,GAAGF;IACpBG,OAAOJ,UAAU;IACjB,MAAMK,cAAcF,QAAQ,UAAU,CAACH,SAAS,OAAO,EAAE;QACvD,QAAQE;IACV;IACAI,iBAAiBD;IACjB,OAAO;QACL,SAASA;QACT,eAAeL,SAAS,OAAO;QAC/B,OAAOA,SAAS,KAAK;QACrB,mBAAmBA,SAAS,iBAAiB;QAC7C,oBAAoBA,SAAS,kBAAkB;IACjD;AACF;AAEO,eAAeO,yBACpBC,QAA2B,EAC3BP,YAA0B,EAC1BQ,OAKC;IAED,MAAM,EAAE,QAAQC,WAAW,EAAE,GAAGT;IAChC,OAAOU,wBAAwB;QAC7B,QAAQ,CAACC,cAAcC,qBACrBC,iBACEC,0BAA0BP,UAAUK,qBACpCZ,cACA;gBACE,aAAaQ,SAAS;gBACtB,4BAA4B;gBAC5B,sBAAsBG;YACxB;QAEJ,eAAe,CAACZ,WACdD,sBACEC,UACAC,cACAQ,SAAS;QAEb,cAAc,CAACO,OAAOhB;YACpB,MAAMiB,eACJD,iBAAiBE,QAAQF,MAAM,OAAO,GAAGG,OAAOH;YAClD,OAAO,IAAII,qBACTH,cACAjB,SAAS,OAAO,EAChBA,SAAS,KAAK,EACdA,SAAS,kBAAkB,EAC3BA,SAAS,iBAAiB;QAE9B;QACA,iBAAiBS,SAAS,cAAcC,YAAY,UAAU;QAC9D,oBAAoBD,SAAS,iBAAiBC,YAAY,aAAa;QACvE,aAAaD,SAAS;IACxB;AACF;AAEO,eAAeY,yBACpBC,IAAuB,EACvBrB,YAA0B,EAC1BQ,OAA4E;IAM5E,MAAM,EAAEc,OAAO,EAAEC,KAAK,EAAEC,kBAAkB,EAAE,GAAG,MAAMX,iBACnDQ,MACArB,cACAQ;IAEF,OAAO;QAAEc;QAASC;QAAOC;IAAmB;AAC9C"}
@@ -26,7 +26,7 @@ async function callOpenAI({ modelRuntime, options, executionId, recordEvent, req
26
26
  };
27
27
  try {
28
28
  const startTime = Date.now();
29
- const response = 'responses' === prepared.protocol ? await callResponses({
29
+ const response = 'responses' === prepared.kind ? await callResponses({
30
30
  ...requestOptions,
31
31
  responses: openai.responses,
32
32
  requestBodyParams: prepared.input.requestParams
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/openai/call-openai.mjs","sources":["../../../../../src/ai-model/service-caller/openai/call-openai.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ModelCallContext, ModelCallResult } from '../types';\nimport { AIResponseParseError } from '../utils';\nimport {\n callChatCompletion,\n type prepareChatCompletion,\n} from './chat-completion/chat-completion';\nimport { createClient } from './openai-client';\nimport { formatOpenAIAPIErrorDetails } from './openai-request-context';\nimport { callResponses, type prepareResponses } from './responses/responses';\nimport { SiwcTokenExpiredError } from './siwc';\n\nexport type PreparedOpenAIInput =\n | {\n protocol: 'chat-completion';\n input: Awaited<ReturnType<typeof prepareChatCompletion>>;\n }\n | {\n protocol: 'responses';\n input: Awaited<ReturnType<typeof prepareResponses>>;\n };\n\nexport async function callOpenAI(\n {\n modelRuntime,\n options,\n executionId,\n recordEvent,\n requestSignal,\n effectiveTimeoutMs,\n }: ModelCallContext,\n prepared: PreparedOpenAIInput,\n): Promise<ModelCallResult> {\n const { config: modelConfig } = modelRuntime;\n const { modelName } = modelConfig;\n const isStreaming = options?.stream ?? modelConfig.streamMode === 'stream';\n const { openai, openAIRequestContext } = await createClient({\n modelConfig,\n proxyAgent: prepared.input.proxyAgent,\n effectiveTimeoutMs,\n executionId,\n recordEvent,\n });\n const debugCall = getDebug('ai:call');\n debugCall(\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\n );\n const requestOptions = {\n requestSignal,\n openAIRequestContext,\n onChunk: options?.onChunk ?? (() => undefined),\n recordEvent,\n };\n try {\n const startTime = Date.now();\n const response =\n prepared.protocol === 'responses'\n ? await callResponses(\n {\n ...requestOptions,\n responses: openai.responses,\n requestBodyParams: prepared.input.requestParams,\n },\n isStreaming,\n )\n : await callChatCompletion(\n {\n ...requestOptions,\n completion: openai.chat.completions,\n requestBodyParams: prepared.input.requestParams,\n extractContentAndReasoning:\n prepared.input.extractContentAndReasoning,\n useReasoningAsContentFallback:\n prepared.input.useReasoningAsContentFallback,\n },\n isStreaming,\n );\n const { reasoningContent, ...result } = response;\n requestSignal.throwIfAborted();\n const timeCost = Date.now() - startTime;\n debugCall(`response reasoning content: ${reasoningContent}`);\n debugCall(`response content: ${result.content}`);\n recordEvent?.({\n type: 'response',\n http: openAIRequestContext.httpResponse,\n final: {\n content: result.content,\n reasoningContent,\n usage: result.rawUsage,\n requestId: result.requestId,\n timeCost,\n responseModelName: result.responseModelName,\n },\n });\n return {\n ...result,\n reasoning_content: reasoningContent,\n isStreamed: isStreaming,\n timeCost,\n };\n } catch (error: any) {\n // Fetch already records non-2xx responses. Preserve successful HTTP\n // responses too when SDK parsing or completion validation fails.\n if (openAIRequestContext.httpResponse?.ok) {\n recordEvent?.({\n type: 'error',\n ...openAIRequestContext.httpResponse,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n getDebug('ai:call', {\n console: true,\n warning: { kind: 'model-request-detail', modelName, error },\n })('call AI error', error);\n if (error instanceof AIResponseParseError) {\n throw error;\n }\n const RequestError =\n modelConfig.authMode === 'siwc' &&\n error.status === 401 &&\n error.code === 'token_expired'\n ? SiwcTokenExpiredError\n : Error;\n throw new RequestError(\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service (${modelName}): ${error.message}${formatOpenAIAPIErrorDetails(error, openAIRequestContext)}\\nTrouble shooting: https://midscenejs.com/model-config#verify-model-connectivity`,\n { cause: error },\n );\n }\n}\n"],"names":["callOpenAI","modelRuntime","options","executionId","recordEvent","requestSignal","effectiveTimeoutMs","prepared","modelConfig","modelName","isStreaming","openai","openAIRequestContext","createClient","debugCall","getDebug","requestOptions","undefined","startTime","Date","response","callResponses","callChatCompletion","reasoningContent","result","timeCost","error","Error","String","AIResponseParseError","RequestError","SiwcTokenExpiredError","formatOpenAIAPIErrorDetails"],"mappings":";;;;;;;AAsBO,eAAeA,WACpB,EACEC,YAAY,EACZC,OAAO,EACPC,WAAW,EACXC,WAAW,EACXC,aAAa,EACbC,kBAAkB,EACD,EACnBC,QAA6B;IAE7B,MAAM,EAAE,QAAQC,WAAW,EAAE,GAAGP;IAChC,MAAM,EAAEQ,SAAS,EAAE,GAAGD;IACtB,MAAME,cAAcR,SAAS,UAAUM,AAA2B,aAA3BA,YAAY,UAAU;IAC7D,MAAM,EAAEG,MAAM,EAAEC,oBAAoB,EAAE,GAAG,MAAMC,aAAa;QAC1DL;QACA,YAAYD,SAAS,KAAK,CAAC,UAAU;QACrCD;QACAH;QACAC;IACF;IACA,MAAMU,YAAYC,SAAS;IAC3BD,UACE,CAAC,QAAQ,EAAEJ,cAAc,eAAe,GAAG,WAAW,EAAED,WAAW;IAErE,MAAMO,iBAAiB;QACrBX;QACAO;QACA,SAASV,SAAS,WAAa,KAAKe,MAAQ;QAC5Cb;IACF;IACA,IAAI;QACF,MAAMc,YAAYC,KAAK,GAAG;QAC1B,MAAMC,WACJb,AAAsB,gBAAtBA,SAAS,QAAQ,GACb,MAAMc,cACJ;YACE,GAAGL,cAAc;YACjB,WAAWL,OAAO,SAAS;YAC3B,mBAAmBJ,SAAS,KAAK,CAAC,aAAa;QACjD,GACAG,eAEF,MAAMY,mBACJ;YACE,GAAGN,cAAc;YACjB,YAAYL,OAAO,IAAI,CAAC,WAAW;YACnC,mBAAmBJ,SAAS,KAAK,CAAC,aAAa;YAC/C,4BACEA,SAAS,KAAK,CAAC,0BAA0B;YAC3C,+BACEA,SAAS,KAAK,CAAC,6BAA6B;QAChD,GACAG;QAER,MAAM,EAAEa,gBAAgB,EAAE,GAAGC,QAAQ,GAAGJ;QACxCf,cAAc,cAAc;QAC5B,MAAMoB,WAAWN,KAAK,GAAG,KAAKD;QAC9BJ,UAAU,CAAC,4BAA4B,EAAES,kBAAkB;QAC3DT,UAAU,CAAC,kBAAkB,EAAEU,OAAO,OAAO,EAAE;QAC/CpB,cAAc;YACZ,MAAM;YACN,MAAMQ,qBAAqB,YAAY;YACvC,OAAO;gBACL,SAASY,OAAO,OAAO;gBACvBD;gBACA,OAAOC,OAAO,QAAQ;gBACtB,WAAWA,OAAO,SAAS;gBAC3BC;gBACA,mBAAmBD,OAAO,iBAAiB;YAC7C;QACF;QACA,OAAO;YACL,GAAGA,MAAM;YACT,mBAAmBD;YACnB,YAAYb;YACZe;QACF;IACF,EAAE,OAAOC,OAAY;QAGnB,IAAId,qBAAqB,YAAY,EAAE,IACrCR,cAAc;YACZ,MAAM;YACN,GAAGQ,qBAAqB,YAAY;YACpC,OAAOc,iBAAiBC,QAAQD,MAAM,OAAO,GAAGE,OAAOF;QACzD;QAEFX,SAAS,WAAW;YAClB,SAAS;YACT,SAAS;gBAAE,MAAM;gBAAwBN;gBAAWiB;YAAM;QAC5D,GAAG,iBAAiBA;QACpB,IAAIA,iBAAiBG,sBACnB,MAAMH;QAER,MAAMI,eACJtB,AAAyB,WAAzBA,YAAY,QAAQ,IACpBkB,AAAiB,QAAjBA,MAAM,MAAM,IACZA,AAAe,oBAAfA,MAAM,IAAI,GACNK,wBACAJ;QACN,MAAM,IAAIG,aACR,CAAC,eAAe,EAAEpB,cAAc,eAAe,GAAG,kBAAkB,EAAED,UAAU,GAAG,EAAEiB,MAAM,OAAO,GAAGM,4BAA4BN,OAAOd,sBAAsB,iFAAiF,CAAC,EAChP;YAAE,OAAOc;QAAM;IAEnB;AACF"}
1
+ {"version":3,"file":"ai-model/service-caller/openai/call-openai.mjs","sources":["../../../../../src/ai-model/service-caller/openai/call-openai.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ModelCallContext, ModelCallResult } from '../types';\nimport { AIResponseParseError } from '../utils';\nimport {\n callChatCompletion,\n type prepareChatCompletion,\n} from './chat-completion/chat-completion';\nimport { createClient } from './openai-client';\nimport { formatOpenAIAPIErrorDetails } from './openai-request-context';\nimport { callResponses, type prepareResponses } from './responses/responses';\nimport { SiwcTokenExpiredError } from './siwc';\n\nexport type PreparedOpenAIInput =\n | {\n kind: 'chat-completion';\n input: Awaited<ReturnType<typeof prepareChatCompletion>>;\n }\n | {\n kind: 'responses';\n input: Awaited<ReturnType<typeof prepareResponses>>;\n };\n\nexport async function callOpenAI(\n {\n modelRuntime,\n options,\n executionId,\n recordEvent,\n requestSignal,\n effectiveTimeoutMs,\n }: ModelCallContext,\n prepared: PreparedOpenAIInput,\n): Promise<ModelCallResult> {\n const { config: modelConfig } = modelRuntime;\n const { modelName } = modelConfig;\n const isStreaming = options?.stream ?? modelConfig.streamMode === 'stream';\n const { openai, openAIRequestContext } = await createClient({\n modelConfig,\n proxyAgent: prepared.input.proxyAgent,\n effectiveTimeoutMs,\n executionId,\n recordEvent,\n });\n const debugCall = getDebug('ai:call');\n debugCall(\n `sending ${isStreaming ? 'streaming ' : ''}request to ${modelName}`,\n );\n const requestOptions = {\n requestSignal,\n openAIRequestContext,\n onChunk: options?.onChunk ?? (() => undefined),\n recordEvent,\n };\n try {\n const startTime = Date.now();\n const response =\n prepared.kind === 'responses'\n ? await callResponses(\n {\n ...requestOptions,\n responses: openai.responses,\n requestBodyParams: prepared.input.requestParams,\n },\n isStreaming,\n )\n : await callChatCompletion(\n {\n ...requestOptions,\n completion: openai.chat.completions,\n requestBodyParams: prepared.input.requestParams,\n extractContentAndReasoning:\n prepared.input.extractContentAndReasoning,\n useReasoningAsContentFallback:\n prepared.input.useReasoningAsContentFallback,\n },\n isStreaming,\n );\n const { reasoningContent, ...result } = response;\n requestSignal.throwIfAborted();\n const timeCost = Date.now() - startTime;\n debugCall(`response reasoning content: ${reasoningContent}`);\n debugCall(`response content: ${result.content}`);\n recordEvent?.({\n type: 'response',\n http: openAIRequestContext.httpResponse,\n final: {\n content: result.content,\n reasoningContent,\n usage: result.rawUsage,\n requestId: result.requestId,\n timeCost,\n responseModelName: result.responseModelName,\n },\n });\n return {\n ...result,\n reasoning_content: reasoningContent,\n isStreamed: isStreaming,\n timeCost,\n };\n } catch (error: any) {\n // Fetch already records non-2xx responses. Preserve successful HTTP\n // responses too when SDK parsing or completion validation fails.\n if (openAIRequestContext.httpResponse?.ok) {\n recordEvent?.({\n type: 'error',\n ...openAIRequestContext.httpResponse,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n getDebug('ai:call', {\n console: true,\n warning: { kind: 'model-request-detail', modelName, error },\n })('call AI error', error);\n if (error instanceof AIResponseParseError) {\n throw error;\n }\n const RequestError =\n modelConfig.authMode === 'siwc' &&\n error.status === 401 &&\n error.code === 'token_expired'\n ? SiwcTokenExpiredError\n : Error;\n throw new RequestError(\n `failed to call ${isStreaming ? 'streaming ' : ''}AI model service (${modelName}): ${error.message}${formatOpenAIAPIErrorDetails(error, openAIRequestContext)}\\nTrouble shooting: https://midscenejs.com/model-config#verify-model-connectivity`,\n { cause: error },\n );\n }\n}\n"],"names":["callOpenAI","modelRuntime","options","executionId","recordEvent","requestSignal","effectiveTimeoutMs","prepared","modelConfig","modelName","isStreaming","openai","openAIRequestContext","createClient","debugCall","getDebug","requestOptions","undefined","startTime","Date","response","callResponses","callChatCompletion","reasoningContent","result","timeCost","error","Error","String","AIResponseParseError","RequestError","SiwcTokenExpiredError","formatOpenAIAPIErrorDetails"],"mappings":";;;;;;;AAsBO,eAAeA,WACpB,EACEC,YAAY,EACZC,OAAO,EACPC,WAAW,EACXC,WAAW,EACXC,aAAa,EACbC,kBAAkB,EACD,EACnBC,QAA6B;IAE7B,MAAM,EAAE,QAAQC,WAAW,EAAE,GAAGP;IAChC,MAAM,EAAEQ,SAAS,EAAE,GAAGD;IACtB,MAAME,cAAcR,SAAS,UAAUM,AAA2B,aAA3BA,YAAY,UAAU;IAC7D,MAAM,EAAEG,MAAM,EAAEC,oBAAoB,EAAE,GAAG,MAAMC,aAAa;QAC1DL;QACA,YAAYD,SAAS,KAAK,CAAC,UAAU;QACrCD;QACAH;QACAC;IACF;IACA,MAAMU,YAAYC,SAAS;IAC3BD,UACE,CAAC,QAAQ,EAAEJ,cAAc,eAAe,GAAG,WAAW,EAAED,WAAW;IAErE,MAAMO,iBAAiB;QACrBX;QACAO;QACA,SAASV,SAAS,WAAa,KAAKe,MAAQ;QAC5Cb;IACF;IACA,IAAI;QACF,MAAMc,YAAYC,KAAK,GAAG;QAC1B,MAAMC,WACJb,AAAkB,gBAAlBA,SAAS,IAAI,GACT,MAAMc,cACJ;YACE,GAAGL,cAAc;YACjB,WAAWL,OAAO,SAAS;YAC3B,mBAAmBJ,SAAS,KAAK,CAAC,aAAa;QACjD,GACAG,eAEF,MAAMY,mBACJ;YACE,GAAGN,cAAc;YACjB,YAAYL,OAAO,IAAI,CAAC,WAAW;YACnC,mBAAmBJ,SAAS,KAAK,CAAC,aAAa;YAC/C,4BACEA,SAAS,KAAK,CAAC,0BAA0B;YAC3C,+BACEA,SAAS,KAAK,CAAC,6BAA6B;QAChD,GACAG;QAER,MAAM,EAAEa,gBAAgB,EAAE,GAAGC,QAAQ,GAAGJ;QACxCf,cAAc,cAAc;QAC5B,MAAMoB,WAAWN,KAAK,GAAG,KAAKD;QAC9BJ,UAAU,CAAC,4BAA4B,EAAES,kBAAkB;QAC3DT,UAAU,CAAC,kBAAkB,EAAEU,OAAO,OAAO,EAAE;QAC/CpB,cAAc;YACZ,MAAM;YACN,MAAMQ,qBAAqB,YAAY;YACvC,OAAO;gBACL,SAASY,OAAO,OAAO;gBACvBD;gBACA,OAAOC,OAAO,QAAQ;gBACtB,WAAWA,OAAO,SAAS;gBAC3BC;gBACA,mBAAmBD,OAAO,iBAAiB;YAC7C;QACF;QACA,OAAO;YACL,GAAGA,MAAM;YACT,mBAAmBD;YACnB,YAAYb;YACZe;QACF;IACF,EAAE,OAAOC,OAAY;QAGnB,IAAId,qBAAqB,YAAY,EAAE,IACrCR,cAAc;YACZ,MAAM;YACN,GAAGQ,qBAAqB,YAAY;YACpC,OAAOc,iBAAiBC,QAAQD,MAAM,OAAO,GAAGE,OAAOF;QACzD;QAEFX,SAAS,WAAW;YAClB,SAAS;YACT,SAAS;gBAAE,MAAM;gBAAwBN;gBAAWiB;YAAM;QAC5D,GAAG,iBAAiBA;QACpB,IAAIA,iBAAiBG,sBACnB,MAAMH;QAER,MAAMI,eACJtB,AAAyB,WAAzBA,YAAY,QAAQ,IACpBkB,AAAiB,QAAjBA,MAAM,MAAM,IACZA,AAAe,oBAAfA,MAAM,IAAI,GACNK,wBACAJ;QACN,MAAM,IAAIG,aACR,CAAC,eAAe,EAAEpB,cAAc,eAAe,GAAG,kBAAkB,EAAED,UAAU,GAAG,EAAEiB,MAAM,OAAO,GAAGM,4BAA4BN,OAAOd,sBAAsB,iFAAiF,CAAC,EAChP;YAAE,OAAOc;QAAM;IAEnB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/openai/chat-completion/chat-completion.mjs","sources":["../../../../../../src/ai-model/service-caller/openai/chat-completion/chat-completion.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ResolveImageDetail } from '../../../model-adapter/types';\nimport type { ModelRequestConfigInput } from '../../../model-adapter/types';\nimport { createProxyAgentIfNeeded } from '../../proxy';\nimport type { ModelCallContext, OpenAIProtocolCallResult } from '../../types';\nimport { stringifyForDebug } from '../../utils';\nimport { callChatCompletionNonStreaming } from './non-stream';\nimport { callChatCompletionStream } from './stream';\nimport type { ChatCompletionCallOptions } from './types';\nimport { toChatMessages } from './utils';\n\nexport const prepareChatCompletion = async ({\n messages,\n modelRuntime,\n options,\n}: Pick<ModelCallContext, 'messages' | 'modelRuntime' | 'options'>) => {\n const debugCall = getDebug('ai:call');\n const { config: modelConfig, adapter } = modelRuntime;\n\n const modelCallInput: ModelRequestConfigInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n responseFormat: modelConfig.responseFormat,\n },\n semanticRetryAttempt: options?.semanticRetryAttempt,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n expectedJsonObjectResponse: options?.expectedJsonObjectResponse,\n };\n\n const { config: adapterChatCompletionParams } =\n adapter.chatCompletion.buildChatCompletionParams(modelCallInput);\n\n debugCall(\n `adapter chat completion params: ${stringifyForDebug({\n config: adapterChatCompletionParams,\n })}`,\n );\n\n const resolveImageDetail: ResolveImageDetail = ({ imageDetail }) =>\n adapter.resolveImageDetail({\n imageDetail,\n intent: modelConfig.intent,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n });\n\n const requestBodyParams: ChatCompletionCallOptions['requestBodyParams'] = {\n model: modelConfig.modelName,\n messages: toChatMessages(messages, resolveImageDetail),\n ...adapterChatCompletionParams,\n ...(modelConfig.extraBody ?? {}),\n };\n\n const proxyAgent = await createProxyAgentIfNeeded({\n socksProxy: modelConfig.socksProxy,\n httpProxy: modelConfig.httpProxy,\n });\n\n return {\n requestParams: requestBodyParams,\n extractContentAndReasoning:\n adapter.chatCompletion.extractContentAndReasoning,\n useReasoningAsContentFallback:\n adapter.chatCompletion.useReasoningAsContentFallback,\n proxyAgent,\n };\n};\n\nexport function callChatCompletion(\n options: ChatCompletionCallOptions,\n stream: boolean,\n): Promise<OpenAIProtocolCallResult> {\n return stream\n ? callChatCompletionStream(options)\n : callChatCompletionNonStreaming(options);\n}\n"],"names":["prepareChatCompletion","messages","modelRuntime","options","debugCall","getDebug","modelConfig","adapter","modelCallInput","adapterChatCompletionParams","stringifyForDebug","resolveImageDetail","imageDetail","requestBodyParams","toChatMessages","proxyAgent","createProxyAgentIfNeeded","callChatCompletion","stream","callChatCompletionStream","callChatCompletionNonStreaming"],"mappings":";;;;;;AAWO,MAAMA,wBAAwB,OAAO,EAC1CC,QAAQ,EACRC,YAAY,EACZC,OAAO,EACyD;IAChE,MAAMC,YAAYC,SAAS;IAC3B,MAAM,EAAE,QAAQC,WAAW,EAAEC,OAAO,EAAE,GAAGL;IAEzC,MAAMM,iBAA0C;QAC9C,QAAQF,YAAY,MAAM;QAC1B,YAAY;YACV,aAAaA,YAAY,WAAW;YACpC,kBAAkBA,YAAY,gBAAgB;YAC9C,iBAAiBA,YAAY,eAAe;YAC5C,iBAAiBA,YAAY,eAAe;YAC5C,gBAAgBA,YAAY,cAAc;QAC5C;QACA,sBAAsBH,SAAS;QAC/B,6BAA6BA,SAAS;QACtC,4BAA4BA,SAAS;IACvC;IAEA,MAAM,EAAE,QAAQM,2BAA2B,EAAE,GAC3CF,QAAQ,cAAc,CAAC,yBAAyB,CAACC;IAEnDJ,UACE,CAAC,gCAAgC,EAAEM,kBAAkB;QACnD,QAAQD;IACV,IAAI;IAGN,MAAME,qBAAyC,CAAC,EAAEC,WAAW,EAAE,GAC7DL,QAAQ,kBAAkB,CAAC;YACzBK;YACA,QAAQN,YAAY,MAAM;YAC1B,6BAA6BH,SAAS;QACxC;IAEF,MAAMU,oBAAoE;QACxE,OAAOP,YAAY,SAAS;QAC5B,UAAUQ,eAAeb,UAAUU;QACnC,GAAGF,2BAA2B;QAC9B,GAAIH,YAAY,SAAS,IAAI,CAAC,CAAC;IACjC;IAEA,MAAMS,aAAa,MAAMC,yBAAyB;QAChD,YAAYV,YAAY,UAAU;QAClC,WAAWA,YAAY,SAAS;IAClC;IAEA,OAAO;QACL,eAAeO;QACf,4BACEN,QAAQ,cAAc,CAAC,0BAA0B;QACnD,+BACEA,QAAQ,cAAc,CAAC,6BAA6B;QACtDQ;IACF;AACF;AAEO,SAASE,mBACdd,OAAkC,EAClCe,MAAe;IAEf,OAAOA,SACHC,yBAAyBhB,WACzBiB,+BAA+BjB;AACrC"}
1
+ {"version":3,"file":"ai-model/service-caller/openai/chat-completion/chat-completion.mjs","sources":["../../../../../../src/ai-model/service-caller/openai/chat-completion/chat-completion.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ResolveImageDetail } from '../../../model-adapter/types';\nimport type { ModelRequestConfigInput } from '../../../model-adapter/types';\nimport { createProxyAgentIfNeeded } from '../../proxy';\nimport type {\n ModelCallContext,\n ModelCallMessages,\n OpenAIProtocolCallResult,\n} from '../../types';\nimport { stringifyForDebug } from '../../utils';\nimport { callChatCompletionNonStreaming } from './non-stream';\nimport { callChatCompletionStream } from './stream';\nimport type { ChatCompletionCallOptions } from './types';\nimport { toChatMessages } from './utils';\n\nexport const prepareChatCompletion = async ({\n messages,\n modelRuntime,\n options,\n}: Pick<ModelCallContext, 'modelRuntime' | 'options'> & {\n messages: ModelCallMessages;\n}) => {\n const debugCall = getDebug('ai:call');\n const { config: modelConfig, adapter } = modelRuntime;\n\n const modelCallInput: ModelRequestConfigInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n responseFormat: modelConfig.responseFormat,\n },\n semanticRetryAttempt: options?.semanticRetryAttempt,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n expectedJsonObjectResponse: options?.expectedJsonObjectResponse,\n };\n\n const { config: adapterChatCompletionParams } =\n adapter.chatCompletion.buildChatCompletionParams(modelCallInput);\n\n debugCall(\n `adapter chat completion params: ${stringifyForDebug({\n config: adapterChatCompletionParams,\n })}`,\n );\n\n const resolveImageDetail: ResolveImageDetail = ({ imageDetail }) =>\n adapter.resolveImageDetail({\n imageDetail,\n intent: modelConfig.intent,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n });\n\n const requestBodyParams: ChatCompletionCallOptions['requestBodyParams'] = {\n model: modelConfig.modelName,\n messages: toChatMessages(messages, resolveImageDetail),\n ...adapterChatCompletionParams,\n ...(modelConfig.extraBody ?? {}),\n };\n\n const proxyAgent = await createProxyAgentIfNeeded({\n socksProxy: modelConfig.socksProxy,\n httpProxy: modelConfig.httpProxy,\n });\n\n return {\n requestParams: requestBodyParams,\n extractContentAndReasoning:\n adapter.chatCompletion.extractContentAndReasoning,\n useReasoningAsContentFallback:\n adapter.chatCompletion.useReasoningAsContentFallback,\n proxyAgent,\n };\n};\n\nexport function callChatCompletion(\n options: ChatCompletionCallOptions,\n stream: boolean,\n): Promise<OpenAIProtocolCallResult> {\n return stream\n ? callChatCompletionStream(options)\n : callChatCompletionNonStreaming(options);\n}\n"],"names":["prepareChatCompletion","messages","modelRuntime","options","debugCall","getDebug","modelConfig","adapter","modelCallInput","adapterChatCompletionParams","stringifyForDebug","resolveImageDetail","imageDetail","requestBodyParams","toChatMessages","proxyAgent","createProxyAgentIfNeeded","callChatCompletion","stream","callChatCompletionStream","callChatCompletionNonStreaming"],"mappings":";;;;;;AAeO,MAAMA,wBAAwB,OAAO,EAC1CC,QAAQ,EACRC,YAAY,EACZC,OAAO,EAGR;IACC,MAAMC,YAAYC,SAAS;IAC3B,MAAM,EAAE,QAAQC,WAAW,EAAEC,OAAO,EAAE,GAAGL;IAEzC,MAAMM,iBAA0C;QAC9C,QAAQF,YAAY,MAAM;QAC1B,YAAY;YACV,aAAaA,YAAY,WAAW;YACpC,kBAAkBA,YAAY,gBAAgB;YAC9C,iBAAiBA,YAAY,eAAe;YAC5C,iBAAiBA,YAAY,eAAe;YAC5C,gBAAgBA,YAAY,cAAc;QAC5C;QACA,sBAAsBH,SAAS;QAC/B,6BAA6BA,SAAS;QACtC,4BAA4BA,SAAS;IACvC;IAEA,MAAM,EAAE,QAAQM,2BAA2B,EAAE,GAC3CF,QAAQ,cAAc,CAAC,yBAAyB,CAACC;IAEnDJ,UACE,CAAC,gCAAgC,EAAEM,kBAAkB;QACnD,QAAQD;IACV,IAAI;IAGN,MAAME,qBAAyC,CAAC,EAAEC,WAAW,EAAE,GAC7DL,QAAQ,kBAAkB,CAAC;YACzBK;YACA,QAAQN,YAAY,MAAM;YAC1B,6BAA6BH,SAAS;QACxC;IAEF,MAAMU,oBAAoE;QACxE,OAAOP,YAAY,SAAS;QAC5B,UAAUQ,eAAeb,UAAUU;QACnC,GAAGF,2BAA2B;QAC9B,GAAIH,YAAY,SAAS,IAAI,CAAC,CAAC;IACjC;IAEA,MAAMS,aAAa,MAAMC,yBAAyB;QAChD,YAAYV,YAAY,UAAU;QAClC,WAAWA,YAAY,SAAS;IAClC;IAEA,OAAO;QACL,eAAeO;QACf,4BACEN,QAAQ,cAAc,CAAC,0BAA0B;QACnD,+BACEA,QAAQ,cAAc,CAAC,6BAA6B;QACtDQ;IACF;AACF;AAEO,SAASE,mBACdd,OAAkC,EAClCe,MAAe;IAEf,OAAOA,SACHC,yBAAyBhB,WACzBiB,+BAA+BjB;AACrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/openai/openai-client.mjs","sources":["../../../../../src/ai-model/service-caller/openai/openai-client.ts"],"sourcesContent":["import {\n type IModelConfig,\n MIDSCENE_LANGFUSE_DEBUG,\n MIDSCENE_LANGSMITH_DEBUG,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { ifInBrowser } from '@midscene/shared/utils';\nimport OpenAI from 'openai';\nimport { getVersion } from '../../../utils';\nimport type { createProxyAgentIfNeeded } from '../proxy';\nimport {\n type OpenAIRequestContext,\n wrapOpenAICompatibleFetch,\n} from './openai-request-context';\n\nconst createAndWrapClient = async ({\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n createOpenAIClient,\n effectiveTimeoutMs,\n proxyAgent,\n executionId,\n openAIRequestContext,\n}: {\n openaiBaseURL: IModelConfig['openaiBaseURL'];\n openaiApiKey: IModelConfig['openaiApiKey'];\n openaiExtraConfig: IModelConfig['openaiExtraConfig'];\n createOpenAIClient: IModelConfig['createOpenAIClient'];\n effectiveTimeoutMs: number | null;\n proxyAgent: Awaited<ReturnType<typeof createProxyAgentIfNeeded>>;\n executionId: string;\n openAIRequestContext: OpenAIRequestContext;\n}): Promise<OpenAI> => {\n const warnClient = getDebug('ai:call', { console: true });\n\n const openAIOptions = {\n baseURL: openaiBaseURL,\n apiKey: openaiApiKey,\n // Use fetchOptions.dispatcher for fetch-based SDK instead of httpAgent\n // Note: Type assertion needed due to undici version mismatch between dependencies\n ...(proxyAgent ? { fetchOptions: { dispatcher: proxyAgent as any } } : {}),\n ...openaiExtraConfig,\n // Midscene exposes this setting through MIDSCENE_*_INIT_CONFIG_JSON, so\n // defaultHeaders is expected to be a plain JSON object rather than another\n // HeadersLike representation supported by the OpenAI SDK.\n defaultHeaders: {\n ...(openaiExtraConfig?.defaultHeaders as\n | Record<string, string>\n | undefined),\n // These Midscene-owned headers intentionally override user-supplied\n // headers with the same names.\n 'x-midscene-version': getVersion(),\n 'x-midscene-execution-id': executionId,\n },\n fetch: wrapOpenAICompatibleFetch(openAIRequestContext),\n // Midscene handles request retries in callAI(), so disable SDK-level retries\n // to avoid duplicate attempts and duplicated backoff latency.\n maxRetries: 0,\n // Disabling the Midscene hard timeout leaves the SDK timeout at its\n // configured value or default; it does not disable SDK/network timeouts.\n ...(effectiveTimeoutMs !== null ? { timeout: effectiveTimeoutMs } : {}),\n dangerouslyAllowBrowser: true,\n };\n\n const baseOpenAI = new OpenAI(openAIOptions);\n\n let openai: OpenAI = baseOpenAI;\n\n // LangSmith wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langsmith is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langsmith wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langsmithModule = 'langsmith/wrappers';\n const { wrapOpenAI } = await import(langsmithModule);\n openai = wrapOpenAI(openai);\n }\n\n // Langfuse wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGFUSE_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langfuse is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langfuse wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langfuseModule = '@langfuse/openai';\n const { observeOpenAI } = await import(langfuseModule);\n openai = observeOpenAI(openai);\n }\n\n if (createOpenAIClient) {\n const wrappedClient = await createOpenAIClient(baseOpenAI, openAIOptions);\n\n if (wrappedClient) {\n openai = wrappedClient as OpenAI;\n }\n }\n\n return openai;\n};\n\nexport async function createClient({\n modelConfig,\n proxyAgent,\n effectiveTimeoutMs,\n executionId,\n recordEvent,\n}: {\n modelConfig: IModelConfig;\n proxyAgent: Awaited<ReturnType<typeof createProxyAgentIfNeeded>>;\n effectiveTimeoutMs: number | null;\n executionId: string;\n recordEvent?: (event: Record<string, unknown>) => void;\n}): Promise<{\n openai: OpenAI;\n openAIRequestContext: OpenAIRequestContext;\n}> {\n const { openaiBaseURL, openaiApiKey, openaiExtraConfig, createOpenAIClient } =\n modelConfig;\n\n const openAIRequestContext: OpenAIRequestContext = {\n recordEvent,\n };\n\n const openai = await createAndWrapClient({\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n createOpenAIClient,\n effectiveTimeoutMs,\n proxyAgent,\n executionId,\n openAIRequestContext,\n });\n\n return {\n openai,\n openAIRequestContext,\n };\n}\n"],"names":["createAndWrapClient","openaiBaseURL","openaiApiKey","openaiExtraConfig","createOpenAIClient","effectiveTimeoutMs","proxyAgent","executionId","openAIRequestContext","warnClient","getDebug","openAIOptions","getVersion","wrapOpenAICompatibleFetch","baseOpenAI","OpenAI","openai","globalConfigManager","MIDSCENE_LANGSMITH_DEBUG","ifInBrowser","Error","langsmithModule","wrapOpenAI","MIDSCENE_LANGFUSE_DEBUG","langfuseModule","observeOpenAI","wrappedClient","createClient","modelConfig","recordEvent"],"mappings":";;;;;;AAgBA,MAAMA,sBAAsB,OAAO,EACjCC,aAAa,EACbC,YAAY,EACZC,iBAAiB,EACjBC,kBAAkB,EAClBC,kBAAkB,EAClBC,UAAU,EACVC,WAAW,EACXC,oBAAoB,EAUrB;IACC,MAAMC,aAAaC,SAAS,WAAW;QAAE,SAAS;IAAK;IAEvD,MAAMC,gBAAgB;QACpB,SAASV;QACT,QAAQC;QAGR,GAAII,aAAa;YAAE,cAAc;gBAAE,YAAYA;YAAkB;QAAE,IAAI,CAAC,CAAC;QACzE,GAAGH,iBAAiB;QAIpB,gBAAgB;YACd,GAAIA,mBAAmB,cAAc;YAKrC,sBAAsBS;YACtB,2BAA2BL;QAC7B;QACA,OAAOM,0BAA0BL;QAGjC,YAAY;QAGZ,GAAIH,AAAuB,SAAvBA,qBAA8B;YAAE,SAASA;QAAmB,IAAI,CAAC,CAAC;QACtE,yBAAyB;IAC3B;IAEA,MAAMS,aAAa,IAAIC,SAAOJ;IAE9B,IAAIK,SAAiBF;IAGrB,IACEE,UACAC,oBAAoB,qBAAqB,CAACC,2BAC1C;QACA,IAAIC,aACF,MAAM,IAAIC,MAAM;QAElBX,WAAW;QAEX,MAAMY,kBAAkB;QACxB,MAAM,EAAEC,UAAU,EAAE,GAAG,MAAM,MAAM,CAACD;QACpCL,SAASM,WAAWN;IACtB;IAGA,IACEA,UACAC,oBAAoB,qBAAqB,CAACM,0BAC1C;QACA,IAAIJ,aACF,MAAM,IAAIC,MAAM;QAElBX,WAAW;QAEX,MAAMe,iBAAiB;QACvB,MAAM,EAAEC,aAAa,EAAE,GAAG,MAAM,MAAM,CAACD;QACvCR,SAASS,cAAcT;IACzB;IAEA,IAAIZ,oBAAoB;QACtB,MAAMsB,gBAAgB,MAAMtB,mBAAmBU,YAAYH;QAE3D,IAAIe,eACFV,SAASU;IAEb;IAEA,OAAOV;AACT;AAEO,eAAeW,aAAa,EACjCC,WAAW,EACXtB,UAAU,EACVD,kBAAkB,EAClBE,WAAW,EACXsB,WAAW,EAOZ;IAIC,MAAM,EAAE5B,aAAa,EAAEC,YAAY,EAAEC,iBAAiB,EAAEC,kBAAkB,EAAE,GAC1EwB;IAEF,MAAMpB,uBAA6C;QACjDqB;IACF;IAEA,MAAMb,SAAS,MAAMhB,oBAAoB;QACvCC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;IACF;IAEA,OAAO;QACLQ;QACAR;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/service-caller/openai/openai-client.mjs","sources":["../../../../../src/ai-model/service-caller/openai/openai-client.ts"],"sourcesContent":["import {\n type IModelConfig,\n MIDSCENE_LANGFUSE_DEBUG,\n MIDSCENE_LANGSMITH_DEBUG,\n globalConfigManager,\n} from '@midscene/shared/env';\nimport { getDebug } from '@midscene/shared/logger';\nimport { ifInBrowser } from '@midscene/shared/utils';\nimport OpenAI from 'openai';\nimport { getVersion } from '../../../utils';\nimport type { createProxyAgentIfNeeded } from '../proxy';\nimport {\n type OpenAIRequestContext,\n wrapOpenAICompatibleFetch,\n} from './openai-request-context';\n\nconst createAndWrapClient = async ({\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n createOpenAIClient,\n effectiveTimeoutMs,\n proxyAgent,\n executionId,\n openAIRequestContext,\n}: {\n openaiBaseURL: IModelConfig['openaiBaseURL'];\n openaiApiKey: IModelConfig['openaiApiKey'];\n openaiExtraConfig: IModelConfig['openaiExtraConfig'];\n createOpenAIClient: IModelConfig['createOpenAIClient'];\n effectiveTimeoutMs: number | null;\n proxyAgent: Awaited<ReturnType<typeof createProxyAgentIfNeeded>>;\n executionId: string;\n openAIRequestContext: OpenAIRequestContext;\n}): Promise<OpenAI> => {\n const warnClient = getDebug('ai:call', { console: true });\n\n const openAIOptions = {\n baseURL: openaiBaseURL,\n apiKey: openaiApiKey,\n // Use fetchOptions.dispatcher for fetch-based SDK instead of httpAgent\n // Note: Type assertion needed due to undici version mismatch between dependencies\n ...(proxyAgent ? { fetchOptions: { dispatcher: proxyAgent as any } } : {}),\n ...openaiExtraConfig,\n // Midscene exposes this setting through MIDSCENE_*_INIT_CONFIG_JSON, so\n // defaultHeaders is expected to be a plain JSON object rather than another\n // HeadersLike representation supported by the OpenAI SDK.\n defaultHeaders: {\n ...(openaiExtraConfig?.defaultHeaders as\n | Record<string, string>\n | undefined),\n // These Midscene-owned headers intentionally override user-supplied\n // headers with the same names.\n 'x-midscene-version': getVersion(),\n 'x-midscene-execution-id': executionId,\n },\n fetch: wrapOpenAICompatibleFetch(openAIRequestContext),\n // Midscene handles request retries in callGenerativeAI(), so disable SDK-level retries\n // to avoid duplicate attempts and duplicated backoff latency.\n maxRetries: 0,\n // Disabling the Midscene hard timeout leaves the SDK timeout at its\n // configured value or default; it does not disable SDK/network timeouts.\n ...(effectiveTimeoutMs !== null ? { timeout: effectiveTimeoutMs } : {}),\n dangerouslyAllowBrowser: true,\n };\n\n const baseOpenAI = new OpenAI(openAIOptions);\n\n let openai: OpenAI = baseOpenAI;\n\n // LangSmith wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGSMITH_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langsmith is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langsmith wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langsmithModule = 'langsmith/wrappers';\n const { wrapOpenAI } = await import(langsmithModule);\n openai = wrapOpenAI(openai);\n }\n\n // Langfuse wrapper\n if (\n openai &&\n globalConfigManager.getEnvConfigInBoolean(MIDSCENE_LANGFUSE_DEBUG)\n ) {\n if (ifInBrowser) {\n throw new Error('langfuse is not supported in browser');\n }\n warnClient('DEBUGGING MODE: langfuse wrapper enabled');\n // Use variable to prevent static analysis by bundlers\n const langfuseModule = '@langfuse/openai';\n const { observeOpenAI } = await import(langfuseModule);\n openai = observeOpenAI(openai);\n }\n\n if (createOpenAIClient) {\n const wrappedClient = await createOpenAIClient(baseOpenAI, openAIOptions);\n\n if (wrappedClient) {\n openai = wrappedClient as OpenAI;\n }\n }\n\n return openai;\n};\n\nexport async function createClient({\n modelConfig,\n proxyAgent,\n effectiveTimeoutMs,\n executionId,\n recordEvent,\n}: {\n modelConfig: IModelConfig;\n proxyAgent: Awaited<ReturnType<typeof createProxyAgentIfNeeded>>;\n effectiveTimeoutMs: number | null;\n executionId: string;\n recordEvent?: (event: Record<string, unknown>) => void;\n}): Promise<{\n openai: OpenAI;\n openAIRequestContext: OpenAIRequestContext;\n}> {\n const { openaiBaseURL, openaiApiKey, openaiExtraConfig, createOpenAIClient } =\n modelConfig;\n\n const openAIRequestContext: OpenAIRequestContext = {\n recordEvent,\n };\n\n const openai = await createAndWrapClient({\n openaiBaseURL,\n openaiApiKey,\n openaiExtraConfig,\n createOpenAIClient,\n effectiveTimeoutMs,\n proxyAgent,\n executionId,\n openAIRequestContext,\n });\n\n return {\n openai,\n openAIRequestContext,\n };\n}\n"],"names":["createAndWrapClient","openaiBaseURL","openaiApiKey","openaiExtraConfig","createOpenAIClient","effectiveTimeoutMs","proxyAgent","executionId","openAIRequestContext","warnClient","getDebug","openAIOptions","getVersion","wrapOpenAICompatibleFetch","baseOpenAI","OpenAI","openai","globalConfigManager","MIDSCENE_LANGSMITH_DEBUG","ifInBrowser","Error","langsmithModule","wrapOpenAI","MIDSCENE_LANGFUSE_DEBUG","langfuseModule","observeOpenAI","wrappedClient","createClient","modelConfig","recordEvent"],"mappings":";;;;;;AAgBA,MAAMA,sBAAsB,OAAO,EACjCC,aAAa,EACbC,YAAY,EACZC,iBAAiB,EACjBC,kBAAkB,EAClBC,kBAAkB,EAClBC,UAAU,EACVC,WAAW,EACXC,oBAAoB,EAUrB;IACC,MAAMC,aAAaC,SAAS,WAAW;QAAE,SAAS;IAAK;IAEvD,MAAMC,gBAAgB;QACpB,SAASV;QACT,QAAQC;QAGR,GAAII,aAAa;YAAE,cAAc;gBAAE,YAAYA;YAAkB;QAAE,IAAI,CAAC,CAAC;QACzE,GAAGH,iBAAiB;QAIpB,gBAAgB;YACd,GAAIA,mBAAmB,cAAc;YAKrC,sBAAsBS;YACtB,2BAA2BL;QAC7B;QACA,OAAOM,0BAA0BL;QAGjC,YAAY;QAGZ,GAAIH,AAAuB,SAAvBA,qBAA8B;YAAE,SAASA;QAAmB,IAAI,CAAC,CAAC;QACtE,yBAAyB;IAC3B;IAEA,MAAMS,aAAa,IAAIC,SAAOJ;IAE9B,IAAIK,SAAiBF;IAGrB,IACEE,UACAC,oBAAoB,qBAAqB,CAACC,2BAC1C;QACA,IAAIC,aACF,MAAM,IAAIC,MAAM;QAElBX,WAAW;QAEX,MAAMY,kBAAkB;QACxB,MAAM,EAAEC,UAAU,EAAE,GAAG,MAAM,MAAM,CAACD;QACpCL,SAASM,WAAWN;IACtB;IAGA,IACEA,UACAC,oBAAoB,qBAAqB,CAACM,0BAC1C;QACA,IAAIJ,aACF,MAAM,IAAIC,MAAM;QAElBX,WAAW;QAEX,MAAMe,iBAAiB;QACvB,MAAM,EAAEC,aAAa,EAAE,GAAG,MAAM,MAAM,CAACD;QACvCR,SAASS,cAAcT;IACzB;IAEA,IAAIZ,oBAAoB;QACtB,MAAMsB,gBAAgB,MAAMtB,mBAAmBU,YAAYH;QAE3D,IAAIe,eACFV,SAASU;IAEb;IAEA,OAAOV;AACT;AAEO,eAAeW,aAAa,EACjCC,WAAW,EACXtB,UAAU,EACVD,kBAAkB,EAClBE,WAAW,EACXsB,WAAW,EAOZ;IAIC,MAAM,EAAE5B,aAAa,EAAEC,YAAY,EAAEC,iBAAiB,EAAEC,kBAAkB,EAAE,GAC1EwB;IAEF,MAAMpB,uBAA6C;QACjDqB;IACF;IAEA,MAAMb,SAAS,MAAMhB,oBAAoB;QACvCC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;IACF;IAEA,OAAO;QACLQ;QACAR;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/openai/responses/responses.mjs","sources":["../../../../../../src/ai-model/service-caller/openai/responses/responses.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ResolveImageDetail } from '../../../model-adapter/types';\nimport type { ModelRequestConfigInput } from '../../../model-adapter/types';\nimport { createProxyAgentIfNeeded } from '../../proxy';\nimport type { ModelCallContext, OpenAIProtocolCallResult } from '../../types';\nimport { stringifyForDebug } from '../../utils';\nimport { callResponsesNonStreaming } from './non-stream';\nimport { callResponsesStream } from './stream';\nimport type { ResponsesCallOptions } from './types';\nimport { toResponsesInput } from './utils';\n\nexport async function prepareResponses({\n messages,\n modelRuntime,\n options,\n}: Pick<ModelCallContext, 'messages' | 'modelRuntime' | 'options'>) {\n const debugCall = getDebug('ai:call');\n const { config: modelConfig, adapter } = modelRuntime;\n const modelCallInput: ModelRequestConfigInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n responseFormat: modelConfig.responseFormat,\n },\n semanticRetryAttempt: options?.semanticRetryAttempt,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n expectedJsonObjectResponse: options?.expectedJsonObjectResponse,\n };\n const { config } = adapter.responses.buildResponsesParams(modelCallInput);\n debugCall(`adapter responses params: ${stringifyForDebug({ config })}`);\n const resolveImageDetail: ResolveImageDetail = ({ imageDetail }) =>\n adapter.resolveImageDetail({\n imageDetail,\n intent: modelConfig.intent,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n });\n const requestParams = { ...config, ...modelConfig.extraBody };\n if (requestParams.background === true) {\n throw new Error('Responses background mode is not supported');\n }\n const requestBodyParams: ResponsesCallOptions['requestBodyParams'] = {\n store: false,\n ...requestParams,\n model: modelConfig.modelName,\n input: toResponsesInput(messages, resolveImageDetail),\n };\n const proxyAgent = await createProxyAgentIfNeeded({\n socksProxy: modelConfig.socksProxy,\n httpProxy: modelConfig.httpProxy,\n });\n return {\n requestParams: requestBodyParams,\n proxyAgent,\n };\n}\n\nexport function callResponses(\n options: ResponsesCallOptions,\n stream: boolean,\n): Promise<OpenAIProtocolCallResult> {\n return stream\n ? callResponsesStream(options)\n : callResponsesNonStreaming(options);\n}\n"],"names":["prepareResponses","messages","modelRuntime","options","debugCall","getDebug","modelConfig","adapter","modelCallInput","config","stringifyForDebug","resolveImageDetail","imageDetail","requestParams","Error","requestBodyParams","toResponsesInput","proxyAgent","createProxyAgentIfNeeded","callResponses","stream","callResponsesStream","callResponsesNonStreaming"],"mappings":";;;;;;AAWO,eAAeA,iBAAiB,EACrCC,QAAQ,EACRC,YAAY,EACZC,OAAO,EACyD;IAChE,MAAMC,YAAYC,SAAS;IAC3B,MAAM,EAAE,QAAQC,WAAW,EAAEC,OAAO,EAAE,GAAGL;IACzC,MAAMM,iBAA0C;QAC9C,QAAQF,YAAY,MAAM;QAC1B,YAAY;YACV,aAAaA,YAAY,WAAW;YACpC,kBAAkBA,YAAY,gBAAgB;YAC9C,iBAAiBA,YAAY,eAAe;YAC5C,iBAAiBA,YAAY,eAAe;YAC5C,gBAAgBA,YAAY,cAAc;QAC5C;QACA,sBAAsBH,SAAS;QAC/B,6BAA6BA,SAAS;QACtC,4BAA4BA,SAAS;IACvC;IACA,MAAM,EAAEM,MAAM,EAAE,GAAGF,QAAQ,SAAS,CAAC,oBAAoB,CAACC;IAC1DJ,UAAU,CAAC,0BAA0B,EAAEM,kBAAkB;QAAED;IAAO,IAAI;IACtE,MAAME,qBAAyC,CAAC,EAAEC,WAAW,EAAE,GAC7DL,QAAQ,kBAAkB,CAAC;YACzBK;YACA,QAAQN,YAAY,MAAM;YAC1B,6BAA6BH,SAAS;QACxC;IACF,MAAMU,gBAAgB;QAAE,GAAGJ,MAAM;QAAE,GAAGH,YAAY,SAAS;IAAC;IAC5D,IAAIO,AAA6B,SAA7BA,cAAc,UAAU,EAC1B,MAAM,IAAIC,MAAM;IAElB,MAAMC,oBAA+D;QACnE,OAAO;QACP,GAAGF,aAAa;QAChB,OAAOP,YAAY,SAAS;QAC5B,OAAOU,iBAAiBf,UAAUU;IACpC;IACA,MAAMM,aAAa,MAAMC,yBAAyB;QAChD,YAAYZ,YAAY,UAAU;QAClC,WAAWA,YAAY,SAAS;IAClC;IACA,OAAO;QACL,eAAeS;QACfE;IACF;AACF;AAEO,SAASE,cACdhB,OAA6B,EAC7BiB,MAAe;IAEf,OAAOA,SACHC,oBAAoBlB,WACpBmB,0BAA0BnB;AAChC"}
1
+ {"version":3,"file":"ai-model/service-caller/openai/responses/responses.mjs","sources":["../../../../../../src/ai-model/service-caller/openai/responses/responses.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport type { ResolveImageDetail } from '../../../model-adapter/types';\nimport type { ModelRequestConfigInput } from '../../../model-adapter/types';\nimport { createProxyAgentIfNeeded } from '../../proxy';\nimport type {\n ModelCallContext,\n ModelCallMessages,\n OpenAIProtocolCallResult,\n} from '../../types';\nimport { stringifyForDebug } from '../../utils';\nimport { callResponsesNonStreaming } from './non-stream';\nimport { callResponsesStream } from './stream';\nimport type { ResponsesCallOptions } from './types';\nimport { toResponsesInput } from './utils';\n\nexport async function prepareResponses({\n messages,\n modelRuntime,\n options,\n}: Pick<ModelCallContext, 'modelRuntime' | 'options'> & {\n messages: ModelCallMessages;\n}) {\n const debugCall = getDebug('ai:call');\n const { config: modelConfig, adapter } = modelRuntime;\n const modelCallInput: ModelRequestConfigInput = {\n intent: modelConfig.intent,\n userConfig: {\n temperature: modelConfig.temperature,\n reasoningEnabled: modelConfig.reasoningEnabled,\n reasoningEffort: modelConfig.reasoningEffort,\n reasoningBudget: modelConfig.reasoningBudget,\n responseFormat: modelConfig.responseFormat,\n },\n semanticRetryAttempt: options?.semanticRetryAttempt,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n expectedJsonObjectResponse: options?.expectedJsonObjectResponse,\n };\n const { config } = adapter.responses.buildResponsesParams(modelCallInput);\n debugCall(`adapter responses params: ${stringifyForDebug({ config })}`);\n const resolveImageDetail: ResolveImageDetail = ({ imageDetail }) =>\n adapter.resolveImageDetail({\n imageDetail,\n intent: modelConfig.intent,\n requiresOriginalImageDetail: options?.requiresOriginalImageDetail,\n });\n const requestParams = { ...config, ...modelConfig.extraBody };\n if (requestParams.background === true) {\n throw new Error('Responses background mode is not supported');\n }\n const requestBodyParams: ResponsesCallOptions['requestBodyParams'] = {\n store: false,\n ...requestParams,\n model: modelConfig.modelName,\n input: toResponsesInput(messages, resolveImageDetail),\n };\n const proxyAgent = await createProxyAgentIfNeeded({\n socksProxy: modelConfig.socksProxy,\n httpProxy: modelConfig.httpProxy,\n });\n return {\n requestParams: requestBodyParams,\n proxyAgent,\n };\n}\n\nexport function callResponses(\n options: ResponsesCallOptions,\n stream: boolean,\n): Promise<OpenAIProtocolCallResult> {\n return stream\n ? callResponsesStream(options)\n : callResponsesNonStreaming(options);\n}\n"],"names":["prepareResponses","messages","modelRuntime","options","debugCall","getDebug","modelConfig","adapter","modelCallInput","config","stringifyForDebug","resolveImageDetail","imageDetail","requestParams","Error","requestBodyParams","toResponsesInput","proxyAgent","createProxyAgentIfNeeded","callResponses","stream","callResponsesStream","callResponsesNonStreaming"],"mappings":";;;;;;AAeO,eAAeA,iBAAiB,EACrCC,QAAQ,EACRC,YAAY,EACZC,OAAO,EAGR;IACC,MAAMC,YAAYC,SAAS;IAC3B,MAAM,EAAE,QAAQC,WAAW,EAAEC,OAAO,EAAE,GAAGL;IACzC,MAAMM,iBAA0C;QAC9C,QAAQF,YAAY,MAAM;QAC1B,YAAY;YACV,aAAaA,YAAY,WAAW;YACpC,kBAAkBA,YAAY,gBAAgB;YAC9C,iBAAiBA,YAAY,eAAe;YAC5C,iBAAiBA,YAAY,eAAe;YAC5C,gBAAgBA,YAAY,cAAc;QAC5C;QACA,sBAAsBH,SAAS;QAC/B,6BAA6BA,SAAS;QACtC,4BAA4BA,SAAS;IACvC;IACA,MAAM,EAAEM,MAAM,EAAE,GAAGF,QAAQ,SAAS,CAAC,oBAAoB,CAACC;IAC1DJ,UAAU,CAAC,0BAA0B,EAAEM,kBAAkB;QAAED;IAAO,IAAI;IACtE,MAAME,qBAAyC,CAAC,EAAEC,WAAW,EAAE,GAC7DL,QAAQ,kBAAkB,CAAC;YACzBK;YACA,QAAQN,YAAY,MAAM;YAC1B,6BAA6BH,SAAS;QACxC;IACF,MAAMU,gBAAgB;QAAE,GAAGJ,MAAM;QAAE,GAAGH,YAAY,SAAS;IAAC;IAC5D,IAAIO,AAA6B,SAA7BA,cAAc,UAAU,EAC1B,MAAM,IAAIC,MAAM;IAElB,MAAMC,oBAA+D;QACnE,OAAO;QACP,GAAGF,aAAa;QAChB,OAAOP,YAAY,SAAS;QAC5B,OAAOU,iBAAiBf,UAAUU;IACpC;IACA,MAAMM,aAAa,MAAMC,yBAAyB;QAChD,YAAYZ,YAAY,UAAU;QAClC,WAAWA,YAAY,SAAS;IAClC;IACA,OAAO;QACL,eAAeS;QACfE;IACF;AACF;AAEO,SAASE,cACdhB,OAA6B,EAC7BiB,MAAe;IAEf,OAAOA,SACHC,oBAAoBlB,WACpBmB,0BAA0BnB;AAChC"}
@@ -0,0 +1,69 @@
1
+ import { assert } from "@midscene/shared/utils";
2
+ import { systemOneResponseSchema } from "./schema.mjs";
3
+ async function callSystemOne(context, prepared) {
4
+ const start = Date.now();
5
+ context.recordEvent?.({
6
+ type: 'request',
7
+ request: {
8
+ url: prepared.url,
9
+ method: 'POST',
10
+ body: prepared.body
11
+ }
12
+ });
13
+ try {
14
+ const response = await fetch(prepared.url, {
15
+ method: 'POST',
16
+ headers: prepared.headers,
17
+ body: prepared.body,
18
+ signal: context.requestSignal,
19
+ ...prepared.dispatcher ? {
20
+ dispatcher: prepared.dispatcher
21
+ } : {}
22
+ });
23
+ const body = await response.text();
24
+ const http = {
25
+ status: response.status,
26
+ ok: response.ok,
27
+ body
28
+ };
29
+ context.recordEvent?.({
30
+ type: 'http-response',
31
+ http
32
+ });
33
+ if (!response.ok) throw new Error(`Jev request failed (${response.status}): ${body.slice(0, 4000)}`);
34
+ const result = systemOneResponseSchema.parse(JSON.parse(body));
35
+ for (const [name, question] of Object.entries(prepared.questions)){
36
+ assert(result.answers[name]?.type === question.type, `Missing or invalid Jev answer: ${name}`);
37
+ const answer = result.answers[name];
38
+ if ('choice' === question.type && 'choice' === answer.type) assert(Object.hasOwn(question.criteria, answer.choice), `Invalid Jev choice: ${name}`);
39
+ }
40
+ const input = result.usage?.input_tokens;
41
+ const output = result.usage?.output_tokens;
42
+ const final = {
43
+ content: body,
44
+ isStreamed: false,
45
+ rawUsage: null != input && null != output ? {
46
+ prompt_tokens: input,
47
+ completion_tokens: output,
48
+ total_tokens: input + output
49
+ } : void 0,
50
+ timeCost: Date.now() - start,
51
+ requestId: void 0,
52
+ responseModelName: result.model
53
+ };
54
+ context.recordEvent?.({
55
+ type: 'response',
56
+ final
57
+ });
58
+ return final;
59
+ } catch (error) {
60
+ context.recordEvent?.({
61
+ type: 'error',
62
+ error: error instanceof Error ? error.message : String(error)
63
+ });
64
+ throw error;
65
+ }
66
+ }
67
+ export { callSystemOne };
68
+
69
+ //# sourceMappingURL=call-system-one.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-model/service-caller/system-one/call-system-one.mjs","sources":["../../../../../src/ai-model/service-caller/system-one/call-system-one.ts"],"sourcesContent":["import { assert } from '@midscene/shared/utils';\nimport type { ModelCallContext, ModelCallResult } from '../types';\nimport type { prepareSystemOne } from './prepare-system-one';\nimport { systemOneResponseSchema } from './schema';\n\nexport async function callSystemOne(\n context: ModelCallContext,\n prepared: Awaited<ReturnType<typeof prepareSystemOne>>,\n): Promise<ModelCallResult> {\n const start = Date.now();\n context.recordEvent?.({\n type: 'request',\n request: { url: prepared.url, method: 'POST', body: prepared.body },\n });\n try {\n const response = await fetch(prepared.url, {\n method: 'POST',\n headers: prepared.headers,\n body: prepared.body,\n signal: context.requestSignal,\n ...(prepared.dispatcher ? { dispatcher: prepared.dispatcher } : {}),\n });\n const body = await response.text();\n const http = { status: response.status, ok: response.ok, body };\n context.recordEvent?.({ type: 'http-response', http });\n if (!response.ok) {\n throw new Error(\n `Jev request failed (${response.status}): ${body.slice(0, 4000)}`,\n );\n }\n const result = systemOneResponseSchema.parse(JSON.parse(body));\n for (const [name, question] of Object.entries(prepared.questions)) {\n assert(\n result.answers[name]?.type === question.type,\n `Missing or invalid Jev answer: ${name}`,\n );\n const answer = result.answers[name];\n if (question.type === 'choice' && answer.type === 'choice') {\n assert(\n Object.hasOwn(question.criteria, answer.choice),\n `Invalid Jev choice: ${name}`,\n );\n }\n }\n const input = result.usage?.input_tokens;\n const output = result.usage?.output_tokens;\n const final: ModelCallResult = {\n content: body,\n isStreamed: false,\n rawUsage:\n input != null && output != null\n ? {\n prompt_tokens: input,\n completion_tokens: output,\n total_tokens: input + output,\n }\n : undefined,\n timeCost: Date.now() - start,\n // TypeSafe and OpenRouter use different ID field names; defer compatibility handling.\n requestId: undefined,\n responseModelName: result.model,\n };\n context.recordEvent?.({ type: 'response', final });\n return final;\n } catch (error) {\n context.recordEvent?.({\n type: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n"],"names":["callSystemOne","context","prepared","start","Date","response","fetch","body","http","Error","result","systemOneResponseSchema","JSON","name","question","Object","assert","answer","input","output","final","undefined","error","String"],"mappings":";;AAKO,eAAeA,cACpBC,OAAyB,EACzBC,QAAsD;IAEtD,MAAMC,QAAQC,KAAK,GAAG;IACtBH,QAAQ,WAAW,GAAG;QACpB,MAAM;QACN,SAAS;YAAE,KAAKC,SAAS,GAAG;YAAE,QAAQ;YAAQ,MAAMA,SAAS,IAAI;QAAC;IACpE;IACA,IAAI;QACF,MAAMG,WAAW,MAAMC,MAAMJ,SAAS,GAAG,EAAE;YACzC,QAAQ;YACR,SAASA,SAAS,OAAO;YACzB,MAAMA,SAAS,IAAI;YACnB,QAAQD,QAAQ,aAAa;YAC7B,GAAIC,SAAS,UAAU,GAAG;gBAAE,YAAYA,SAAS,UAAU;YAAC,IAAI,CAAC,CAAC;QACpE;QACA,MAAMK,OAAO,MAAMF,SAAS,IAAI;QAChC,MAAMG,OAAO;YAAE,QAAQH,SAAS,MAAM;YAAE,IAAIA,SAAS,EAAE;YAAEE;QAAK;QAC9DN,QAAQ,WAAW,GAAG;YAAE,MAAM;YAAiBO;QAAK;QACpD,IAAI,CAACH,SAAS,EAAE,EACd,MAAM,IAAII,MACR,CAAC,oBAAoB,EAAEJ,SAAS,MAAM,CAAC,GAAG,EAAEE,KAAK,KAAK,CAAC,GAAG,OAAO;QAGrE,MAAMG,SAASC,wBAAwB,KAAK,CAACC,KAAK,KAAK,CAACL;QACxD,KAAK,MAAM,CAACM,MAAMC,SAAS,IAAIC,OAAO,OAAO,CAACb,SAAS,SAAS,EAAG;YACjEc,OACEN,OAAO,OAAO,CAACG,KAAK,EAAE,SAASC,SAAS,IAAI,EAC5C,CAAC,+BAA+B,EAAED,MAAM;YAE1C,MAAMI,SAASP,OAAO,OAAO,CAACG,KAAK;YACnC,IAAIC,AAAkB,aAAlBA,SAAS,IAAI,IAAiBG,AAAgB,aAAhBA,OAAO,IAAI,EAC3CD,OACED,OAAO,MAAM,CAACD,SAAS,QAAQ,EAAEG,OAAO,MAAM,GAC9C,CAAC,oBAAoB,EAAEJ,MAAM;QAGnC;QACA,MAAMK,QAAQR,OAAO,KAAK,EAAE;QAC5B,MAAMS,SAAST,OAAO,KAAK,EAAE;QAC7B,MAAMU,QAAyB;YAC7B,SAASb;YACT,YAAY;YACZ,UACEW,AAAS,QAATA,SAAiBC,AAAU,QAAVA,SACb;gBACE,eAAeD;gBACf,mBAAmBC;gBACnB,cAAcD,QAAQC;YACxB,IACAE;YACN,UAAUjB,KAAK,GAAG,KAAKD;YAEvB,WAAWkB;YACX,mBAAmBX,OAAO,KAAK;QACjC;QACAT,QAAQ,WAAW,GAAG;YAAE,MAAM;YAAYmB;QAAM;QAChD,OAAOA;IACT,EAAE,OAAOE,OAAO;QACdrB,QAAQ,WAAW,GAAG;YACpB,MAAM;YACN,OAAOqB,iBAAiBb,QAAQa,MAAM,OAAO,GAAGC,OAAOD;QACzD;QACA,MAAMA;IACR;AACF"}
@@ -0,0 +1,3 @@
1
+ import { callSystemOne } from "./call-system-one.mjs";
2
+ import { prepareSystemOne } from "./prepare-system-one.mjs";
3
+ export { callSystemOne, prepareSystemOne };
@@ -0,0 +1,44 @@
1
+ import { assert } from "@midscene/shared/utils";
2
+ import { createProxyAgentIfNeeded } from "../proxy/index.mjs";
3
+ import { encodeSystemOneImages } from "./utils.mjs";
4
+ async function prepareSystemOne(config, request) {
5
+ assert(config.openaiBaseURL, 'Jev requires MIDSCENE_*_MODEL_BASE_URL');
6
+ assert(config.openaiApiKey, 'Jev requires MIDSCENE_*_MODEL_API_KEY');
7
+ assert(!config.protocol || 'openai-chat' === config.protocol, 'Jev uses System One, not the Responses API');
8
+ const base = config.openaiBaseURL.replace(/\/+$/, '');
9
+ const url = `${base}/systemone`;
10
+ const isOpenRouter = 'openrouter.ai' === new URL(base).hostname;
11
+ const { imageState, assets } = encodeSystemOneImages(request.images, isOpenRouter);
12
+ const body = {
13
+ ...config.extraBody,
14
+ model: config.modelName,
15
+ state: {
16
+ ...request.state,
17
+ ...imageState
18
+ },
19
+ questions: request.questions,
20
+ ...!isOpenRouter && Object.keys(assets).length ? {
21
+ assets
22
+ } : {}
23
+ };
24
+ const serializedBody = JSON.stringify(body);
25
+ assert(new TextEncoder().encode(serializedBody).length <= 33554432, 'Jev request exceeds the 32 MiB body limit');
26
+ return {
27
+ url,
28
+ body: serializedBody,
29
+ questions: request.questions,
30
+ headers: {
31
+ ...config.openaiExtraConfig?.defaultHeaders,
32
+ Authorization: `Bearer ${config.openaiApiKey}`,
33
+ 'Content-Type': 'application/json',
34
+ 'TypeSafe-Danger-Zone-Images': 'true'
35
+ },
36
+ dispatcher: await createProxyAgentIfNeeded({
37
+ socksProxy: config.socksProxy,
38
+ httpProxy: config.httpProxy
39
+ })
40
+ };
41
+ }
42
+ export { prepareSystemOne };
43
+
44
+ //# sourceMappingURL=prepare-system-one.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-model/service-caller/system-one/prepare-system-one.mjs","sources":["../../../../../src/ai-model/service-caller/system-one/prepare-system-one.ts"],"sourcesContent":["import type { IModelConfig } from '@midscene/shared/env';\nimport { assert } from '@midscene/shared/utils';\nimport { createProxyAgentIfNeeded } from '../proxy';\nimport type { SystemOneRequest } from './schema';\nimport { encodeSystemOneImages } from './utils';\n\nexport async function prepareSystemOne(\n config: IModelConfig,\n request: SystemOneRequest,\n) {\n assert(config.openaiBaseURL, 'Jev requires MIDSCENE_*_MODEL_BASE_URL');\n assert(config.openaiApiKey, 'Jev requires MIDSCENE_*_MODEL_API_KEY');\n assert(\n !config.protocol || config.protocol === 'openai-chat',\n 'Jev uses System One, not the Responses API',\n );\n const base = config.openaiBaseURL.replace(/\\/+$/, '');\n const url = `${base}/systemone`;\n const isOpenRouter = new URL(base).hostname === 'openrouter.ai';\n const { imageState, assets } = encodeSystemOneImages(\n request.images,\n isOpenRouter,\n );\n const body = {\n ...config.extraBody,\n model: config.modelName,\n state: { ...request.state, ...imageState },\n questions: request.questions,\n ...(!isOpenRouter && Object.keys(assets).length ? { assets } : {}),\n };\n const serializedBody = JSON.stringify(body);\n assert(\n new TextEncoder().encode(serializedBody).length <= 32 * 1024 * 1024,\n 'Jev request exceeds the 32 MiB body limit',\n );\n return {\n url,\n body: serializedBody,\n questions: request.questions,\n headers: {\n ...(config.openaiExtraConfig?.defaultHeaders as\n | Record<string, string>\n | undefined),\n Authorization: `Bearer ${config.openaiApiKey}`,\n 'Content-Type': 'application/json',\n 'TypeSafe-Danger-Zone-Images': 'true',\n },\n dispatcher: await createProxyAgentIfNeeded({\n socksProxy: config.socksProxy,\n httpProxy: config.httpProxy,\n }),\n };\n}\n"],"names":["prepareSystemOne","config","request","assert","base","url","isOpenRouter","URL","imageState","assets","encodeSystemOneImages","body","Object","serializedBody","JSON","TextEncoder","createProxyAgentIfNeeded"],"mappings":";;;AAMO,eAAeA,iBACpBC,MAAoB,EACpBC,OAAyB;IAEzBC,OAAOF,OAAO,aAAa,EAAE;IAC7BE,OAAOF,OAAO,YAAY,EAAE;IAC5BE,OACE,CAACF,OAAO,QAAQ,IAAIA,AAAoB,kBAApBA,OAAO,QAAQ,EACnC;IAEF,MAAMG,OAAOH,OAAO,aAAa,CAAC,OAAO,CAAC,QAAQ;IAClD,MAAMI,MAAM,GAAGD,KAAK,UAAU,CAAC;IAC/B,MAAME,eAAe,AAA2B,oBAA3B,IAAIC,IAAIH,MAAM,QAAQ;IAC3C,MAAM,EAAEI,UAAU,EAAEC,MAAM,EAAE,GAAGC,sBAC7BR,QAAQ,MAAM,EACdI;IAEF,MAAMK,OAAO;QACX,GAAGV,OAAO,SAAS;QACnB,OAAOA,OAAO,SAAS;QACvB,OAAO;YAAE,GAAGC,QAAQ,KAAK;YAAE,GAAGM,UAAU;QAAC;QACzC,WAAWN,QAAQ,SAAS;QAC5B,GAAI,CAACI,gBAAgBM,OAAO,IAAI,CAACH,QAAQ,MAAM,GAAG;YAAEA;QAAO,IAAI,CAAC,CAAC;IACnE;IACA,MAAMI,iBAAiBC,KAAK,SAAS,CAACH;IACtCR,OACE,IAAIY,cAAc,MAAM,CAACF,gBAAgB,MAAM,IAAI,UACnD;IAEF,OAAO;QACLR;QACA,MAAMQ;QACN,WAAWX,QAAQ,SAAS;QAC5B,SAAS;YACP,GAAID,OAAO,iBAAiB,EAAE,cAAc;YAG5C,eAAe,CAAC,OAAO,EAAEA,OAAO,YAAY,EAAE;YAC9C,gBAAgB;YAChB,+BAA+B;QACjC;QACA,YAAY,MAAMe,yBAAyB;YACzC,YAAYf,OAAO,UAAU;YAC7B,WAAWA,OAAO,SAAS;QAC7B;IACF;AACF"}
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ const probability = z.number().min(0).max(1);
3
+ const systemOneAnswerSchema = z.discriminatedUnion('type', [
4
+ z.object({
5
+ type: z.literal('noul'),
6
+ noul: probability
7
+ }),
8
+ z.object({
9
+ type: z.literal('choice'),
10
+ choice: z.string()
11
+ }),
12
+ z.object({
13
+ type: z.literal('box'),
14
+ box: z.object({
15
+ left: probability,
16
+ right: probability,
17
+ top: probability,
18
+ bottom: probability
19
+ }).refine((box)=>box.left < box.right && box.top < box.bottom, 'Invalid box edges')
20
+ })
21
+ ]);
22
+ const systemOneResponseSchema = z.object({
23
+ model: z.string().optional(),
24
+ answers: z.record(systemOneAnswerSchema),
25
+ usage: z.object({
26
+ input_tokens: z.number().nonnegative().nullable().optional(),
27
+ output_tokens: z.number().nonnegative().nullable().optional()
28
+ }).optional()
29
+ });
30
+ export { systemOneAnswerSchema, systemOneResponseSchema };
31
+
32
+ //# sourceMappingURL=schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-model/service-caller/system-one/schema.mjs","sources":["../../../../../src/ai-model/service-caller/system-one/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport interface SystemOneRequest {\n state: Record<string, unknown>;\n images?: Record<string, string>;\n questions: Record<\n string,\n | { type: 'noul' | 'box'; instructions: unknown }\n | {\n type: 'choice';\n instructions: unknown;\n criteria: Record<string, string>;\n }\n >;\n}\n\nconst probability = z.number().min(0).max(1);\nexport const systemOneAnswerSchema = z.discriminatedUnion('type', [\n z.object({ type: z.literal('noul'), noul: probability }),\n z.object({ type: z.literal('choice'), choice: z.string() }),\n z.object({\n type: z.literal('box'),\n box: z\n .object({\n left: probability,\n right: probability,\n top: probability,\n bottom: probability,\n })\n .refine(\n (box) => box.left < box.right && box.top < box.bottom,\n 'Invalid box edges',\n ),\n }),\n]);\nexport const systemOneResponseSchema = z.object({\n model: z.string().optional(),\n answers: z.record(systemOneAnswerSchema),\n usage: z\n .object({\n input_tokens: z.number().nonnegative().nullable().optional(),\n output_tokens: z.number().nonnegative().nullable().optional(),\n })\n .optional(),\n});\n"],"names":["probability","z","systemOneAnswerSchema","box","systemOneResponseSchema"],"mappings":";AAgBA,MAAMA,cAAcC,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACnC,MAAMC,wBAAwBD,EAAE,kBAAkB,CAAC,QAAQ;IAChEA,EAAE,MAAM,CAAC;QAAE,MAAMA,EAAE,OAAO,CAAC;QAAS,MAAMD;IAAY;IACtDC,EAAE,MAAM,CAAC;QAAE,MAAMA,EAAE,OAAO,CAAC;QAAW,QAAQA,EAAE,MAAM;IAAG;IACzDA,EAAE,MAAM,CAAC;QACP,MAAMA,EAAE,OAAO,CAAC;QAChB,KAAKA,EAAAA,MACI,CAAC;YACN,MAAMD;YACN,OAAOA;YACP,KAAKA;YACL,QAAQA;QACV,GACC,MAAM,CACL,CAACG,MAAQA,IAAI,IAAI,GAAGA,IAAI,KAAK,IAAIA,IAAI,GAAG,GAAGA,IAAI,MAAM,EACrD;IAEN;CACD;AACM,MAAMC,0BAA0BH,EAAE,MAAM,CAAC;IAC9C,OAAOA,EAAE,MAAM,GAAG,QAAQ;IAC1B,SAASA,EAAE,MAAM,CAACC;IAClB,OAAOD,EAAAA,MACE,CAAC;QACN,cAAcA,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ;QAC1D,eAAeA,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ;IAC7D,GACC,QAAQ;AACb"}
@@ -0,0 +1,34 @@
1
+ import { assert, uuid } from "@midscene/shared/utils";
2
+ function encodeSystemOneImages(images, isOpenRouter) {
3
+ const assets = {};
4
+ const imageState = Object.fromEntries(Object.entries(images ?? {}).map(([name, dataURL])=>{
5
+ if (isOpenRouter) return [
6
+ name,
7
+ {
8
+ type: 'image_url',
9
+ image_url: {
10
+ url: dataURL
11
+ }
12
+ }
13
+ ];
14
+ const reference = uuid();
15
+ const match = /^data:image\/(png|jpe?g);base64,(.+)$/.exec(dataURL);
16
+ assert(match, 'System One images must be prepared PNG or JPEG data URLs');
17
+ assets[reference] = {
18
+ type: 'image',
19
+ format: 'png' === match[1] ? 'png' : 'jpg',
20
+ data_base64: match[2]
21
+ };
22
+ return [
23
+ name,
24
+ reference
25
+ ];
26
+ }));
27
+ return {
28
+ imageState,
29
+ assets
30
+ };
31
+ }
32
+ export { encodeSystemOneImages };
33
+
34
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-model/service-caller/system-one/utils.mjs","sources":["../../../../../src/ai-model/service-caller/system-one/utils.ts"],"sourcesContent":["import { assert, uuid } from '@midscene/shared/utils';\nimport type { SystemOneRequest } from './schema';\n\nexport function encodeSystemOneImages(\n images: SystemOneRequest['images'],\n isOpenRouter: boolean,\n) {\n const assets: Record<string, unknown> = {};\n const imageState = Object.fromEntries(\n Object.entries(images ?? {}).map(([name, dataURL]) => {\n if (isOpenRouter) {\n return [name, { type: 'image_url', image_url: { url: dataURL } }];\n }\n const reference = uuid();\n const match = /^data:image\\/(png|jpe?g);base64,(.+)$/.exec(dataURL);\n assert(match, 'System One images must be prepared PNG or JPEG data URLs');\n assets[reference] = {\n type: 'image',\n format: match[1] === 'png' ? 'png' : 'jpg',\n data_base64: match[2],\n };\n return [name, reference];\n }),\n );\n return { imageState, assets };\n}\n"],"names":["encodeSystemOneImages","images","isOpenRouter","assets","imageState","Object","name","dataURL","reference","uuid","match","assert"],"mappings":";AAGO,SAASA,sBACdC,MAAkC,EAClCC,YAAqB;IAErB,MAAMC,SAAkC,CAAC;IACzC,MAAMC,aAAaC,OAAO,WAAW,CACnCA,OAAO,OAAO,CAACJ,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAACK,MAAMC,QAAQ;QAC/C,IAAIL,cACF,OAAO;YAACI;YAAM;gBAAE,MAAM;gBAAa,WAAW;oBAAE,KAAKC;gBAAQ;YAAE;SAAE;QAEnE,MAAMC,YAAYC;QAClB,MAAMC,QAAQ,wCAAwC,IAAI,CAACH;QAC3DI,OAAOD,OAAO;QACdP,MAAM,CAACK,UAAU,GAAG;YAClB,MAAM;YACN,QAAQE,AAAa,UAAbA,KAAK,CAAC,EAAE,GAAa,QAAQ;YACrC,aAAaA,KAAK,CAAC,EAAE;QACvB;QACA,OAAO;YAACJ;YAAME;SAAU;IAC1B;IAEF,OAAO;QAAEJ;QAAYD;IAAO;AAC9B"}
@@ -53,12 +53,12 @@ function appendAIRequestFailureSummary(error, attemptErrors, maxAttempts) {
53
53
  error.message = `${error.message}\nPrevious AI call attempt errors:\n${details}`;
54
54
  return error;
55
55
  }
56
- const buildUsageInfo = ({ apiProtocol, stream, usageData, requestId, timeCost, totalTimeCost, retryCount, modelName, modelDescription, responseModelName, slot, internalCallId })=>{
56
+ const buildUsageInfo = ({ requestKind, stream, usageData, requestId, timeCost, totalTimeCost, retryCount, modelName, modelDescription, responseModelName, slot, internalCallId })=>{
57
57
  if (!usageData) return;
58
58
  const cachedInputTokens = usageData?.prompt_tokens_details?.cached_tokens;
59
59
  return {
60
60
  ...usageData,
61
- api_protocol: apiProtocol,
61
+ request_kind: requestKind,
62
62
  stream,
63
63
  prompt_tokens: usageData.prompt_tokens ?? 0,
64
64
  completion_tokens: usageData.completion_tokens ?? 0,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/service-caller/utils.mjs","sources":["../../../../src/ai-model/service-caller/utils.ts"],"sourcesContent":["import type { RawAssistantOutput } from '@/types';\nimport type { AIUsageInfo } from '@/types';\nimport type OpenAI from 'openai';\nimport type { ModelRuntime } from '../models';\n\n// Error class that preserves usage and rawResponse when AI call parsing fails\nexport class AIResponseParseError extends Error {\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse: string;\n rawAssistantOutput?: RawAssistantOutput;\n reasoningContent?: string;\n\n constructor(\n message: string,\n rawResponse: string,\n usage?: AIUsageInfo,\n rawAssistantOutput?: RawAssistantOutput,\n reasoningContent?: string,\n ) {\n super(message);\n this.name = 'AIResponseParseError';\n this.rawResponse = rawResponse;\n this.usage = usage;\n this.rawAssistantOutput = rawAssistantOutput;\n this.reasoningContent = reasoningContent;\n }\n}\n\n/**\n * Internal field name stamped onto every AIUsageInfo shaped by callAI().\n * Used for cross-path dedup when the provider does not return a request_id.\n */\nexport const INTERNAL_CALL_ID_FIELD = '_midscene_call_id';\n\nlet internalCallIdCounter = 0;\nexport function nextInternalCallId(): string {\n internalCallIdCounter += 1;\n return `call_${internalCallIdCounter}`;\n}\n\nexport function stringifyForDebug(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch (_error) {\n return String(value);\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nexport function normalizeRetryCount(retryCount: unknown): number {\n if (typeof retryCount !== 'number' || !Number.isFinite(retryCount)) {\n return 1;\n }\n\n return Math.max(0, Math.floor(retryCount));\n}\n\nexport function appendAIRequestFailureSummary<T extends Error>(\n error: T,\n attemptErrors: Array<{ attempt: number; error: unknown }>,\n maxAttempts: number,\n): T {\n const failedAttempts = attemptErrors.length;\n const retries = Math.max(0, failedAttempts - 1);\n const retryLabel = retries === 1 ? 'retry' : 'retries';\n const originalMessage = error.message;\n const previousAttemptErrors = attemptErrors.slice(0, -1);\n\n error.message = `AI model request failed after ${retries} ${retryLabel} (${failedAttempts}/${maxAttempts} attempts). Last error: ${originalMessage}`;\n\n if (previousAttemptErrors.length === 0) {\n return error;\n }\n\n const details = previousAttemptErrors\n .map(\n ({ attempt, error }) => `Attempt ${attempt}: ${getErrorMessage(error)}`,\n )\n .join('\\n');\n\n error.message = `${error.message}\\nPrevious AI call attempt errors:\\n${details}`;\n return error;\n}\n\nexport const buildUsageInfo = ({\n apiProtocol,\n stream,\n usageData,\n requestId,\n timeCost,\n totalTimeCost,\n retryCount,\n modelName,\n modelDescription,\n responseModelName,\n slot,\n internalCallId,\n}: {\n apiProtocol: NonNullable<AIUsageInfo['api_protocol']>;\n stream: boolean;\n usageData?: OpenAI.CompletionUsage;\n requestId?: string | null;\n timeCost?: number;\n totalTimeCost: number;\n retryCount: number;\n modelName: string;\n modelDescription: string;\n responseModelName?: string;\n slot: ModelRuntime['config']['slot'];\n internalCallId: string;\n}): AIUsageInfo | undefined => {\n if (!usageData) return undefined;\n\n const cachedInputTokens = (\n usageData as { prompt_tokens_details?: { cached_tokens?: number } }\n )?.prompt_tokens_details?.cached_tokens;\n\n return {\n ...usageData,\n api_protocol: apiProtocol,\n stream,\n prompt_tokens: usageData.prompt_tokens ?? 0,\n completion_tokens: usageData.completion_tokens ?? 0,\n total_tokens: usageData.total_tokens ?? 0,\n cached_input: cachedInputTokens ?? 0,\n time_cost: timeCost ?? 0,\n total_time_cost: totalTimeCost,\n retry_count: retryCount,\n model_name: modelName,\n model_description: modelDescription,\n response_model_name: responseModelName,\n slot,\n // Left undefined at the raw call layer. The agent's onUsage callback\n // fills it from modelConfig.slot for metrics collection, and task\n // layers use withUsageIntent() to stamp a more specific semantic\n // intent (e.g. 'planning', 'insight') when attaching usage to tasks.\n intent: undefined,\n request_id: requestId ?? undefined,\n // Internal stable ID for cross-path dedup when request_id is absent.\n [INTERNAL_CALL_ID_FIELD]: internalCallId,\n } satisfies AIUsageInfo;\n};\n\nexport const hasUsableText = (\n value: string | null | undefined,\n): value is string => typeof value === 'string' && value.trim().length > 0;\n"],"names":["AIResponseParseError","Error","message","rawResponse","usage","rawAssistantOutput","reasoningContent","INTERNAL_CALL_ID_FIELD","internalCallIdCounter","nextInternalCallId","stringifyForDebug","value","JSON","_error","String","getErrorMessage","error","toError","normalizeRetryCount","retryCount","Number","Math","appendAIRequestFailureSummary","attemptErrors","maxAttempts","failedAttempts","retries","retryLabel","originalMessage","previousAttemptErrors","details","attempt","buildUsageInfo","apiProtocol","stream","usageData","requestId","timeCost","totalTimeCost","modelName","modelDescription","responseModelName","slot","internalCallId","cachedInputTokens","undefined","hasUsableText"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/service-caller/utils.mjs","sources":["../../../../src/ai-model/service-caller/utils.ts"],"sourcesContent":["import type { RawAssistantOutput } from '@/types';\nimport type { AIUsageInfo } from '@/types';\nimport type OpenAI from 'openai';\nimport type { ModelRuntime } from '../models';\n\n// Error class that preserves usage and rawResponse when AI call parsing fails\nexport class AIResponseParseError extends Error {\n usage?: AIUsageInfo;\n /**\n * Adapter-extracted content used by Midscene for parsing. This is not the\n * full provider response or choices[0].message.\n */\n rawResponse: string;\n rawAssistantOutput?: RawAssistantOutput;\n reasoningContent?: string;\n\n constructor(\n message: string,\n rawResponse: string,\n usage?: AIUsageInfo,\n rawAssistantOutput?: RawAssistantOutput,\n reasoningContent?: string,\n ) {\n super(message);\n this.name = 'AIResponseParseError';\n this.rawResponse = rawResponse;\n this.usage = usage;\n this.rawAssistantOutput = rawAssistantOutput;\n this.reasoningContent = reasoningContent;\n }\n}\n\n/**\n * Internal field name stamped onto AIUsageInfo by the shared model call pipeline.\n * Used for cross-path dedup when the provider does not return a request_id.\n */\nexport const INTERNAL_CALL_ID_FIELD = '_midscene_call_id';\n\nlet internalCallIdCounter = 0;\nexport function nextInternalCallId(): string {\n internalCallIdCounter += 1;\n return `call_${internalCallIdCounter}`;\n}\n\nexport function stringifyForDebug(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch (_error) {\n return String(value);\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nexport function normalizeRetryCount(retryCount: unknown): number {\n if (typeof retryCount !== 'number' || !Number.isFinite(retryCount)) {\n return 1;\n }\n\n return Math.max(0, Math.floor(retryCount));\n}\n\nexport function appendAIRequestFailureSummary<T extends Error>(\n error: T,\n attemptErrors: Array<{ attempt: number; error: unknown }>,\n maxAttempts: number,\n): T {\n const failedAttempts = attemptErrors.length;\n const retries = Math.max(0, failedAttempts - 1);\n const retryLabel = retries === 1 ? 'retry' : 'retries';\n const originalMessage = error.message;\n const previousAttemptErrors = attemptErrors.slice(0, -1);\n\n error.message = `AI model request failed after ${retries} ${retryLabel} (${failedAttempts}/${maxAttempts} attempts). Last error: ${originalMessage}`;\n\n if (previousAttemptErrors.length === 0) {\n return error;\n }\n\n const details = previousAttemptErrors\n .map(\n ({ attempt, error }) => `Attempt ${attempt}: ${getErrorMessage(error)}`,\n )\n .join('\\n');\n\n error.message = `${error.message}\\nPrevious AI call attempt errors:\\n${details}`;\n return error;\n}\n\nexport const buildUsageInfo = ({\n requestKind,\n stream,\n usageData,\n requestId,\n timeCost,\n totalTimeCost,\n retryCount,\n modelName,\n modelDescription,\n responseModelName,\n slot,\n internalCallId,\n}: {\n requestKind: NonNullable<AIUsageInfo['request_kind']>;\n stream: boolean;\n usageData?: OpenAI.CompletionUsage;\n requestId?: string | null;\n timeCost?: number;\n totalTimeCost: number;\n retryCount: number;\n modelName: string;\n modelDescription: string;\n responseModelName?: string;\n slot: ModelRuntime['config']['slot'];\n internalCallId: string;\n}): AIUsageInfo | undefined => {\n if (!usageData) return undefined;\n\n const cachedInputTokens = (\n usageData as { prompt_tokens_details?: { cached_tokens?: number } }\n )?.prompt_tokens_details?.cached_tokens;\n\n return {\n ...usageData,\n request_kind: requestKind,\n stream,\n prompt_tokens: usageData.prompt_tokens ?? 0,\n completion_tokens: usageData.completion_tokens ?? 0,\n total_tokens: usageData.total_tokens ?? 0,\n cached_input: cachedInputTokens ?? 0,\n time_cost: timeCost ?? 0,\n total_time_cost: totalTimeCost,\n retry_count: retryCount,\n model_name: modelName,\n model_description: modelDescription,\n response_model_name: responseModelName,\n slot,\n // Left undefined at the raw call layer. The agent's onUsage callback\n // fills it from modelConfig.slot for metrics collection, and task\n // layers use withUsageIntent() to stamp a more specific semantic\n // intent (e.g. 'planning', 'insight') when attaching usage to tasks.\n intent: undefined,\n request_id: requestId ?? undefined,\n // Internal stable ID for cross-path dedup when request_id is absent.\n [INTERNAL_CALL_ID_FIELD]: internalCallId,\n } satisfies AIUsageInfo;\n};\n\nexport const hasUsableText = (\n value: string | null | undefined,\n): value is string => typeof value === 'string' && value.trim().length > 0;\n"],"names":["AIResponseParseError","Error","message","rawResponse","usage","rawAssistantOutput","reasoningContent","INTERNAL_CALL_ID_FIELD","internalCallIdCounter","nextInternalCallId","stringifyForDebug","value","JSON","_error","String","getErrorMessage","error","toError","normalizeRetryCount","retryCount","Number","Math","appendAIRequestFailureSummary","attemptErrors","maxAttempts","failedAttempts","retries","retryLabel","originalMessage","previousAttemptErrors","details","attempt","buildUsageInfo","requestKind","stream","usageData","requestId","timeCost","totalTimeCost","modelName","modelDescription","responseModelName","slot","internalCallId","cachedInputTokens","undefined","hasUsableText"],"mappings":"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"}
@@ -6,6 +6,9 @@ import { assertLocateResultCoordinateRangeAndOrder, assertLocateResultStructure
6
6
  function resolveLocateResultCoordinates(coordinates) {
7
7
  if (void 0 !== coordinates.normalizedBy && coordinates.normalizedBy <= 0) throw new Error(`locate result coordinates normalizedBy must be positive: ${coordinates.normalizedBy}`);
8
8
  return {
9
+ ...'bbox' === coordinates.shape ? {
10
+ boundsType: coordinates.boundsType ?? 'inclusive'
11
+ } : {},
9
12
  shape: coordinates.shape,
10
13
  order: coordinates.order ?? 'xy',
11
14
  normalizedBy: coordinates.normalizedBy,
@@ -24,11 +27,12 @@ function createLocateResultCodec(config) {
24
27
  const result = parseRawLocateValue(rawResult);
25
28
  const { preparedSize, contentSize = preparedSize } = context;
26
29
  assertLocateResultStructure(result);
27
- assertLocateResultCoordinateRangeAndOrder(result, preparedSize.width - 1, preparedSize.height - 1);
30
+ const edgeBounds = isBboxLocateResultValue(result) && 'edges' === result.coordinatesMeta.boundsType;
31
+ assertLocateResultCoordinateRangeAndOrder(result, preparedSize.width - (edgeBounds ? 0 : 1), preparedSize.height - (edgeBounds ? 0 : 1));
28
32
  const center = clampPixelPointToSize(mapLocateResultToPixelPoint(result, preparedSize), contentSize);
29
33
  const rect = isBboxLocateResultValue(result) ? (()=>{
30
- const pixelBbox = clampPixelBboxToSize(mapLocateResultToPixelBbox(result, preparedSize), contentSize);
31
- return pixelBboxToRect(pixelBbox);
34
+ const pixelBbox = clampPixelBboxToSize(mapLocateResultToPixelBbox(result, preparedSize), contentSize, result.coordinatesMeta.boundsType);
35
+ return pixelBboxToRect(pixelBbox, result.coordinatesMeta.boundsType);
32
36
  })() : void 0;
33
37
  return {
34
38
  center,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/shared/model-locate-result/factory.mjs","sources":["../../../../../src/ai-model/shared/model-locate-result/factory.ts"],"sourcesContent":["import { parseNumericLocateResult } from './parse';\nimport {\n clampPixelBboxToSize,\n clampPixelPointToSize,\n mapLocateResultToPixelBbox,\n mapLocateResultToPixelPoint,\n pixelBboxToRect,\n} from './pixel-mapper';\nimport { createLocateResultPromptSpec } from './prompt-spec';\nimport { isBboxLocateResultValue } from './types';\nimport type {\n LocateResultCodec,\n LocateResultCoordinates,\n LocateResultFormatDefinition,\n ResolvedLocateResultCoordinates,\n} from './types';\nimport {\n assertLocateResultCoordinateRangeAndOrder,\n assertLocateResultStructure,\n} from './validation';\n\nexport function resolveLocateResultCoordinates(\n coordinates: LocateResultCoordinates,\n): ResolvedLocateResultCoordinates {\n if (coordinates.normalizedBy !== undefined && coordinates.normalizedBy <= 0) {\n throw new Error(\n `locate result coordinates normalizedBy must be positive: ${coordinates.normalizedBy}`,\n );\n }\n return {\n shape: coordinates.shape,\n order: coordinates.order ?? 'xy',\n normalizedBy: coordinates.normalizedBy,\n rounding: coordinates.rounding ?? 'round',\n };\n}\n\nexport function createLocateResultCodec(\n config: LocateResultFormatDefinition,\n): LocateResultCodec {\n const resolvedCoordinates = resolveLocateResultCoordinates(\n config.coordinates,\n );\n const parseRawLocateValue =\n config.parseRawLocateValue ??\n ((input) => parseNumericLocateResult(resolvedCoordinates, input));\n return {\n promptSpec: createLocateResultPromptSpec(resolvedCoordinates, {\n resultKey: config.resultKey,\n resultKeyAliases: config.resultKeyAliases,\n }),\n toPixelResult: (rawResult, context) => {\n const result = parseRawLocateValue(rawResult);\n const { preparedSize, contentSize = preparedSize } = context;\n assertLocateResultStructure(result);\n assertLocateResultCoordinateRangeAndOrder(\n result,\n preparedSize.width - 1,\n preparedSize.height - 1,\n );\n // Clamp the mapped center independently from the optional bbox so padding\n // removal cannot change the target by recomputing a clipped box's center.\n const center = clampPixelPointToSize(\n mapLocateResultToPixelPoint(result, preparedSize),\n contentSize,\n );\n // Preserve an original bbox as region metadata for DeepLocate search areas\n // and aiLocate's return value. Point-only results leave rect undefined;\n // click coordinates always use the independently calculated center.\n const rect = isBboxLocateResultValue(result)\n ? (() => {\n const pixelBbox = clampPixelBboxToSize(\n mapLocateResultToPixelBbox(result, preparedSize),\n contentSize,\n );\n return pixelBboxToRect(pixelBbox);\n })()\n : undefined;\n return { center, rect };\n },\n };\n}\n"],"names":["resolveLocateResultCoordinates","coordinates","undefined","Error","createLocateResultCodec","config","resolvedCoordinates","parseRawLocateValue","input","parseNumericLocateResult","createLocateResultPromptSpec","rawResult","context","result","preparedSize","contentSize","assertLocateResultStructure","assertLocateResultCoordinateRangeAndOrder","center","clampPixelPointToSize","mapLocateResultToPixelPoint","rect","isBboxLocateResultValue","pixelBbox","clampPixelBboxToSize","mapLocateResultToPixelBbox","pixelBboxToRect"],"mappings":";;;;;AAqBO,SAASA,+BACdC,WAAoC;IAEpC,IAAIA,AAA6BC,WAA7BD,YAAY,YAAY,IAAkBA,YAAY,YAAY,IAAI,GACxE,MAAM,IAAIE,MACR,CAAC,yDAAyD,EAAEF,YAAY,YAAY,EAAE;IAG1F,OAAO;QACL,OAAOA,YAAY,KAAK;QACxB,OAAOA,YAAY,KAAK,IAAI;QAC5B,cAAcA,YAAY,YAAY;QACtC,UAAUA,YAAY,QAAQ,IAAI;IACpC;AACF;AAEO,SAASG,wBACdC,MAAoC;IAEpC,MAAMC,sBAAsBN,+BAC1BK,OAAO,WAAW;IAEpB,MAAME,sBACJF,OAAO,mBAAmB,IACxB,EAAAG,QAAUC,yBAAyBH,qBAAqBE,MAAK;IACjE,OAAO;QACL,YAAYE,6BAA6BJ,qBAAqB;YAC5D,WAAWD,OAAO,SAAS;YAC3B,kBAAkBA,OAAO,gBAAgB;QAC3C;QACA,eAAe,CAACM,WAAWC;YACzB,MAAMC,SAASN,oBAAoBI;YACnC,MAAM,EAAEG,YAAY,EAAEC,cAAcD,YAAY,EAAE,GAAGF;YACrDI,4BAA4BH;YAC5BI,0CACEJ,QACAC,aAAa,KAAK,GAAG,GACrBA,aAAa,MAAM,GAAG;YAIxB,MAAMI,SAASC,sBACbC,4BAA4BP,QAAQC,eACpCC;YAKF,MAAMM,OAAOC,wBAAwBT,UAChC,AAAC;gBACA,MAAMU,YAAYC,qBAChBC,2BAA2BZ,QAAQC,eACnCC;gBAEF,OAAOW,gBAAgBH;YACzB,OACArB;YACJ,OAAO;gBAAEgB;gBAAQG;YAAK;QACxB;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/shared/model-locate-result/factory.mjs","sources":["../../../../../src/ai-model/shared/model-locate-result/factory.ts"],"sourcesContent":["import { parseNumericLocateResult } from './parse';\nimport {\n clampPixelBboxToSize,\n clampPixelPointToSize,\n mapLocateResultToPixelBbox,\n mapLocateResultToPixelPoint,\n pixelBboxToRect,\n} from './pixel-mapper';\nimport { createLocateResultPromptSpec } from './prompt-spec';\nimport { isBboxLocateResultValue } from './types';\nimport type {\n LocateResultCodec,\n LocateResultCoordinates,\n LocateResultFormatDefinition,\n ResolvedLocateResultCoordinates,\n} from './types';\nimport {\n assertLocateResultCoordinateRangeAndOrder,\n assertLocateResultStructure,\n} from './validation';\n\nexport function resolveLocateResultCoordinates(\n coordinates: LocateResultCoordinates,\n): ResolvedLocateResultCoordinates {\n if (coordinates.normalizedBy !== undefined && coordinates.normalizedBy <= 0) {\n throw new Error(\n `locate result coordinates normalizedBy must be positive: ${coordinates.normalizedBy}`,\n );\n }\n return {\n ...(coordinates.shape === 'bbox'\n ? { boundsType: coordinates.boundsType ?? 'inclusive' }\n : {}),\n shape: coordinates.shape,\n order: coordinates.order ?? 'xy',\n normalizedBy: coordinates.normalizedBy,\n rounding: coordinates.rounding ?? 'round',\n };\n}\n\nexport function createLocateResultCodec(\n config: LocateResultFormatDefinition,\n): LocateResultCodec {\n const resolvedCoordinates = resolveLocateResultCoordinates(\n config.coordinates,\n );\n const parseRawLocateValue =\n config.parseRawLocateValue ??\n ((input) => parseNumericLocateResult(resolvedCoordinates, input));\n return {\n promptSpec: createLocateResultPromptSpec(resolvedCoordinates, {\n resultKey: config.resultKey,\n resultKeyAliases: config.resultKeyAliases,\n }),\n toPixelResult: (rawResult, context) => {\n const result = parseRawLocateValue(rawResult);\n const { preparedSize, contentSize = preparedSize } = context;\n assertLocateResultStructure(result);\n const edgeBounds =\n isBboxLocateResultValue(result) &&\n result.coordinatesMeta.boundsType === 'edges';\n assertLocateResultCoordinateRangeAndOrder(\n result,\n preparedSize.width - (edgeBounds ? 0 : 1),\n preparedSize.height - (edgeBounds ? 0 : 1),\n );\n // Clamp the mapped center independently from the optional bbox so padding\n // removal cannot change the target by recomputing a clipped box's center.\n const center = clampPixelPointToSize(\n mapLocateResultToPixelPoint(result, preparedSize),\n contentSize,\n );\n // Preserve an original bbox as region metadata for DeepLocate search areas\n // and aiLocate's return value. Point-only results leave rect undefined;\n // click coordinates always use the independently calculated center.\n const rect = isBboxLocateResultValue(result)\n ? (() => {\n const pixelBbox = clampPixelBboxToSize(\n mapLocateResultToPixelBbox(result, preparedSize),\n contentSize,\n result.coordinatesMeta.boundsType,\n );\n return pixelBboxToRect(\n pixelBbox,\n result.coordinatesMeta.boundsType,\n );\n })()\n : undefined;\n return { center, rect };\n },\n };\n}\n"],"names":["resolveLocateResultCoordinates","coordinates","undefined","Error","createLocateResultCodec","config","resolvedCoordinates","parseRawLocateValue","input","parseNumericLocateResult","createLocateResultPromptSpec","rawResult","context","result","preparedSize","contentSize","assertLocateResultStructure","edgeBounds","isBboxLocateResultValue","assertLocateResultCoordinateRangeAndOrder","center","clampPixelPointToSize","mapLocateResultToPixelPoint","rect","pixelBbox","clampPixelBboxToSize","mapLocateResultToPixelBbox","pixelBboxToRect"],"mappings":";;;;;AAqBO,SAASA,+BACdC,WAAoC;IAEpC,IAAIA,AAA6BC,WAA7BD,YAAY,YAAY,IAAkBA,YAAY,YAAY,IAAI,GACxE,MAAM,IAAIE,MACR,CAAC,yDAAyD,EAAEF,YAAY,YAAY,EAAE;IAG1F,OAAO;QACL,GAAIA,AAAsB,WAAtBA,YAAY,KAAK,GACjB;YAAE,YAAYA,YAAY,UAAU,IAAI;QAAY,IACpD,CAAC,CAAC;QACN,OAAOA,YAAY,KAAK;QACxB,OAAOA,YAAY,KAAK,IAAI;QAC5B,cAAcA,YAAY,YAAY;QACtC,UAAUA,YAAY,QAAQ,IAAI;IACpC;AACF;AAEO,SAASG,wBACdC,MAAoC;IAEpC,MAAMC,sBAAsBN,+BAC1BK,OAAO,WAAW;IAEpB,MAAME,sBACJF,OAAO,mBAAmB,IACxB,EAAAG,QAAUC,yBAAyBH,qBAAqBE,MAAK;IACjE,OAAO;QACL,YAAYE,6BAA6BJ,qBAAqB;YAC5D,WAAWD,OAAO,SAAS;YAC3B,kBAAkBA,OAAO,gBAAgB;QAC3C;QACA,eAAe,CAACM,WAAWC;YACzB,MAAMC,SAASN,oBAAoBI;YACnC,MAAM,EAAEG,YAAY,EAAEC,cAAcD,YAAY,EAAE,GAAGF;YACrDI,4BAA4BH;YAC5B,MAAMI,aACJC,wBAAwBL,WACxBA,AAAsC,YAAtCA,OAAO,eAAe,CAAC,UAAU;YACnCM,0CACEN,QACAC,aAAa,KAAK,GAAIG,CAAAA,aAAa,IAAI,IACvCH,aAAa,MAAM,GAAIG,CAAAA,aAAa,IAAI;YAI1C,MAAMG,SAASC,sBACbC,4BAA4BT,QAAQC,eACpCC;YAKF,MAAMQ,OAAOL,wBAAwBL,UAChC,AAAC;gBACA,MAAMW,YAAYC,qBAChBC,2BAA2Bb,QAAQC,eACnCC,aACAF,OAAO,eAAe,CAAC,UAAU;gBAEnC,OAAOc,gBACLH,WACAX,OAAO,eAAe,CAAC,UAAU;YAErC,OACAX;YACJ,OAAO;gBAAEkB;gBAAQG;YAAK;QACxB;IACF;AACF"}
@@ -24,8 +24,14 @@ function clampPixelPointToSize([x, y], { width, height }) {
24
24
  clamp(y, 0, maxPixelCoordinate(height))
25
25
  ];
26
26
  }
27
- function clampPixelBboxToSize(pixelBbox, size) {
27
+ function clampPixelBboxToSize(pixelBbox, size, boundsType = 'inclusive') {
28
28
  const [left, top, right, bottom] = pixelBbox;
29
+ if ('edges' === boundsType) return [
30
+ clamp(left, 0, size.width),
31
+ clamp(top, 0, size.height),
32
+ clamp(right, 0, size.width),
33
+ clamp(bottom, 0, size.height)
34
+ ];
29
35
  return [
30
36
  ...clampPixelPointToSize([
31
37
  left,
@@ -37,12 +43,12 @@ function clampPixelBboxToSize(pixelBbox, size) {
37
43
  ], size)
38
44
  ];
39
45
  }
40
- function pixelBboxToRect([left, top, right, bottom]) {
46
+ function pixelBboxToRect([left, top, right, bottom], boundsType = 'inclusive') {
41
47
  return {
42
48
  left,
43
49
  top,
44
- width: right - left + 1,
45
- height: bottom - top + 1
50
+ width: right - left + ('inclusive' === boundsType ? 1 : 0),
51
+ height: bottom - top + ('inclusive' === boundsType ? 1 : 0)
46
52
  };
47
53
  }
48
54
  function mapLocateResultToPixelBbox(result, { width, height }) {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/shared/model-locate-result/pixel-mapper.mjs","sources":["../../../../../src/ai-model/shared/model-locate-result/pixel-mapper.ts"],"sourcesContent":["import type { Rect } from '@/types';\nimport { isBboxLocateResultValue } from './types';\nimport type {\n BboxLocateResultValue,\n CoordinateRounding,\n LocateResultPoint,\n LocateResultValue,\n PixelBbox,\n} from './types';\n\nfunction clamp(value: number, min: number, max: number) {\n return Math.min(Math.max(value, min), max);\n}\n\nexport function maxPixelCoordinate(size: number) {\n return Math.max(size - 1, 0);\n}\n\nexport function normalizedCoordinateToPixel(\n value: number,\n normalizedBy: number,\n size: number,\n rounding: CoordinateRounding,\n) {\n const pixel = (value * size) / normalizedBy;\n switch (rounding) {\n case 'round':\n return Math.round(pixel);\n case 'trunc':\n return Math.trunc(pixel);\n case 'none':\n return pixel;\n default:\n throw new Error(`Invalid coordinate rounding: ${rounding}`);\n }\n}\n\n/** Restrict an already mapped point to the effective content area. */\nexport function clampPixelPointToSize(\n [x, y]: LocateResultPoint,\n { width, height }: { width: number; height: number },\n): LocateResultPoint {\n return [\n clamp(x, 0, maxPixelCoordinate(width)),\n clamp(y, 0, maxPixelCoordinate(height)),\n ];\n}\n\n/** Restrict an already mapped bbox to the effective content area. */\nexport function clampPixelBboxToSize(\n pixelBbox: PixelBbox,\n size: { width: number; height: number },\n): PixelBbox {\n const [left, top, right, bottom] = pixelBbox;\n return [\n ...clampPixelPointToSize([left, top], size),\n ...clampPixelPointToSize([right, bottom], size),\n ];\n}\n\nexport function pixelBboxToRect([left, top, right, bottom]: PixelBbox): Rect {\n return {\n left,\n top,\n width: right - left + 1,\n height: bottom - top + 1,\n };\n}\n\nexport function mapLocateResultToPixelBbox(\n result: BboxLocateResultValue,\n { width, height }: { width: number; height: number },\n): PixelBbox {\n const { normalizedBy, order, rounding } = result.coordinatesMeta;\n const [first, second, third, fourth] = result.coordinates;\n const xyBbox: PixelBbox =\n order === 'yx' ? [second, first, fourth, third] : result.coordinates;\n return normalizedBy === undefined\n ? xyBbox\n : [\n normalizedCoordinateToPixel(xyBbox[0], normalizedBy, width, rounding),\n normalizedCoordinateToPixel(xyBbox[1], normalizedBy, height, rounding),\n normalizedCoordinateToPixel(xyBbox[2], normalizedBy, width, rounding),\n normalizedCoordinateToPixel(xyBbox[3], normalizedBy, height, rounding),\n ];\n}\n\n/** Resolve the target before any rounding or clipping can shift its center. */\nexport function mapLocateResultToPixelPoint(\n result: LocateResultValue,\n { width, height }: { width: number; height: number },\n): LocateResultPoint {\n const { order, normalizedBy, rounding } = result.coordinatesMeta;\n const [first, second] = isBboxLocateResultValue(result)\n ? [\n (result.coordinates[0] + result.coordinates[2]) / 2,\n (result.coordinates[1] + result.coordinates[3]) / 2,\n ]\n : result.coordinates;\n const [x, y] = order === 'yx' ? [second, first] : [first, second];\n return normalizedBy === undefined\n ? [x, y]\n : [\n normalizedCoordinateToPixel(x, normalizedBy, width, rounding),\n normalizedCoordinateToPixel(y, normalizedBy, height, rounding),\n ];\n}\n"],"names":["clamp","value","min","max","Math","maxPixelCoordinate","size","normalizedCoordinateToPixel","normalizedBy","rounding","pixel","Error","clampPixelPointToSize","x","y","width","height","clampPixelBboxToSize","pixelBbox","left","top","right","bottom","pixelBboxToRect","mapLocateResultToPixelBbox","result","order","first","second","third","fourth","xyBbox","undefined","mapLocateResultToPixelPoint","isBboxLocateResultValue"],"mappings":";AAUA,SAASA,MAAMC,KAAa,EAAEC,GAAW,EAAEC,GAAW;IACpD,OAAOC,KAAK,GAAG,CAACA,KAAK,GAAG,CAACH,OAAOC,MAAMC;AACxC;AAEO,SAASE,mBAAmBC,IAAY;IAC7C,OAAOF,KAAK,GAAG,CAACE,OAAO,GAAG;AAC5B;AAEO,SAASC,4BACdN,KAAa,EACbO,YAAoB,EACpBF,IAAY,EACZG,QAA4B;IAE5B,MAAMC,QAAST,QAAQK,OAAQE;IAC/B,OAAQC;QACN,KAAK;YACH,OAAOL,KAAK,KAAK,CAACM;QACpB,KAAK;YACH,OAAON,KAAK,KAAK,CAACM;QACpB,KAAK;YACH,OAAOA;QACT;YACE,MAAM,IAAIC,MAAM,CAAC,6BAA6B,EAAEF,UAAU;IAC9D;AACF;AAGO,SAASG,sBACd,CAACC,GAAGC,EAAqB,EACzB,EAAEC,KAAK,EAAEC,MAAM,EAAqC;IAEpD,OAAO;QACLhB,MAAMa,GAAG,GAAGR,mBAAmBU;QAC/Bf,MAAMc,GAAG,GAAGT,mBAAmBW;KAChC;AACH;AAGO,SAASC,qBACdC,SAAoB,EACpBZ,IAAuC;IAEvC,MAAM,CAACa,MAAMC,KAAKC,OAAOC,OAAO,GAAGJ;IACnC,OAAO;WACFN,sBAAsB;YAACO;YAAMC;SAAI,EAAEd;WACnCM,sBAAsB;YAACS;YAAOC;SAAO,EAAEhB;KAC3C;AACH;AAEO,SAASiB,gBAAgB,CAACJ,MAAMC,KAAKC,OAAOC,OAAkB;IACnE,OAAO;QACLH;QACAC;QACA,OAAOC,QAAQF,OAAO;QACtB,QAAQG,SAASF,MAAM;IACzB;AACF;AAEO,SAASI,2BACdC,MAA6B,EAC7B,EAAEV,KAAK,EAAEC,MAAM,EAAqC;IAEpD,MAAM,EAAER,YAAY,EAAEkB,KAAK,EAAEjB,QAAQ,EAAE,GAAGgB,OAAO,eAAe;IAChE,MAAM,CAACE,OAAOC,QAAQC,OAAOC,OAAO,GAAGL,OAAO,WAAW;IACzD,MAAMM,SACJL,AAAU,SAAVA,QAAiB;QAACE;QAAQD;QAAOG;QAAQD;KAAM,GAAGJ,OAAO,WAAW;IACtE,OAAOjB,AAAiBwB,WAAjBxB,eACHuB,SACA;QACExB,4BAA4BwB,MAAM,CAAC,EAAE,EAAEvB,cAAcO,OAAON;QAC5DF,4BAA4BwB,MAAM,CAAC,EAAE,EAAEvB,cAAcQ,QAAQP;QAC7DF,4BAA4BwB,MAAM,CAAC,EAAE,EAAEvB,cAAcO,OAAON;QAC5DF,4BAA4BwB,MAAM,CAAC,EAAE,EAAEvB,cAAcQ,QAAQP;KAC9D;AACP;AAGO,SAASwB,4BACdR,MAAyB,EACzB,EAAEV,KAAK,EAAEC,MAAM,EAAqC;IAEpD,MAAM,EAAEU,KAAK,EAAElB,YAAY,EAAEC,QAAQ,EAAE,GAAGgB,OAAO,eAAe;IAChE,MAAM,CAACE,OAAOC,OAAO,GAAGM,wBAAwBT,UAC5C;QACGA,CAAAA,OAAO,WAAW,CAAC,EAAE,GAAGA,OAAO,WAAW,CAAC,EAAC,IAAK;QACjDA,CAAAA,OAAO,WAAW,CAAC,EAAE,GAAGA,OAAO,WAAW,CAAC,EAAC,IAAK;KACnD,GACDA,OAAO,WAAW;IACtB,MAAM,CAACZ,GAAGC,EAAE,GAAGY,AAAU,SAAVA,QAAiB;QAACE;QAAQD;KAAM,GAAG;QAACA;QAAOC;KAAO;IACjE,OAAOpB,AAAiBwB,WAAjBxB,eACH;QAACK;QAAGC;KAAE,GACN;QACEP,4BAA4BM,GAAGL,cAAcO,OAAON;QACpDF,4BAA4BO,GAAGN,cAAcQ,QAAQP;KACtD;AACP"}
1
+ {"version":3,"file":"ai-model/shared/model-locate-result/pixel-mapper.mjs","sources":["../../../../../src/ai-model/shared/model-locate-result/pixel-mapper.ts"],"sourcesContent":["import type { Rect } from '@/types';\nimport { isBboxLocateResultValue } from './types';\nimport type {\n BboxBoundsType,\n BboxLocateResultValue,\n CoordinateRounding,\n LocateResultPoint,\n LocateResultValue,\n PixelBbox,\n} from './types';\n\nfunction clamp(value: number, min: number, max: number) {\n return Math.min(Math.max(value, min), max);\n}\n\nexport function maxPixelCoordinate(size: number) {\n return Math.max(size - 1, 0);\n}\n\nexport function normalizedCoordinateToPixel(\n value: number,\n normalizedBy: number,\n size: number,\n rounding: CoordinateRounding,\n) {\n const pixel = (value * size) / normalizedBy;\n switch (rounding) {\n case 'round':\n return Math.round(pixel);\n case 'trunc':\n return Math.trunc(pixel);\n case 'none':\n return pixel;\n default:\n throw new Error(`Invalid coordinate rounding: ${rounding}`);\n }\n}\n\n/** Restrict an already mapped point to the effective content area. */\nexport function clampPixelPointToSize(\n [x, y]: LocateResultPoint,\n { width, height }: { width: number; height: number },\n): LocateResultPoint {\n return [\n clamp(x, 0, maxPixelCoordinate(width)),\n clamp(y, 0, maxPixelCoordinate(height)),\n ];\n}\n\n/** Restrict an already mapped bbox to the effective content area. */\nexport function clampPixelBboxToSize(\n pixelBbox: PixelBbox,\n size: { width: number; height: number },\n boundsType: BboxBoundsType = 'inclusive',\n): PixelBbox {\n const [left, top, right, bottom] = pixelBbox;\n if (boundsType === 'edges') {\n return [\n clamp(left, 0, size.width),\n clamp(top, 0, size.height),\n clamp(right, 0, size.width),\n clamp(bottom, 0, size.height),\n ];\n }\n return [\n ...clampPixelPointToSize([left, top], size),\n ...clampPixelPointToSize([right, bottom], size),\n ];\n}\n\nexport function pixelBboxToRect(\n [left, top, right, bottom]: PixelBbox,\n boundsType: BboxBoundsType = 'inclusive',\n): Rect {\n return {\n left,\n top,\n width: right - left + (boundsType === 'inclusive' ? 1 : 0),\n height: bottom - top + (boundsType === 'inclusive' ? 1 : 0),\n };\n}\n\nexport function mapLocateResultToPixelBbox(\n result: BboxLocateResultValue,\n { width, height }: { width: number; height: number },\n): PixelBbox {\n const { normalizedBy, order, rounding } = result.coordinatesMeta;\n const [first, second, third, fourth] = result.coordinates;\n const xyBbox: PixelBbox =\n order === 'yx' ? [second, first, fourth, third] : result.coordinates;\n return normalizedBy === undefined\n ? xyBbox\n : [\n normalizedCoordinateToPixel(xyBbox[0], normalizedBy, width, rounding),\n normalizedCoordinateToPixel(xyBbox[1], normalizedBy, height, rounding),\n normalizedCoordinateToPixel(xyBbox[2], normalizedBy, width, rounding),\n normalizedCoordinateToPixel(xyBbox[3], normalizedBy, height, rounding),\n ];\n}\n\n/** Resolve the target before any rounding or clipping can shift its center. */\nexport function mapLocateResultToPixelPoint(\n result: LocateResultValue,\n { width, height }: { width: number; height: number },\n): LocateResultPoint {\n const { order, normalizedBy, rounding } = result.coordinatesMeta;\n const [first, second] = isBboxLocateResultValue(result)\n ? [\n (result.coordinates[0] + result.coordinates[2]) / 2,\n (result.coordinates[1] + result.coordinates[3]) / 2,\n ]\n : result.coordinates;\n const [x, y] = order === 'yx' ? [second, first] : [first, second];\n return normalizedBy === undefined\n ? [x, y]\n : [\n normalizedCoordinateToPixel(x, normalizedBy, width, rounding),\n normalizedCoordinateToPixel(y, normalizedBy, height, rounding),\n ];\n}\n"],"names":["clamp","value","min","max","Math","maxPixelCoordinate","size","normalizedCoordinateToPixel","normalizedBy","rounding","pixel","Error","clampPixelPointToSize","x","y","width","height","clampPixelBboxToSize","pixelBbox","boundsType","left","top","right","bottom","pixelBboxToRect","mapLocateResultToPixelBbox","result","order","first","second","third","fourth","xyBbox","undefined","mapLocateResultToPixelPoint","isBboxLocateResultValue"],"mappings":"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"}