@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.
- package/esm/core.js +1 -0
- package/esm/funcs/analyticsGetUserActivity.js +1 -0
- package/esm/funcs/apiKeysCreate.js +1 -0
- package/esm/funcs/apiKeysDelete.js +1 -0
- package/esm/funcs/apiKeysGet.js +1 -0
- package/esm/funcs/apiKeysGetCurrentKeyMetadata.js +1 -0
- package/esm/funcs/apiKeysList.js +1 -0
- package/esm/funcs/apiKeysUpdate.js +1 -0
- package/esm/funcs/betaResponsesSend.js +1 -0
- package/esm/funcs/call-model.d.ts +33 -0
- package/esm/funcs/call-model.js +155 -0
- package/esm/funcs/chatSend.js +1 -0
- package/esm/funcs/completionsGenerate.js +1 -0
- package/esm/funcs/creditsCreateCoinbaseCharge.js +1 -0
- package/esm/funcs/creditsGetCredits.js +1 -0
- package/esm/funcs/embeddingsGenerate.js +1 -0
- package/esm/funcs/embeddingsListModels.js +1 -0
- package/esm/funcs/endpointsList.js +1 -0
- package/esm/funcs/endpointsListZdrEndpoints.js +1 -0
- package/esm/funcs/generationsGetGeneration.js +1 -0
- package/esm/funcs/modelsCount.js +1 -0
- package/esm/funcs/modelsList.js +1 -0
- package/esm/funcs/modelsListForUser.js +1 -0
- package/esm/funcs/oAuthCreateAuthCode.js +1 -0
- package/esm/funcs/oAuthExchangeAuthCodeForAPIKey.js +1 -0
- package/esm/funcs/parametersGetParameters.js +1 -0
- package/esm/funcs/providersList.js +1 -0
- package/esm/hooks/hooks.js +1 -0
- package/esm/hooks/index.js +1 -0
- package/esm/hooks/types.js +1 -0
- package/esm/index.d.ts +3 -0
- package/esm/index.js +4 -0
- package/esm/lib/anthropic-compat.d.ts +46 -0
- package/esm/lib/anthropic-compat.js +204 -0
- package/esm/lib/anthropic-compat.test.d.ts +2 -0
- package/esm/lib/anthropic-compat.test.js +479 -0
- package/esm/lib/base64.js +1 -0
- package/esm/lib/chat-compat.d.ts +46 -0
- package/esm/lib/chat-compat.js +108 -0
- package/esm/lib/chat-compat.test.d.ts +2 -0
- package/esm/lib/chat-compat.test.js +282 -0
- package/esm/lib/config.d.ts +2 -2
- package/esm/lib/config.js +3 -2
- package/esm/lib/dlv.js +1 -0
- package/esm/lib/encodings.js +1 -0
- package/esm/lib/env.js +1 -0
- package/esm/lib/event-streams.js +1 -0
- package/esm/lib/files.js +1 -0
- package/esm/lib/http.js +1 -0
- package/esm/lib/is-plain-object.js +1 -0
- package/esm/lib/logger.js +1 -0
- package/esm/lib/matchers.js +1 -0
- package/esm/lib/{response-wrapper.d.ts → model-result.d.ts} +19 -26
- package/esm/lib/{response-wrapper.js → model-result.js} +93 -83
- package/esm/lib/primitives.js +1 -0
- package/esm/lib/retries.js +1 -0
- package/esm/lib/schemas.js +1 -0
- package/esm/lib/sdks.js +1 -0
- package/esm/lib/security.js +1 -0
- package/esm/lib/stream-transformers.d.ts +27 -1
- package/esm/lib/stream-transformers.js +319 -1
- package/esm/lib/tool-types.d.ts +3 -3
- package/esm/lib/url.js +1 -0
- package/esm/models/activityitem.js +1 -0
- package/esm/models/assistantmessage.js +1 -0
- package/esm/models/badgatewayresponseerrordata.js +1 -0
- package/esm/models/badrequestresponseerrordata.js +1 -0
- package/esm/models/chatcompletionfinishreason.js +1 -0
- package/esm/models/chaterror.js +1 -0
- package/esm/models/chatgenerationparams.js +1 -0
- package/esm/models/chatgenerationtokenusage.js +1 -0
- package/esm/models/chatmessagecontentitem.js +1 -0
- package/esm/models/chatmessagecontentitemaudio.js +1 -0
- package/esm/models/chatmessagecontentitemcachecontrol.js +1 -0
- package/esm/models/chatmessagecontentitemimage.js +1 -0
- package/esm/models/chatmessagecontentitemtext.js +1 -0
- package/esm/models/chatmessagecontentitemvideo.js +1 -0
- package/esm/models/chatmessagetokenlogprob.js +1 -0
- package/esm/models/chatmessagetokenlogprobs.js +1 -0
- package/esm/models/chatmessagetoolcall.js +1 -0
- package/esm/models/chatresponse.js +1 -0
- package/esm/models/chatresponsechoice.js +1 -0
- package/esm/models/chatstreamingchoice.js +1 -0
- package/esm/models/chatstreamingmessagechunk.js +1 -0
- package/esm/models/chatstreamingmessagetoolcall.js +1 -0
- package/esm/models/chatstreamingresponsechunk.js +1 -0
- package/esm/models/chatstreamoptions.js +1 -0
- package/esm/models/claude-message.d.ts +218 -0
- package/esm/models/claude-message.js +6 -0
- package/esm/models/completionchoice.js +1 -0
- package/esm/models/completioncreateparams.js +1 -0
- package/esm/models/completionlogprobs.js +1 -0
- package/esm/models/completionresponse.js +1 -0
- package/esm/models/completionusage.js +1 -0
- package/esm/models/createchargerequest.js +1 -0
- package/esm/models/datacollection.js +1 -0
- package/esm/models/defaultparameters.js +1 -0
- package/esm/models/edgenetworktimeoutresponseerrordata.js +1 -0
- package/esm/models/endpointstatus.js +1 -0
- package/esm/models/errors/badgatewayresponseerror.js +1 -0
- package/esm/models/errors/badrequestresponseerror.js +1 -0
- package/esm/models/errors/chaterror.js +1 -0
- package/esm/models/errors/edgenetworktimeoutresponseerror.js +1 -0
- package/esm/models/errors/forbiddenresponseerror.js +1 -0
- package/esm/models/errors/httpclienterrors.js +1 -0
- package/esm/models/errors/index.js +1 -0
- package/esm/models/errors/internalserverresponseerror.js +1 -0
- package/esm/models/errors/notfoundresponseerror.js +1 -0
- package/esm/models/errors/openrouterdefaulterror.js +1 -0
- package/esm/models/errors/openroutererror.js +1 -0
- package/esm/models/errors/payloadtoolargeresponseerror.js +1 -0
- package/esm/models/errors/paymentrequiredresponseerror.js +1 -0
- package/esm/models/errors/provideroverloadedresponseerror.js +1 -0
- package/esm/models/errors/requesttimeoutresponseerror.js +1 -0
- package/esm/models/errors/responsevalidationerror.js +1 -0
- package/esm/models/errors/sdkvalidationerror.js +1 -0
- package/esm/models/errors/serviceunavailableresponseerror.js +1 -0
- package/esm/models/errors/toomanyrequestsresponseerror.js +1 -0
- package/esm/models/errors/unauthorizedresponseerror.js +1 -0
- package/esm/models/errors/unprocessableentityresponseerror.js +1 -0
- package/esm/models/filecitation.js +1 -0
- package/esm/models/filepath.js +1 -0
- package/esm/models/forbiddenresponseerrordata.js +1 -0
- package/esm/models/imagegenerationstatus.js +1 -0
- package/esm/models/index.d.ts +1 -0
- package/esm/models/index.js +2 -0
- package/esm/models/inputmodality.js +1 -0
- package/esm/models/instructtype.js +1 -0
- package/esm/models/internalserverresponseerrordata.js +1 -0
- package/esm/models/jsonschemaconfig.js +1 -0
- package/esm/models/listendpointsresponse.js +1 -0
- package/esm/models/message.js +1 -0
- package/esm/models/model.js +1 -0
- package/esm/models/modelarchitecture.js +1 -0
- package/esm/models/modelgroup.js +1 -0
- package/esm/models/modelscountresponse.js +1 -0
- package/esm/models/modelslistresponse.js +1 -0
- package/esm/models/namedtoolchoice.js +1 -0
- package/esm/models/notfoundresponseerrordata.js +1 -0
- package/esm/models/openairesponsesannotation.js +1 -0
- package/esm/models/openairesponsesincludable.js +1 -0
- package/esm/models/openairesponsesincompletedetails.js +1 -0
- package/esm/models/openairesponsesinputunion.js +1 -0
- package/esm/models/openairesponsesprompt.js +1 -0
- package/esm/models/openairesponsesreasoningconfig.js +1 -0
- package/esm/models/openairesponsesreasoningeffort.js +1 -0
- package/esm/models/openairesponsesrefusalcontent.js +1 -0
- package/esm/models/openairesponsesresponsestatus.js +1 -0
- package/esm/models/openairesponsesservicetier.js +1 -0
- package/esm/models/openairesponsestoolchoiceunion.js +1 -0
- package/esm/models/openairesponsestruncation.js +1 -0
- package/esm/models/openresponseseasyinputmessage.js +1 -0
- package/esm/models/openresponseserrorevent.js +1 -0
- package/esm/models/openresponsesfunctioncalloutput.js +1 -0
- package/esm/models/openresponsesfunctiontoolcall.js +1 -0
- package/esm/models/openresponsesimagegencallcompleted.js +1 -0
- package/esm/models/openresponsesimagegencallgenerating.js +1 -0
- package/esm/models/openresponsesimagegencallinprogress.js +1 -0
- package/esm/models/openresponsesimagegencallpartialimage.js +1 -0
- package/esm/models/openresponsesinput.js +1 -0
- package/esm/models/openresponsesinputmessageitem.js +1 -0
- package/esm/models/openresponseslogprobs.js +1 -0
- package/esm/models/openresponsesnonstreamingresponse.js +1 -0
- package/esm/models/openresponsesreasoning.js +1 -0
- package/esm/models/openresponsesreasoningconfig.js +1 -0
- package/esm/models/openresponsesreasoningdeltaevent.js +1 -0
- package/esm/models/openresponsesreasoningdoneevent.js +1 -0
- package/esm/models/openresponsesreasoningsummarypartaddedevent.js +1 -0
- package/esm/models/openresponsesreasoningsummarytextdeltaevent.js +1 -0
- package/esm/models/openresponsesreasoningsummarytextdoneevent.js +1 -0
- package/esm/models/openresponsesrequest.js +1 -0
- package/esm/models/openresponsesresponsetext.js +1 -0
- package/esm/models/openresponsesstreamevent.js +1 -0
- package/esm/models/openresponsestoplogprobs.js +1 -0
- package/esm/models/openresponsesusage.js +1 -0
- package/esm/models/openresponseswebsearch20250826tool.js +1 -0
- package/esm/models/openresponseswebsearchpreview20250311tool.js +1 -0
- package/esm/models/openresponseswebsearchpreviewtool.js +1 -0
- package/esm/models/openresponseswebsearchtool.js +1 -0
- package/esm/models/operations/createauthkeyscode.js +1 -0
- package/esm/models/operations/createcoinbasecharge.js +1 -0
- package/esm/models/operations/createembeddings.js +1 -0
- package/esm/models/operations/createkeys.js +1 -0
- package/esm/models/operations/createresponses.js +1 -0
- package/esm/models/operations/deletekeys.js +1 -0
- package/esm/models/operations/exchangeauthcodeforapikey.js +1 -0
- package/esm/models/operations/getcredits.js +1 -0
- package/esm/models/operations/getcurrentkey.js +1 -0
- package/esm/models/operations/getgeneration.js +1 -0
- package/esm/models/operations/getkey.js +1 -0
- package/esm/models/operations/getmodels.js +1 -0
- package/esm/models/operations/getparameters.js +1 -0
- package/esm/models/operations/getuseractivity.js +1 -0
- package/esm/models/operations/index.js +1 -0
- package/esm/models/operations/list.js +1 -0
- package/esm/models/operations/listendpoints.js +1 -0
- package/esm/models/operations/listendpointszdr.js +1 -0
- package/esm/models/operations/listmodelsuser.js +1 -0
- package/esm/models/operations/listproviders.js +1 -0
- package/esm/models/operations/sendchatcompletionrequest.js +1 -0
- package/esm/models/operations/updatekeys.js +1 -0
- package/esm/models/outputitemimagegenerationcall.js +1 -0
- package/esm/models/outputmessage.js +1 -0
- package/esm/models/outputmodality.js +1 -0
- package/esm/models/parameter.js +1 -0
- package/esm/models/payloadtoolargeresponseerrordata.js +1 -0
- package/esm/models/paymentrequiredresponseerrordata.js +1 -0
- package/esm/models/pdfparserengine.js +1 -0
- package/esm/models/pdfparseroptions.js +1 -0
- package/esm/models/perrequestlimits.js +1 -0
- package/esm/models/providername.js +1 -0
- package/esm/models/provideroverloadedresponseerrordata.js +1 -0
- package/esm/models/providerpreferences.js +1 -0
- package/esm/models/providersort.js +1 -0
- package/esm/models/providersortconfig.js +1 -0
- package/esm/models/providersortunion.js +1 -0
- package/esm/models/publicendpoint.js +1 -0
- package/esm/models/publicpricing.js +1 -0
- package/esm/models/quantization.js +1 -0
- package/esm/models/reasoningsummarytext.js +1 -0
- package/esm/models/reasoningsummaryverbosity.js +1 -0
- package/esm/models/reasoningtextcontent.js +1 -0
- package/esm/models/requesttimeoutresponseerrordata.js +1 -0
- package/esm/models/responseformatjsonschema.js +1 -0
- package/esm/models/responseformattextconfig.js +1 -0
- package/esm/models/responseformattextgrammar.js +1 -0
- package/esm/models/responseinputaudio.js +1 -0
- package/esm/models/responseinputfile.js +1 -0
- package/esm/models/responseinputimage.js +1 -0
- package/esm/models/responseinputtext.js +1 -0
- package/esm/models/responseoutputtext.js +1 -0
- package/esm/models/responseserrorfield.js +1 -0
- package/esm/models/responsesformatjsonobject.js +1 -0
- package/esm/models/responsesformattext.js +1 -0
- package/esm/models/responsesformattextjsonschemaconfig.js +1 -0
- package/esm/models/responsesimagegenerationcall.js +1 -0
- package/esm/models/responsesoutputitem.js +1 -0
- package/esm/models/responsesoutputitemfilesearchcall.js +1 -0
- package/esm/models/responsesoutputitemfunctioncall.js +1 -0
- package/esm/models/responsesoutputitemreasoning.js +1 -0
- package/esm/models/responsesoutputmessage.js +1 -0
- package/esm/models/responsessearchcontextsize.js +1 -0
- package/esm/models/responseswebsearchcalloutput.js +1 -0
- package/esm/models/responseswebsearchuserlocation.js +1 -0
- package/esm/models/responsetextconfig.js +1 -0
- package/esm/models/schema0.js +1 -0
- package/esm/models/schema3.js +1 -0
- package/esm/models/security.js +1 -0
- package/esm/models/serviceunavailableresponseerrordata.js +1 -0
- package/esm/models/systemmessage.js +1 -0
- package/esm/models/toolcallstatus.js +1 -0
- package/esm/models/tooldefinitionjson.js +1 -0
- package/esm/models/toolresponsemessage.js +1 -0
- package/esm/models/toomanyrequestsresponseerrordata.js +1 -0
- package/esm/models/topproviderinfo.js +1 -0
- package/esm/models/unauthorizedresponseerrordata.js +1 -0
- package/esm/models/unprocessableentityresponseerrordata.js +1 -0
- package/esm/models/urlcitation.js +1 -0
- package/esm/models/usermessage.js +1 -0
- package/esm/models/websearchengine.js +1 -0
- package/esm/models/websearchpreviewtooluserlocation.js +1 -0
- package/esm/models/websearchstatus.js +1 -0
- package/esm/sdk/analytics.js +1 -0
- package/esm/sdk/apikeys.js +1 -0
- package/esm/sdk/beta.js +1 -0
- package/esm/sdk/chat.js +1 -0
- package/esm/sdk/completions.js +1 -0
- package/esm/sdk/credits.js +1 -0
- package/esm/sdk/embeddings.js +1 -0
- package/esm/sdk/endpoints.js +1 -0
- package/esm/sdk/generations.js +1 -0
- package/esm/sdk/index.js +1 -0
- package/esm/sdk/models.js +1 -0
- package/esm/sdk/oauth.js +1 -0
- package/esm/sdk/parameters.js +1 -0
- package/esm/sdk/providers.js +1 -0
- package/esm/sdk/responses.js +1 -0
- package/esm/sdk/sdk.d.ts +3 -3
- package/esm/sdk/sdk.js +2 -1
- package/esm/types/async.js +1 -0
- package/esm/types/blobs.js +1 -0
- package/esm/types/constdatetime.js +1 -0
- package/esm/types/discriminatedUnion.js +1 -0
- package/esm/types/enums.js +1 -0
- package/esm/types/fp.js +1 -0
- package/esm/types/index.js +1 -0
- package/esm/types/operations.js +1 -0
- package/esm/types/rfcdate.js +1 -0
- package/esm/types/streams.js +1 -0
- package/esm/types/unrecognized.js +1 -0
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/esm/funcs/callModel.d.ts +0 -87
- 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,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
|