@openrouter/sdk 0.3.2 → 0.3.7

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 (294) hide show
  1. package/esm/core.js +1 -0
  2. package/esm/funcs/analyticsGetUserActivity.js +1 -0
  3. package/esm/funcs/apiKeysCreate.js +1 -0
  4. package/esm/funcs/apiKeysDelete.js +1 -0
  5. package/esm/funcs/apiKeysGet.js +1 -0
  6. package/esm/funcs/apiKeysGetCurrentKeyMetadata.js +1 -0
  7. package/esm/funcs/apiKeysList.js +1 -0
  8. package/esm/funcs/apiKeysUpdate.js +1 -0
  9. package/esm/funcs/betaResponsesSend.js +1 -0
  10. package/esm/funcs/call-model.d.ts +33 -0
  11. package/esm/funcs/call-model.js +155 -0
  12. package/esm/funcs/chatSend.js +1 -0
  13. package/esm/funcs/completionsGenerate.js +1 -0
  14. package/esm/funcs/creditsCreateCoinbaseCharge.js +1 -0
  15. package/esm/funcs/creditsGetCredits.js +1 -0
  16. package/esm/funcs/embeddingsGenerate.js +1 -0
  17. package/esm/funcs/embeddingsListModels.js +1 -0
  18. package/esm/funcs/endpointsList.js +1 -0
  19. package/esm/funcs/endpointsListZdrEndpoints.js +1 -0
  20. package/esm/funcs/generationsGetGeneration.js +1 -0
  21. package/esm/funcs/modelsCount.js +1 -0
  22. package/esm/funcs/modelsList.js +1 -0
  23. package/esm/funcs/modelsListForUser.js +1 -0
  24. package/esm/funcs/oAuthCreateAuthCode.js +1 -0
  25. package/esm/funcs/oAuthExchangeAuthCodeForAPIKey.js +1 -0
  26. package/esm/funcs/parametersGetParameters.js +1 -0
  27. package/esm/funcs/providersList.js +1 -0
  28. package/esm/hooks/hooks.js +1 -0
  29. package/esm/hooks/index.js +1 -0
  30. package/esm/hooks/types.js +1 -0
  31. package/esm/index.d.ts +3 -0
  32. package/esm/index.js +4 -0
  33. package/esm/lib/anthropic-compat.d.ts +46 -0
  34. package/esm/lib/anthropic-compat.js +204 -0
  35. package/esm/lib/anthropic-compat.test.d.ts +2 -0
  36. package/esm/lib/anthropic-compat.test.js +479 -0
  37. package/esm/lib/base64.js +1 -0
  38. package/esm/lib/chat-compat.d.ts +46 -0
  39. package/esm/lib/chat-compat.js +108 -0
  40. package/esm/lib/chat-compat.test.d.ts +2 -0
  41. package/esm/lib/chat-compat.test.js +282 -0
  42. package/esm/lib/config.d.ts +2 -2
  43. package/esm/lib/config.js +3 -2
  44. package/esm/lib/dlv.js +1 -0
  45. package/esm/lib/encodings.js +1 -0
  46. package/esm/lib/env.js +1 -0
  47. package/esm/lib/event-streams.js +1 -0
  48. package/esm/lib/files.js +1 -0
  49. package/esm/lib/http.js +1 -0
  50. package/esm/lib/is-plain-object.js +1 -0
  51. package/esm/lib/logger.js +1 -0
  52. package/esm/lib/matchers.js +1 -0
  53. package/esm/lib/{response-wrapper.d.ts → model-result.d.ts} +19 -26
  54. package/esm/lib/{response-wrapper.js → model-result.js} +93 -83
  55. package/esm/lib/primitives.js +1 -0
  56. package/esm/lib/retries.js +1 -0
  57. package/esm/lib/schemas.js +1 -0
  58. package/esm/lib/sdks.js +1 -0
  59. package/esm/lib/security.js +1 -0
  60. package/esm/lib/stream-transformers.d.ts +27 -1
  61. package/esm/lib/stream-transformers.js +319 -1
  62. package/esm/lib/tool-types.d.ts +3 -3
  63. package/esm/lib/url.js +1 -0
  64. package/esm/models/activityitem.js +1 -0
  65. package/esm/models/assistantmessage.js +1 -0
  66. package/esm/models/badgatewayresponseerrordata.js +1 -0
  67. package/esm/models/badrequestresponseerrordata.js +1 -0
  68. package/esm/models/chatcompletionfinishreason.js +1 -0
  69. package/esm/models/chaterror.js +1 -0
  70. package/esm/models/chatgenerationparams.js +1 -0
  71. package/esm/models/chatgenerationtokenusage.js +1 -0
  72. package/esm/models/chatmessagecontentitem.js +1 -0
  73. package/esm/models/chatmessagecontentitemaudio.js +1 -0
  74. package/esm/models/chatmessagecontentitemcachecontrol.js +1 -0
  75. package/esm/models/chatmessagecontentitemimage.js +1 -0
  76. package/esm/models/chatmessagecontentitemtext.js +1 -0
  77. package/esm/models/chatmessagecontentitemvideo.js +1 -0
  78. package/esm/models/chatmessagetokenlogprob.js +1 -0
  79. package/esm/models/chatmessagetokenlogprobs.js +1 -0
  80. package/esm/models/chatmessagetoolcall.js +1 -0
  81. package/esm/models/chatresponse.js +1 -0
  82. package/esm/models/chatresponsechoice.js +1 -0
  83. package/esm/models/chatstreamingchoice.js +1 -0
  84. package/esm/models/chatstreamingmessagechunk.js +1 -0
  85. package/esm/models/chatstreamingmessagetoolcall.js +1 -0
  86. package/esm/models/chatstreamingresponsechunk.js +1 -0
  87. package/esm/models/chatstreamoptions.js +1 -0
  88. package/esm/models/claude-message.d.ts +218 -0
  89. package/esm/models/claude-message.js +6 -0
  90. package/esm/models/completionchoice.js +1 -0
  91. package/esm/models/completioncreateparams.js +1 -0
  92. package/esm/models/completionlogprobs.js +1 -0
  93. package/esm/models/completionresponse.js +1 -0
  94. package/esm/models/completionusage.js +1 -0
  95. package/esm/models/createchargerequest.js +1 -0
  96. package/esm/models/datacollection.js +1 -0
  97. package/esm/models/defaultparameters.js +1 -0
  98. package/esm/models/edgenetworktimeoutresponseerrordata.js +1 -0
  99. package/esm/models/endpointstatus.js +1 -0
  100. package/esm/models/errors/badgatewayresponseerror.js +1 -0
  101. package/esm/models/errors/badrequestresponseerror.js +1 -0
  102. package/esm/models/errors/chaterror.js +1 -0
  103. package/esm/models/errors/edgenetworktimeoutresponseerror.js +1 -0
  104. package/esm/models/errors/forbiddenresponseerror.js +1 -0
  105. package/esm/models/errors/httpclienterrors.js +1 -0
  106. package/esm/models/errors/index.js +1 -0
  107. package/esm/models/errors/internalserverresponseerror.js +1 -0
  108. package/esm/models/errors/notfoundresponseerror.js +1 -0
  109. package/esm/models/errors/openrouterdefaulterror.js +1 -0
  110. package/esm/models/errors/openroutererror.js +1 -0
  111. package/esm/models/errors/payloadtoolargeresponseerror.js +1 -0
  112. package/esm/models/errors/paymentrequiredresponseerror.js +1 -0
  113. package/esm/models/errors/provideroverloadedresponseerror.js +1 -0
  114. package/esm/models/errors/requesttimeoutresponseerror.js +1 -0
  115. package/esm/models/errors/responsevalidationerror.js +1 -0
  116. package/esm/models/errors/sdkvalidationerror.js +1 -0
  117. package/esm/models/errors/serviceunavailableresponseerror.js +1 -0
  118. package/esm/models/errors/toomanyrequestsresponseerror.js +1 -0
  119. package/esm/models/errors/unauthorizedresponseerror.js +1 -0
  120. package/esm/models/errors/unprocessableentityresponseerror.js +1 -0
  121. package/esm/models/filecitation.js +1 -0
  122. package/esm/models/filepath.js +1 -0
  123. package/esm/models/forbiddenresponseerrordata.js +1 -0
  124. package/esm/models/imagegenerationstatus.js +1 -0
  125. package/esm/models/index.d.ts +1 -0
  126. package/esm/models/index.js +2 -0
  127. package/esm/models/inputmodality.js +1 -0
  128. package/esm/models/instructtype.js +1 -0
  129. package/esm/models/internalserverresponseerrordata.js +1 -0
  130. package/esm/models/jsonschemaconfig.js +1 -0
  131. package/esm/models/listendpointsresponse.js +1 -0
  132. package/esm/models/message.js +1 -0
  133. package/esm/models/model.js +1 -0
  134. package/esm/models/modelarchitecture.js +1 -0
  135. package/esm/models/modelgroup.js +1 -0
  136. package/esm/models/modelscountresponse.js +1 -0
  137. package/esm/models/modelslistresponse.js +1 -0
  138. package/esm/models/namedtoolchoice.js +1 -0
  139. package/esm/models/notfoundresponseerrordata.js +1 -0
  140. package/esm/models/openairesponsesannotation.js +1 -0
  141. package/esm/models/openairesponsesincludable.js +1 -0
  142. package/esm/models/openairesponsesincompletedetails.js +1 -0
  143. package/esm/models/openairesponsesinputunion.js +1 -0
  144. package/esm/models/openairesponsesprompt.js +1 -0
  145. package/esm/models/openairesponsesreasoningconfig.js +1 -0
  146. package/esm/models/openairesponsesreasoningeffort.js +1 -0
  147. package/esm/models/openairesponsesrefusalcontent.js +1 -0
  148. package/esm/models/openairesponsesresponsestatus.js +1 -0
  149. package/esm/models/openairesponsesservicetier.js +1 -0
  150. package/esm/models/openairesponsestoolchoiceunion.js +1 -0
  151. package/esm/models/openairesponsestruncation.js +1 -0
  152. package/esm/models/openresponseseasyinputmessage.js +1 -0
  153. package/esm/models/openresponseserrorevent.js +1 -0
  154. package/esm/models/openresponsesfunctioncalloutput.js +1 -0
  155. package/esm/models/openresponsesfunctiontoolcall.js +1 -0
  156. package/esm/models/openresponsesimagegencallcompleted.js +1 -0
  157. package/esm/models/openresponsesimagegencallgenerating.js +1 -0
  158. package/esm/models/openresponsesimagegencallinprogress.js +1 -0
  159. package/esm/models/openresponsesimagegencallpartialimage.js +1 -0
  160. package/esm/models/openresponsesinput.js +1 -0
  161. package/esm/models/openresponsesinputmessageitem.js +1 -0
  162. package/esm/models/openresponseslogprobs.js +1 -0
  163. package/esm/models/openresponsesnonstreamingresponse.js +1 -0
  164. package/esm/models/openresponsesreasoning.js +1 -0
  165. package/esm/models/openresponsesreasoningconfig.js +1 -0
  166. package/esm/models/openresponsesreasoningdeltaevent.js +1 -0
  167. package/esm/models/openresponsesreasoningdoneevent.js +1 -0
  168. package/esm/models/openresponsesreasoningsummarypartaddedevent.js +1 -0
  169. package/esm/models/openresponsesreasoningsummarytextdeltaevent.js +1 -0
  170. package/esm/models/openresponsesreasoningsummarytextdoneevent.js +1 -0
  171. package/esm/models/openresponsesrequest.js +1 -0
  172. package/esm/models/openresponsesresponsetext.js +1 -0
  173. package/esm/models/openresponsesstreamevent.js +1 -0
  174. package/esm/models/openresponsestoplogprobs.js +1 -0
  175. package/esm/models/openresponsesusage.js +1 -0
  176. package/esm/models/openresponseswebsearch20250826tool.js +1 -0
  177. package/esm/models/openresponseswebsearchpreview20250311tool.js +1 -0
  178. package/esm/models/openresponseswebsearchpreviewtool.js +1 -0
  179. package/esm/models/openresponseswebsearchtool.js +1 -0
  180. package/esm/models/operations/createauthkeyscode.js +1 -0
  181. package/esm/models/operations/createcoinbasecharge.js +1 -0
  182. package/esm/models/operations/createembeddings.js +1 -0
  183. package/esm/models/operations/createkeys.js +1 -0
  184. package/esm/models/operations/createresponses.js +1 -0
  185. package/esm/models/operations/deletekeys.js +1 -0
  186. package/esm/models/operations/exchangeauthcodeforapikey.js +1 -0
  187. package/esm/models/operations/getcredits.js +1 -0
  188. package/esm/models/operations/getcurrentkey.js +1 -0
  189. package/esm/models/operations/getgeneration.js +1 -0
  190. package/esm/models/operations/getkey.js +1 -0
  191. package/esm/models/operations/getmodels.js +1 -0
  192. package/esm/models/operations/getparameters.js +1 -0
  193. package/esm/models/operations/getuseractivity.js +1 -0
  194. package/esm/models/operations/index.js +1 -0
  195. package/esm/models/operations/list.js +1 -0
  196. package/esm/models/operations/listendpoints.js +1 -0
  197. package/esm/models/operations/listendpointszdr.js +1 -0
  198. package/esm/models/operations/listmodelsuser.js +1 -0
  199. package/esm/models/operations/listproviders.js +1 -0
  200. package/esm/models/operations/sendchatcompletionrequest.js +1 -0
  201. package/esm/models/operations/updatekeys.js +1 -0
  202. package/esm/models/outputitemimagegenerationcall.js +1 -0
  203. package/esm/models/outputmessage.js +1 -0
  204. package/esm/models/outputmodality.js +1 -0
  205. package/esm/models/parameter.js +1 -0
  206. package/esm/models/payloadtoolargeresponseerrordata.js +1 -0
  207. package/esm/models/paymentrequiredresponseerrordata.js +1 -0
  208. package/esm/models/pdfparserengine.js +1 -0
  209. package/esm/models/pdfparseroptions.js +1 -0
  210. package/esm/models/perrequestlimits.js +1 -0
  211. package/esm/models/providername.js +1 -0
  212. package/esm/models/provideroverloadedresponseerrordata.js +1 -0
  213. package/esm/models/providerpreferences.js +1 -0
  214. package/esm/models/providersort.js +1 -0
  215. package/esm/models/providersortconfig.js +1 -0
  216. package/esm/models/providersortunion.js +1 -0
  217. package/esm/models/publicendpoint.js +1 -0
  218. package/esm/models/publicpricing.js +1 -0
  219. package/esm/models/quantization.js +1 -0
  220. package/esm/models/reasoningsummarytext.js +1 -0
  221. package/esm/models/reasoningsummaryverbosity.js +1 -0
  222. package/esm/models/reasoningtextcontent.js +1 -0
  223. package/esm/models/requesttimeoutresponseerrordata.js +1 -0
  224. package/esm/models/responseformatjsonschema.js +1 -0
  225. package/esm/models/responseformattextconfig.js +1 -0
  226. package/esm/models/responseformattextgrammar.js +1 -0
  227. package/esm/models/responseinputaudio.js +1 -0
  228. package/esm/models/responseinputfile.js +1 -0
  229. package/esm/models/responseinputimage.js +1 -0
  230. package/esm/models/responseinputtext.js +1 -0
  231. package/esm/models/responseoutputtext.js +1 -0
  232. package/esm/models/responseserrorfield.js +1 -0
  233. package/esm/models/responsesformatjsonobject.js +1 -0
  234. package/esm/models/responsesformattext.js +1 -0
  235. package/esm/models/responsesformattextjsonschemaconfig.js +1 -0
  236. package/esm/models/responsesimagegenerationcall.js +1 -0
  237. package/esm/models/responsesoutputitem.js +1 -0
  238. package/esm/models/responsesoutputitemfilesearchcall.js +1 -0
  239. package/esm/models/responsesoutputitemfunctioncall.js +1 -0
  240. package/esm/models/responsesoutputitemreasoning.js +1 -0
  241. package/esm/models/responsesoutputmessage.js +1 -0
  242. package/esm/models/responsessearchcontextsize.js +1 -0
  243. package/esm/models/responseswebsearchcalloutput.js +1 -0
  244. package/esm/models/responseswebsearchuserlocation.js +1 -0
  245. package/esm/models/responsetextconfig.js +1 -0
  246. package/esm/models/schema0.js +1 -0
  247. package/esm/models/schema3.js +1 -0
  248. package/esm/models/security.js +1 -0
  249. package/esm/models/serviceunavailableresponseerrordata.js +1 -0
  250. package/esm/models/systemmessage.js +1 -0
  251. package/esm/models/toolcallstatus.js +1 -0
  252. package/esm/models/tooldefinitionjson.js +1 -0
  253. package/esm/models/toolresponsemessage.js +1 -0
  254. package/esm/models/toomanyrequestsresponseerrordata.js +1 -0
  255. package/esm/models/topproviderinfo.js +1 -0
  256. package/esm/models/unauthorizedresponseerrordata.js +1 -0
  257. package/esm/models/unprocessableentityresponseerrordata.js +1 -0
  258. package/esm/models/urlcitation.js +1 -0
  259. package/esm/models/usermessage.js +1 -0
  260. package/esm/models/websearchengine.js +1 -0
  261. package/esm/models/websearchpreviewtooluserlocation.js +1 -0
  262. package/esm/models/websearchstatus.js +1 -0
  263. package/esm/sdk/analytics.js +1 -0
  264. package/esm/sdk/apikeys.js +1 -0
  265. package/esm/sdk/beta.js +1 -0
  266. package/esm/sdk/chat.js +1 -0
  267. package/esm/sdk/completions.js +1 -0
  268. package/esm/sdk/credits.js +1 -0
  269. package/esm/sdk/embeddings.js +1 -0
  270. package/esm/sdk/endpoints.js +1 -0
  271. package/esm/sdk/generations.js +1 -0
  272. package/esm/sdk/index.js +1 -0
  273. package/esm/sdk/models.js +1 -0
  274. package/esm/sdk/oauth.js +1 -0
  275. package/esm/sdk/parameters.js +1 -0
  276. package/esm/sdk/providers.js +1 -0
  277. package/esm/sdk/responses.js +1 -0
  278. package/esm/sdk/sdk.d.ts +3 -3
  279. package/esm/sdk/sdk.js +2 -1
  280. package/esm/types/async.js +1 -0
  281. package/esm/types/blobs.js +1 -0
  282. package/esm/types/constdatetime.js +1 -0
  283. package/esm/types/discriminatedUnion.js +1 -0
  284. package/esm/types/enums.js +1 -0
  285. package/esm/types/fp.js +1 -0
  286. package/esm/types/index.js +1 -0
  287. package/esm/types/operations.js +1 -0
  288. package/esm/types/rfcdate.js +1 -0
  289. package/esm/types/streams.js +1 -0
  290. package/esm/types/unrecognized.js +1 -0
  291. package/jsr.json +1 -1
  292. package/package.json +1 -1
  293. package/esm/funcs/callModel.d.ts +0 -87
  294. package/esm/funcs/callModel.js +0 -215
@@ -0,0 +1,204 @@
1
+ import { OpenResponsesEasyInputMessageRoleUser, OpenResponsesEasyInputMessageRoleAssistant, } from "../models/openresponseseasyinputmessage.js";
2
+ import { OpenResponsesInputMessageItemRoleUser, OpenResponsesInputMessageItemRoleSystem, } from "../models/openresponsesinputmessageitem.js";
3
+ import { OpenResponsesFunctionCallOutputType } from "../models/openresponsesfunctioncalloutput.js";
4
+ import { convertToClaudeMessage } from "./stream-transformers.js";
5
+ /**
6
+ * Maps Claude role strings to OpenResponses role types
7
+ */
8
+ function mapClaudeRole(role) {
9
+ if (role === "user") {
10
+ return OpenResponsesEasyInputMessageRoleUser.User;
11
+ }
12
+ return OpenResponsesEasyInputMessageRoleAssistant.Assistant;
13
+ }
14
+ /**
15
+ * Creates a properly typed OpenResponsesEasyInputMessage
16
+ */
17
+ function createEasyInputMessage(role, content) {
18
+ return {
19
+ role: mapClaudeRole(role),
20
+ content,
21
+ };
22
+ }
23
+ /**
24
+ * Creates a properly typed OpenResponsesFunctionCallOutput
25
+ */
26
+ function createFunctionCallOutput(callId, output) {
27
+ return {
28
+ type: OpenResponsesFunctionCallOutputType.FunctionCallOutput,
29
+ callId,
30
+ output,
31
+ };
32
+ }
33
+ /**
34
+ * Convert Anthropic Claude-style messages to OpenResponses input format.
35
+ *
36
+ * This function transforms ClaudeMessageParam[] (Anthropic SDK format) to
37
+ * OpenResponsesInput format that can be passed directly to callModel().
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { fromClaudeMessages } from '@openrouter/sdk';
42
+ *
43
+ * const claudeMessages = [
44
+ * { role: "user", content: "Hello!" },
45
+ * { role: "assistant", content: "Hi there!" },
46
+ * ];
47
+ *
48
+ * const response = openrouter.callModel({
49
+ * model: "anthropic/claude-3-sonnet",
50
+ * input: fromClaudeMessages(claudeMessages),
51
+ * });
52
+ * ```
53
+ */
54
+ export function fromClaudeMessages(messages) {
55
+ const result = [];
56
+ for (const msg of messages) {
57
+ const { role, content } = msg;
58
+ if (typeof content === "string") {
59
+ result.push(createEasyInputMessage(role, content));
60
+ continue;
61
+ }
62
+ const contentItems = [];
63
+ let hasStructuredContent = false;
64
+ for (const block of content) {
65
+ switch (block.type) {
66
+ case 'text': {
67
+ const textBlock = block;
68
+ contentItems.push({
69
+ type: 'input_text',
70
+ text: textBlock.text,
71
+ });
72
+ // Note: cache_control is lost in conversion (OpenRouter doesn't support it)
73
+ break;
74
+ }
75
+ case 'image': {
76
+ const imageBlock = block;
77
+ hasStructuredContent = true;
78
+ // Convert Claude image source to OpenRouter format
79
+ if (imageBlock.source.type === 'url') {
80
+ contentItems.push({
81
+ type: 'input_image',
82
+ detail: 'auto',
83
+ imageUrl: imageBlock.source.url,
84
+ });
85
+ }
86
+ else if (imageBlock.source.type === 'base64') {
87
+ // Base64 images: OpenRouter expects a URL, so we use data URI
88
+ const dataUri = `data:${imageBlock.source.media_type};base64,${imageBlock.source.data}`;
89
+ contentItems.push({
90
+ type: 'input_image',
91
+ detail: 'auto',
92
+ imageUrl: dataUri,
93
+ });
94
+ }
95
+ break;
96
+ }
97
+ case 'tool_use': {
98
+ const toolUseBlock = block;
99
+ // Map to OpenResponsesFunctionToolCall
100
+ result.push({
101
+ type: 'function_call',
102
+ callId: toolUseBlock.id,
103
+ name: toolUseBlock.name,
104
+ arguments: JSON.stringify(toolUseBlock.input),
105
+ id: toolUseBlock.id,
106
+ status: 'completed', // Tool use in conversation history is already completed
107
+ });
108
+ break;
109
+ }
110
+ case 'tool_result': {
111
+ const toolResultBlock = block;
112
+ let toolOutput = '';
113
+ if (typeof toolResultBlock.content === 'string') {
114
+ toolOutput = toolResultBlock.content;
115
+ }
116
+ else {
117
+ // Extract text and handle images separately
118
+ const textParts = [];
119
+ const imageParts = [];
120
+ for (const part of toolResultBlock.content) {
121
+ if (part.type === 'text') {
122
+ textParts.push(part.text);
123
+ }
124
+ else if (part.type === 'image') {
125
+ imageParts.push(part);
126
+ }
127
+ }
128
+ toolOutput = textParts.join('');
129
+ // Map images to image_generation_call items
130
+ for (const imagePart of imageParts) {
131
+ const imageUrl = imagePart.source.type === 'url'
132
+ ? imagePart.source.url
133
+ : `data:${imagePart.source.media_type};base64,${imagePart.source.data}`;
134
+ result.push({
135
+ type: 'image_generation_call',
136
+ id: `${toolResultBlock.tool_use_id}-image-${imageParts.indexOf(imagePart)}`,
137
+ result: imageUrl,
138
+ status: 'completed',
139
+ });
140
+ }
141
+ }
142
+ // Add the function call output for the text portion
143
+ if (toolOutput || typeof toolResultBlock.content === 'string') {
144
+ result.push(createFunctionCallOutput(toolResultBlock.tool_use_id, toolOutput));
145
+ }
146
+ break;
147
+ }
148
+ default: {
149
+ const _exhaustiveCheck = block;
150
+ throw new Error(`Unhandled content block type: ${_exhaustiveCheck.type}`);
151
+ }
152
+ }
153
+ }
154
+ // Use structured format if we have images, otherwise use simple format
155
+ if (contentItems.length > 0) {
156
+ if (hasStructuredContent) {
157
+ // Use OpenResponsesInputMessageItem for messages with images
158
+ const messageRole = role === 'user'
159
+ ? OpenResponsesInputMessageItemRoleUser.User
160
+ : role === 'assistant'
161
+ ? OpenResponsesInputMessageItemRoleSystem.System // Assistant messages treated as system in this context
162
+ : OpenResponsesInputMessageItemRoleSystem.System;
163
+ result.push({
164
+ type: 'message',
165
+ role: messageRole,
166
+ content: contentItems,
167
+ });
168
+ }
169
+ else {
170
+ // Use simple format for text-only messages
171
+ const textContent = contentItems
172
+ .filter((item) => item.type === 'input_text')
173
+ .map(item => item.text)
174
+ .join('');
175
+ if (textContent) {
176
+ result.push(createEasyInputMessage(role, textContent));
177
+ }
178
+ }
179
+ }
180
+ }
181
+ return result;
182
+ }
183
+ /**
184
+ * Convert an OpenResponses response to Anthropic Claude message format.
185
+ *
186
+ * This function transforms OpenResponsesNonStreamingResponse to ClaudeMessage
187
+ * (Anthropic SDK format) for compatibility with code expecting Claude responses.
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * import { toClaudeMessage } from '@openrouter/sdk';
192
+ *
193
+ * const response = await openrouter.callModel({
194
+ * model: "anthropic/claude-3-sonnet",
195
+ * input: "Hello!",
196
+ * });
197
+ *
198
+ * const openResponsesResult = await response.getResponse();
199
+ * const claudeMessage = toClaudeMessage(openResponsesResult);
200
+ * // claudeMessage is now compatible with Anthropic SDK types
201
+ * ```
202
+ */
203
+ export const toClaudeMessage = convertToClaudeMessage;
204
+ //# sourceMappingURL=anthropic-compat.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=anthropic-compat.test.d.ts.map
@@ -0,0 +1,479 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { fromClaudeMessages, toClaudeMessage } from "./anthropic-compat.js";
3
+ /**
4
+ * Creates a properly typed mock OpenResponsesNonStreamingResponse for testing.
5
+ * This factory provides all required fields with sensible defaults.
6
+ */
7
+ function createMockResponse(overrides) {
8
+ return {
9
+ id: "resp_test",
10
+ object: "response",
11
+ createdAt: Date.now(),
12
+ model: "openai/gpt-4",
13
+ status: "completed",
14
+ error: null,
15
+ incompleteDetails: null,
16
+ temperature: null,
17
+ topP: null,
18
+ metadata: null,
19
+ tools: [],
20
+ toolChoice: "auto",
21
+ parallelToolCalls: false,
22
+ ...overrides,
23
+ };
24
+ }
25
+ describe("fromClaudeMessages", () => {
26
+ describe("basic message conversion", () => {
27
+ it("converts user message with string content", () => {
28
+ const claudeMessages = [
29
+ { role: "user", content: "Hello, how are you?" },
30
+ ];
31
+ const result = fromClaudeMessages(claudeMessages);
32
+ expect(result).toEqual([
33
+ { role: "user", content: "Hello, how are you?" },
34
+ ]);
35
+ });
36
+ it("converts assistant message with string content", () => {
37
+ const claudeMessages = [
38
+ { role: "assistant", content: "I am doing well, thank you!" },
39
+ ];
40
+ const result = fromClaudeMessages(claudeMessages);
41
+ expect(result).toEqual([
42
+ { role: "assistant", content: "I am doing well, thank you!" },
43
+ ]);
44
+ });
45
+ it("converts multiple messages in conversation", () => {
46
+ const claudeMessages = [
47
+ { role: "user", content: "Hi" },
48
+ { role: "assistant", content: "Hello!" },
49
+ { role: "user", content: "How are you?" },
50
+ ];
51
+ const result = fromClaudeMessages(claudeMessages);
52
+ expect(result).toEqual([
53
+ { role: "user", content: "Hi" },
54
+ { role: "assistant", content: "Hello!" },
55
+ { role: "user", content: "How are you?" },
56
+ ]);
57
+ });
58
+ });
59
+ describe("text block content conversion", () => {
60
+ it("converts user message with text block array", () => {
61
+ const claudeMessages = [
62
+ {
63
+ role: "user",
64
+ content: [{ type: "text", text: "Hello from text block" }],
65
+ },
66
+ ];
67
+ const result = fromClaudeMessages(claudeMessages);
68
+ expect(result).toEqual([
69
+ { role: "user", content: "Hello from text block" },
70
+ ]);
71
+ });
72
+ it("combines multiple text blocks into single content string", () => {
73
+ const claudeMessages = [
74
+ {
75
+ role: "user",
76
+ content: [
77
+ { type: "text", text: "First part. " },
78
+ { type: "text", text: "Second part." },
79
+ ],
80
+ },
81
+ ];
82
+ const result = fromClaudeMessages(claudeMessages);
83
+ expect(result).toEqual([
84
+ { role: "user", content: "First part. Second part." },
85
+ ]);
86
+ });
87
+ });
88
+ describe("tool_result block conversion", () => {
89
+ it("converts tool_result with string content to function_call_output", () => {
90
+ const claudeMessages = [
91
+ {
92
+ role: "user",
93
+ content: [
94
+ {
95
+ type: "tool_result",
96
+ tool_use_id: "tool_123",
97
+ content: "Tool execution result",
98
+ },
99
+ ],
100
+ },
101
+ ];
102
+ const result = fromClaudeMessages(claudeMessages);
103
+ expect(result).toEqual([
104
+ {
105
+ type: "function_call_output",
106
+ callId: "tool_123",
107
+ output: "Tool execution result",
108
+ },
109
+ ]);
110
+ });
111
+ it("converts tool_result with text block array to function_call_output", () => {
112
+ const claudeMessages = [
113
+ {
114
+ role: "user",
115
+ content: [
116
+ {
117
+ type: "tool_result",
118
+ tool_use_id: "tool_456",
119
+ content: [
120
+ { type: "text", text: "Result part 1. " },
121
+ { type: "text", text: "Result part 2." },
122
+ ],
123
+ },
124
+ ],
125
+ },
126
+ ];
127
+ const result = fromClaudeMessages(claudeMessages);
128
+ expect(result).toEqual([
129
+ {
130
+ type: "function_call_output",
131
+ callId: "tool_456",
132
+ output: "Result part 1. Result part 2.",
133
+ },
134
+ ]);
135
+ });
136
+ it("handles mixed text and tool_result blocks", () => {
137
+ const claudeMessages = [
138
+ {
139
+ role: "user",
140
+ content: [
141
+ { type: "text", text: "Here is some context. " },
142
+ {
143
+ type: "tool_result",
144
+ tool_use_id: "tool_789",
145
+ content: "Tool output",
146
+ },
147
+ { type: "text", text: "And some more text." },
148
+ ],
149
+ },
150
+ ];
151
+ const result = fromClaudeMessages(claudeMessages);
152
+ // Should produce both the text message and the function_call_output
153
+ expect(result).toEqual([
154
+ {
155
+ type: "function_call_output",
156
+ callId: "tool_789",
157
+ output: "Tool output",
158
+ },
159
+ { role: "user", content: "Here is some context. And some more text." },
160
+ ]);
161
+ });
162
+ });
163
+ describe("tool_use blocks (should be skipped)", () => {
164
+ it("skips tool_use blocks as they are output from assistant", () => {
165
+ const claudeMessages = [
166
+ {
167
+ role: "assistant",
168
+ content: [
169
+ { type: "text", text: "Let me help you with that." },
170
+ {
171
+ type: "tool_use",
172
+ id: "tool_abc",
173
+ name: "get_weather",
174
+ input: { location: "SF" },
175
+ },
176
+ ],
177
+ },
178
+ ];
179
+ const result = fromClaudeMessages(claudeMessages);
180
+ // Only the text should be captured, tool_use is from previous response
181
+ expect(result).toEqual([
182
+ { role: "assistant", content: "Let me help you with that." },
183
+ ]);
184
+ });
185
+ });
186
+ describe("image blocks (should be skipped)", () => {
187
+ it("skips image blocks", () => {
188
+ const claudeMessages = [
189
+ {
190
+ role: "user",
191
+ content: [
192
+ { type: "text", text: "Look at this image:" },
193
+ {
194
+ type: "image",
195
+ source: {
196
+ type: "base64",
197
+ media_type: "image/png",
198
+ data: "base64data...",
199
+ },
200
+ },
201
+ ],
202
+ },
203
+ ];
204
+ const result = fromClaudeMessages(claudeMessages);
205
+ // Only the text should be captured
206
+ expect(result).toEqual([
207
+ { role: "user", content: "Look at this image:" },
208
+ ]);
209
+ });
210
+ });
211
+ describe("empty and edge cases", () => {
212
+ it("handles empty messages array", () => {
213
+ const result = fromClaudeMessages([]);
214
+ expect(result).toEqual([]);
215
+ });
216
+ it("handles message with empty string content", () => {
217
+ const claudeMessages = [
218
+ { role: "user", content: "" },
219
+ ];
220
+ const result = fromClaudeMessages(claudeMessages);
221
+ expect(result).toEqual([{ role: "user", content: "" }]);
222
+ });
223
+ it("handles message with empty content array", () => {
224
+ const claudeMessages = [
225
+ { role: "user", content: [] },
226
+ ];
227
+ const result = fromClaudeMessages(claudeMessages);
228
+ // Should produce empty array since no text and no tool_results
229
+ expect(result).toEqual([]);
230
+ });
231
+ });
232
+ });
233
+ describe("toClaudeMessage", () => {
234
+ describe("basic message conversion", () => {
235
+ it("converts response with text output to ClaudeMessage", () => {
236
+ const response = createMockResponse({
237
+ id: "resp_123",
238
+ output: [
239
+ {
240
+ id: "msg_1",
241
+ type: "message",
242
+ role: "assistant",
243
+ status: "completed",
244
+ content: [
245
+ {
246
+ type: "output_text",
247
+ text: "Hello! How can I help you?",
248
+ annotations: [],
249
+ },
250
+ ],
251
+ },
252
+ ],
253
+ usage: {
254
+ inputTokens: 10,
255
+ outputTokens: 20,
256
+ totalTokens: 30,
257
+ inputTokensDetails: { cachedTokens: 0 },
258
+ outputTokensDetails: { reasoningTokens: 0 },
259
+ },
260
+ });
261
+ const result = toClaudeMessage(response);
262
+ expect(result).toEqual({
263
+ id: "resp_123",
264
+ type: "message",
265
+ role: "assistant",
266
+ model: "openai/gpt-4",
267
+ content: [
268
+ {
269
+ type: "text",
270
+ text: "Hello! How can I help you?",
271
+ },
272
+ ],
273
+ stop_reason: "end_turn",
274
+ stop_sequence: null,
275
+ usage: {
276
+ input_tokens: 10,
277
+ output_tokens: 20,
278
+ cache_creation_input_tokens: 0,
279
+ cache_read_input_tokens: 0,
280
+ },
281
+ });
282
+ });
283
+ });
284
+ describe("function call conversion", () => {
285
+ it("converts function_call output to tool_use block", () => {
286
+ const response = createMockResponse({
287
+ id: "resp_456",
288
+ output: [
289
+ {
290
+ type: "function_call",
291
+ callId: "call_abc",
292
+ name: "get_weather",
293
+ arguments: '{"location":"San Francisco"}',
294
+ id: "fc_1",
295
+ status: "completed",
296
+ },
297
+ ],
298
+ usage: {
299
+ inputTokens: 15,
300
+ outputTokens: 25,
301
+ totalTokens: 40,
302
+ inputTokensDetails: { cachedTokens: 0 },
303
+ outputTokensDetails: { reasoningTokens: 0 },
304
+ },
305
+ });
306
+ const result = toClaudeMessage(response);
307
+ expect(result.content).toEqual([
308
+ {
309
+ type: "tool_use",
310
+ id: "call_abc",
311
+ name: "get_weather",
312
+ input: { location: "San Francisco" },
313
+ },
314
+ ]);
315
+ expect(result.stop_reason).toBe("tool_use");
316
+ });
317
+ });
318
+ describe("reasoning conversion", () => {
319
+ it("converts reasoning output to thinking block", () => {
320
+ const response = createMockResponse({
321
+ id: "resp_789",
322
+ model: "openai/o1",
323
+ output: [
324
+ {
325
+ type: "reasoning",
326
+ id: "reason_1",
327
+ summary: [
328
+ {
329
+ type: "summary_text",
330
+ text: "I need to think about this carefully...",
331
+ },
332
+ ],
333
+ },
334
+ {
335
+ id: "msg_2",
336
+ type: "message",
337
+ role: "assistant",
338
+ status: "completed",
339
+ content: [
340
+ {
341
+ type: "output_text",
342
+ text: "Here is my answer.",
343
+ annotations: [],
344
+ },
345
+ ],
346
+ },
347
+ ],
348
+ usage: {
349
+ inputTokens: 20,
350
+ outputTokens: 100,
351
+ totalTokens: 120,
352
+ inputTokensDetails: { cachedTokens: 0 },
353
+ outputTokensDetails: { reasoningTokens: 0 },
354
+ },
355
+ });
356
+ const result = toClaudeMessage(response);
357
+ expect(result.content).toEqual([
358
+ {
359
+ type: "thinking",
360
+ thinking: "I need to think about this carefully...",
361
+ signature: "",
362
+ },
363
+ {
364
+ type: "text",
365
+ text: "Here is my answer.",
366
+ },
367
+ ]);
368
+ });
369
+ });
370
+ describe("stop reason mapping", () => {
371
+ it("maps completed status to end_turn", () => {
372
+ const response = createMockResponse({
373
+ id: "resp_1",
374
+ output: [
375
+ {
376
+ id: "msg_1",
377
+ type: "message",
378
+ role: "assistant",
379
+ status: "completed",
380
+ content: [{ type: "output_text", text: "Done", annotations: [] }],
381
+ },
382
+ ],
383
+ usage: {
384
+ inputTokens: 5,
385
+ outputTokens: 5,
386
+ totalTokens: 10,
387
+ inputTokensDetails: { cachedTokens: 0 },
388
+ outputTokensDetails: { reasoningTokens: 0 },
389
+ },
390
+ });
391
+ const result = toClaudeMessage(response);
392
+ expect(result.stop_reason).toBe("end_turn");
393
+ });
394
+ it("maps incomplete with max_output_tokens to max_tokens", () => {
395
+ const response = createMockResponse({
396
+ id: "resp_2",
397
+ status: "incomplete",
398
+ incompleteDetails: { reason: "max_output_tokens" },
399
+ output: [
400
+ {
401
+ id: "msg_1",
402
+ type: "message",
403
+ role: "assistant",
404
+ status: "incomplete",
405
+ content: [
406
+ { type: "output_text", text: "Partial...", annotations: [] },
407
+ ],
408
+ },
409
+ ],
410
+ usage: {
411
+ inputTokens: 5,
412
+ outputTokens: 100,
413
+ totalTokens: 105,
414
+ inputTokensDetails: { cachedTokens: 0 },
415
+ outputTokensDetails: { reasoningTokens: 0 },
416
+ },
417
+ });
418
+ const result = toClaudeMessage(response);
419
+ expect(result.stop_reason).toBe("max_tokens");
420
+ });
421
+ it("maps response with function calls to tool_use", () => {
422
+ const response = createMockResponse({
423
+ id: "resp_3",
424
+ output: [
425
+ {
426
+ type: "function_call",
427
+ callId: "call_1",
428
+ name: "test_tool",
429
+ arguments: "{}",
430
+ id: "fc_1",
431
+ status: "completed",
432
+ },
433
+ ],
434
+ usage: {
435
+ inputTokens: 5,
436
+ outputTokens: 10,
437
+ totalTokens: 15,
438
+ inputTokensDetails: { cachedTokens: 0 },
439
+ outputTokensDetails: { reasoningTokens: 0 },
440
+ },
441
+ });
442
+ const result = toClaudeMessage(response);
443
+ expect(result.stop_reason).toBe("tool_use");
444
+ });
445
+ });
446
+ describe("usage mapping", () => {
447
+ it("maps usage with cached tokens", () => {
448
+ const response = createMockResponse({
449
+ id: "resp_1",
450
+ output: [
451
+ {
452
+ id: "msg_1",
453
+ type: "message",
454
+ role: "assistant",
455
+ status: "completed",
456
+ content: [{ type: "output_text", text: "OK", annotations: [] }],
457
+ },
458
+ ],
459
+ usage: {
460
+ inputTokens: 100,
461
+ outputTokens: 50,
462
+ totalTokens: 150,
463
+ inputTokensDetails: {
464
+ cachedTokens: 80,
465
+ },
466
+ outputTokensDetails: { reasoningTokens: 0 },
467
+ },
468
+ });
469
+ const result = toClaudeMessage(response);
470
+ expect(result.usage).toEqual({
471
+ input_tokens: 100,
472
+ output_tokens: 50,
473
+ cache_creation_input_tokens: 80,
474
+ cache_read_input_tokens: 0,
475
+ });
476
+ });
477
+ });
478
+ });
479
+ //# sourceMappingURL=anthropic-compat.test.js.map
package/esm/lib/base64.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ * @generated-id: 598522066688
3
4
  */
4
5
  import * as z from "zod/v4";
5
6
  export function bytesToBase64(u8arr) {