@openrouter/sdk 0.3.2 → 0.3.10
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/.zed/settings.json +10 -0
- package/_speakeasy/.github/action-inputs-config.json +53 -0
- package/_speakeasy/.github/action-security-config.json +88 -0
- 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 +118 -0
- package/esm/funcs/call-model.js +137 -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 +20 -5
- package/esm/index.js +21 -4
- package/esm/lib/anthropic-compat.d.ts +50 -0
- package/esm/lib/anthropic-compat.js +223 -0
- package/esm/lib/anthropic-compat.test.d.ts +2 -0
- package/esm/lib/anthropic-compat.test.js +479 -0
- package/esm/lib/async-params.d.ts +53 -0
- package/esm/lib/async-params.js +76 -0
- package/esm/lib/base64.js +1 -0
- package/esm/lib/chat-compat.d.ts +46 -0
- package/esm/lib/chat-compat.js +112 -0
- package/esm/lib/chat-compat.test.d.ts +2 -0
- package/esm/lib/chat-compat.test.js +282 -0
- package/esm/lib/claude-constants.d.ts +22 -0
- package/esm/lib/claude-constants.js +20 -0
- package/esm/lib/claude-type-guards.d.ts +10 -0
- package/esm/lib/claude-type-guards.js +70 -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} +29 -43
- package/esm/lib/{response-wrapper.js → model-result.js} +146 -175
- package/esm/lib/next-turn-params.d.ts +30 -0
- package/esm/lib/next-turn-params.js +129 -0
- package/esm/lib/primitives.js +1 -0
- package/esm/lib/retries.js +1 -0
- package/esm/lib/reusable-stream.js +10 -10
- package/esm/lib/schemas.js +1 -0
- package/esm/lib/sdks.js +1 -0
- package/esm/lib/security.js +1 -0
- package/esm/lib/stop-conditions.d.ts +80 -0
- package/esm/lib/stop-conditions.js +104 -0
- package/esm/lib/stream-transformers.d.ts +30 -4
- package/esm/lib/stream-transformers.js +467 -98
- package/esm/lib/stream-type-guards.d.ts +29 -0
- package/esm/lib/stream-type-guards.js +109 -0
- package/esm/lib/tool-executor.d.ts +7 -6
- package/esm/lib/tool-executor.js +4 -0
- package/esm/lib/tool-orchestrator.d.ts +7 -7
- package/esm/lib/tool-orchestrator.js +38 -10
- package/esm/lib/tool-types.d.ts +163 -29
- package/esm/lib/tool-types.js +6 -0
- package/esm/lib/tool.d.ts +99 -0
- package/esm/lib/tool.js +71 -0
- package/esm/lib/turn-context.d.ts +50 -0
- package/esm/lib/turn-context.js +59 -0
- 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 +4 -10
- 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 +6 -3
- package/esm/funcs/callModel.d.ts +0 -87
- package/esm/funcs/callModel.js +0 -215
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { isOutputTextDeltaEvent, isReasoningDeltaEvent, isFunctionCallArgumentsDeltaEvent, isOutputItemAddedEvent, isOutputItemDoneEvent, isResponseCompletedEvent, isResponseFailedEvent, isResponseIncompleteEvent, isFunctionCallArgumentsDoneEvent, isOutputMessage, isFunctionCallOutputItem, isReasoningOutputItem, isWebSearchCallOutputItem, isFileSearchCallOutputItem, isImageGenerationCallOutputItem, isOutputTextPart, isRefusalPart, isFileCitationAnnotation, isURLCitationAnnotation, isFilePathAnnotation, } from './stream-type-guards.js';
|
|
1
2
|
/**
|
|
2
3
|
* Extract text deltas from responses stream events
|
|
3
4
|
*/
|
|
4
5
|
export async function* extractTextDeltas(stream) {
|
|
5
6
|
const consumer = stream.createConsumer();
|
|
6
7
|
for await (const event of consumer) {
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
yield deltaEvent.delta;
|
|
8
|
+
if (isOutputTextDeltaEvent(event)) {
|
|
9
|
+
if (event.delta) {
|
|
10
|
+
yield event.delta;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -18,10 +18,9 @@ export async function* extractTextDeltas(stream) {
|
|
|
18
18
|
export async function* extractReasoningDeltas(stream) {
|
|
19
19
|
const consumer = stream.createConsumer();
|
|
20
20
|
for await (const event of consumer) {
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
yield deltaEvent.delta;
|
|
21
|
+
if (isReasoningDeltaEvent(event)) {
|
|
22
|
+
if (event.delta) {
|
|
23
|
+
yield event.delta;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
}
|
|
@@ -32,22 +31,22 @@ export async function* extractReasoningDeltas(stream) {
|
|
|
32
31
|
export async function* extractToolDeltas(stream) {
|
|
33
32
|
const consumer = stream.createConsumer();
|
|
34
33
|
for await (const event of consumer) {
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
yield deltaEvent.delta;
|
|
34
|
+
if (isFunctionCallArgumentsDeltaEvent(event)) {
|
|
35
|
+
if (event.delta) {
|
|
36
|
+
yield event.delta;
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
42
|
+
* Core message stream builder - shared logic for both formats
|
|
43
|
+
* Accumulates text deltas and yields updates
|
|
46
44
|
*/
|
|
47
|
-
|
|
45
|
+
async function* buildMessageStreamCore(stream) {
|
|
48
46
|
const consumer = stream.createConsumer();
|
|
49
|
-
// Track the accumulated text
|
|
47
|
+
// Track the accumulated text and message info
|
|
50
48
|
let currentText = '';
|
|
49
|
+
let currentId = '';
|
|
51
50
|
let hasStarted = false;
|
|
52
51
|
for await (const event of consumer) {
|
|
53
52
|
if (!('type' in event)) {
|
|
@@ -55,36 +54,95 @@ export async function* buildMessageStream(stream) {
|
|
|
55
54
|
}
|
|
56
55
|
switch (event.type) {
|
|
57
56
|
case 'response.output_item.added': {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
if (isOutputItemAddedEvent(event)) {
|
|
58
|
+
if (event.item && isOutputMessage(event.item)) {
|
|
59
|
+
hasStarted = true;
|
|
60
|
+
currentText = '';
|
|
61
|
+
currentId = event.item.id;
|
|
62
|
+
}
|
|
62
63
|
}
|
|
63
64
|
break;
|
|
64
65
|
}
|
|
65
66
|
case 'response.output_text.delta': {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
if (isOutputTextDeltaEvent(event)) {
|
|
68
|
+
if (hasStarted && event.delta) {
|
|
69
|
+
currentText += event.delta;
|
|
70
|
+
yield {
|
|
71
|
+
type: 'delta',
|
|
72
|
+
text: currentText,
|
|
73
|
+
messageId: currentId,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
77
|
break;
|
|
76
78
|
}
|
|
77
79
|
case 'response.output_item.done': {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
if (isOutputItemDoneEvent(event)) {
|
|
81
|
+
if (event.item && isOutputMessage(event.item)) {
|
|
82
|
+
yield {
|
|
83
|
+
type: 'complete',
|
|
84
|
+
completeMessage: event.item,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
85
87
|
}
|
|
86
88
|
break;
|
|
87
89
|
}
|
|
90
|
+
case 'response.completed':
|
|
91
|
+
case 'response.failed':
|
|
92
|
+
case 'response.incomplete':
|
|
93
|
+
// Stream is complete, stop consuming
|
|
94
|
+
return;
|
|
95
|
+
default:
|
|
96
|
+
// Ignore other event types - this is intentionally not exhaustive
|
|
97
|
+
// as we only care about specific events for message building
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build incremental message updates from responses stream events
|
|
104
|
+
* Returns ResponsesOutputMessage (assistant/responses format)
|
|
105
|
+
*/
|
|
106
|
+
export async function* buildResponsesMessageStream(stream) {
|
|
107
|
+
for await (const update of buildMessageStreamCore(stream)) {
|
|
108
|
+
if (update.type === 'delta' && update.text !== undefined && update.messageId !== undefined) {
|
|
109
|
+
// Yield incremental update in ResponsesOutputMessage format
|
|
110
|
+
yield {
|
|
111
|
+
id: update.messageId,
|
|
112
|
+
type: 'message',
|
|
113
|
+
role: 'assistant',
|
|
114
|
+
status: 'in_progress',
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: 'output_text',
|
|
118
|
+
text: update.text,
|
|
119
|
+
annotations: [],
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else if (update.type === 'complete' && update.completeMessage) {
|
|
125
|
+
// Yield final complete message
|
|
126
|
+
yield update.completeMessage;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Build incremental message updates from responses stream events
|
|
132
|
+
* Returns AssistantMessage (chat format) instead of ResponsesOutputMessage
|
|
133
|
+
*/
|
|
134
|
+
export async function* buildMessageStream(stream) {
|
|
135
|
+
for await (const update of buildMessageStreamCore(stream)) {
|
|
136
|
+
if (update.type === 'delta' && update.text !== undefined) {
|
|
137
|
+
// Yield incremental update in chat format
|
|
138
|
+
yield {
|
|
139
|
+
role: 'assistant',
|
|
140
|
+
content: update.text,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
else if (update.type === 'complete' && update.completeMessage) {
|
|
144
|
+
// Yield final complete message converted to chat format
|
|
145
|
+
yield convertToAssistantMessage(update.completeMessage);
|
|
88
146
|
}
|
|
89
147
|
}
|
|
90
148
|
}
|
|
@@ -97,19 +155,16 @@ export async function consumeStreamForCompletion(stream) {
|
|
|
97
155
|
if (!('type' in event)) {
|
|
98
156
|
continue;
|
|
99
157
|
}
|
|
100
|
-
if (event
|
|
101
|
-
|
|
102
|
-
return completedEvent.response;
|
|
158
|
+
if (isResponseCompletedEvent(event)) {
|
|
159
|
+
return event.response;
|
|
103
160
|
}
|
|
104
|
-
if (event
|
|
105
|
-
const failedEvent = event;
|
|
161
|
+
if (isResponseFailedEvent(event)) {
|
|
106
162
|
// The failed event contains the full response with error information
|
|
107
|
-
throw new Error(`Response failed: ${JSON.stringify(
|
|
163
|
+
throw new Error(`Response failed: ${JSON.stringify(event.response.error)}`);
|
|
108
164
|
}
|
|
109
|
-
if (event
|
|
110
|
-
const incompleteEvent = event;
|
|
165
|
+
if (isResponseIncompleteEvent(event)) {
|
|
111
166
|
// Return the incomplete response
|
|
112
|
-
return
|
|
167
|
+
return event.response;
|
|
113
168
|
}
|
|
114
169
|
}
|
|
115
170
|
throw new Error('Stream ended without completion event');
|
|
@@ -129,7 +184,7 @@ function convertToAssistantMessage(outputMessage) {
|
|
|
129
184
|
};
|
|
130
185
|
}
|
|
131
186
|
/**
|
|
132
|
-
* Extract the first message from a completed response
|
|
187
|
+
* Extract the first message from a completed response (chat format)
|
|
133
188
|
*/
|
|
134
189
|
export function extractMessageFromResponse(response) {
|
|
135
190
|
const messageItem = response.output.find((item) => 'type' in item && item.type === 'message');
|
|
@@ -138,6 +193,16 @@ export function extractMessageFromResponse(response) {
|
|
|
138
193
|
}
|
|
139
194
|
return convertToAssistantMessage(messageItem);
|
|
140
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Extract the first message from a completed response (responses format)
|
|
198
|
+
*/
|
|
199
|
+
export function extractResponsesMessageFromResponse(response) {
|
|
200
|
+
const messageItem = response.output.find((item) => 'type' in item && item.type === 'message');
|
|
201
|
+
if (!messageItem) {
|
|
202
|
+
throw new Error('No message found in response output');
|
|
203
|
+
}
|
|
204
|
+
return messageItem;
|
|
205
|
+
}
|
|
141
206
|
/**
|
|
142
207
|
* Extract text from a response, either from outputText or by concatenating message content
|
|
143
208
|
*/
|
|
@@ -146,6 +211,12 @@ export function extractTextFromResponse(response) {
|
|
|
146
211
|
if (response.outputText) {
|
|
147
212
|
return response.outputText;
|
|
148
213
|
}
|
|
214
|
+
// Check if there's a message in the output
|
|
215
|
+
const hasMessage = response.output.some((item) => 'type' in item && item.type === 'message');
|
|
216
|
+
if (!hasMessage) {
|
|
217
|
+
// No message in response (e.g., only function calls)
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
149
220
|
// Otherwise, extract from the first message (convert to AssistantMessage which has string content)
|
|
150
221
|
const message = extractMessageFromResponse(response);
|
|
151
222
|
// AssistantMessage.content is string | Array | null | undefined
|
|
@@ -161,22 +232,22 @@ export function extractTextFromResponse(response) {
|
|
|
161
232
|
export function extractToolCallsFromResponse(response) {
|
|
162
233
|
const toolCalls = [];
|
|
163
234
|
for (const item of response.output) {
|
|
164
|
-
if (
|
|
165
|
-
const functionCallItem = item;
|
|
235
|
+
if (isFunctionCallOutputItem(item)) {
|
|
166
236
|
try {
|
|
167
|
-
const parsedArguments = JSON.parse(
|
|
237
|
+
const parsedArguments = JSON.parse(item.arguments);
|
|
168
238
|
toolCalls.push({
|
|
169
|
-
id:
|
|
170
|
-
name:
|
|
239
|
+
id: item.callId,
|
|
240
|
+
name: item.name,
|
|
171
241
|
arguments: parsedArguments,
|
|
172
242
|
});
|
|
173
243
|
}
|
|
174
|
-
catch (
|
|
244
|
+
catch (error) {
|
|
245
|
+
console.warn(`Failed to parse tool call arguments for ${item.name}:`, error instanceof Error ? error.message : String(error), `\nArguments: ${item.arguments.substring(0, 100)}${item.arguments.length > 100 ? '...' : ''}`);
|
|
175
246
|
// Include the tool call with unparsed arguments
|
|
176
247
|
toolCalls.push({
|
|
177
|
-
id:
|
|
178
|
-
name:
|
|
179
|
-
arguments:
|
|
248
|
+
id: item.callId,
|
|
249
|
+
name: item.name,
|
|
250
|
+
arguments: item.arguments, // Keep as string if parsing fails
|
|
180
251
|
});
|
|
181
252
|
}
|
|
182
253
|
}
|
|
@@ -197,75 +268,72 @@ export async function* buildToolCallStream(stream) {
|
|
|
197
268
|
}
|
|
198
269
|
switch (event.type) {
|
|
199
270
|
case 'response.output_item.added': {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
id: functionCallItem.callId,
|
|
205
|
-
name: functionCallItem.name,
|
|
271
|
+
if (isOutputItemAddedEvent(event) && event.item && isFunctionCallOutputItem(event.item)) {
|
|
272
|
+
toolCallsInProgress.set(event.item.callId, {
|
|
273
|
+
id: event.item.callId,
|
|
274
|
+
name: event.item.name,
|
|
206
275
|
argumentsAccumulated: '',
|
|
207
276
|
});
|
|
208
277
|
}
|
|
209
278
|
break;
|
|
210
279
|
}
|
|
211
280
|
case 'response.function_call_arguments.delta': {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
281
|
+
if (isFunctionCallArgumentsDeltaEvent(event)) {
|
|
282
|
+
const toolCall = toolCallsInProgress.get(event.itemId);
|
|
283
|
+
if (toolCall && event.delta) {
|
|
284
|
+
toolCall.argumentsAccumulated += event.delta;
|
|
285
|
+
}
|
|
216
286
|
}
|
|
217
287
|
break;
|
|
218
288
|
}
|
|
219
289
|
case 'response.function_call_arguments.done': {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
290
|
+
if (isFunctionCallArgumentsDoneEvent(event)) {
|
|
291
|
+
const toolCall = toolCallsInProgress.get(event.itemId);
|
|
292
|
+
if (toolCall) {
|
|
293
|
+
// Parse complete arguments
|
|
294
|
+
try {
|
|
295
|
+
const parsedArguments = JSON.parse(event.arguments);
|
|
296
|
+
yield {
|
|
297
|
+
id: toolCall.id,
|
|
298
|
+
name: event.name,
|
|
299
|
+
arguments: parsedArguments,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
console.warn(`Failed to parse tool call arguments for ${event.name}:`, error instanceof Error ? error.message : String(error), `\nArguments: ${event.arguments.substring(0, 100)}${event.arguments.length > 100 ? '...' : ''}`);
|
|
304
|
+
// Yield with unparsed arguments if parsing fails
|
|
305
|
+
yield {
|
|
306
|
+
id: toolCall.id,
|
|
307
|
+
name: event.name,
|
|
308
|
+
arguments: event.arguments,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
// Clean up
|
|
312
|
+
toolCallsInProgress.delete(event.itemId);
|
|
239
313
|
}
|
|
240
|
-
// Clean up
|
|
241
|
-
toolCallsInProgress.delete(doneEvent.itemId);
|
|
242
314
|
}
|
|
243
315
|
break;
|
|
244
316
|
}
|
|
245
317
|
case 'response.output_item.done': {
|
|
246
|
-
|
|
247
|
-
if (itemDoneEvent.item &&
|
|
248
|
-
'type' in itemDoneEvent.item &&
|
|
249
|
-
itemDoneEvent.item.type === 'function_call') {
|
|
250
|
-
const functionCallItem = itemDoneEvent.item;
|
|
318
|
+
if (isOutputItemDoneEvent(event) && event.item && isFunctionCallOutputItem(event.item)) {
|
|
251
319
|
// Yield final tool call if we haven't already
|
|
252
|
-
if (toolCallsInProgress.has(
|
|
320
|
+
if (toolCallsInProgress.has(event.item.callId)) {
|
|
253
321
|
try {
|
|
254
|
-
const parsedArguments = JSON.parse(
|
|
322
|
+
const parsedArguments = JSON.parse(event.item.arguments);
|
|
255
323
|
yield {
|
|
256
|
-
id:
|
|
257
|
-
name:
|
|
324
|
+
id: event.item.callId,
|
|
325
|
+
name: event.item.name,
|
|
258
326
|
arguments: parsedArguments,
|
|
259
327
|
};
|
|
260
328
|
}
|
|
261
329
|
catch (_error) {
|
|
262
330
|
yield {
|
|
263
|
-
id:
|
|
264
|
-
name:
|
|
265
|
-
arguments:
|
|
331
|
+
id: event.item.callId,
|
|
332
|
+
name: event.item.name,
|
|
333
|
+
arguments: event.item.arguments,
|
|
266
334
|
};
|
|
267
335
|
}
|
|
268
|
-
toolCallsInProgress.delete(
|
|
336
|
+
toolCallsInProgress.delete(event.item.callId);
|
|
269
337
|
}
|
|
270
338
|
}
|
|
271
339
|
break;
|
|
@@ -279,4 +347,305 @@ export async function* buildToolCallStream(stream) {
|
|
|
279
347
|
export function responseHasToolCalls(response) {
|
|
280
348
|
return response.output.some((item) => 'type' in item && item.type === 'function_call');
|
|
281
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* Convert OpenRouter annotations to Claude citations
|
|
352
|
+
*/
|
|
353
|
+
function mapAnnotationsToCitations(annotations) {
|
|
354
|
+
if (!annotations || annotations.length === 0) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
const citations = [];
|
|
358
|
+
for (const annotation of annotations) {
|
|
359
|
+
if (!('type' in annotation)) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
switch (annotation.type) {
|
|
363
|
+
case 'file_citation': {
|
|
364
|
+
if (isFileCitationAnnotation(annotation)) {
|
|
365
|
+
citations.push({
|
|
366
|
+
type: 'char_location',
|
|
367
|
+
cited_text: '',
|
|
368
|
+
document_index: annotation.index,
|
|
369
|
+
document_title: annotation.filename,
|
|
370
|
+
file_id: annotation.fileId,
|
|
371
|
+
start_char_index: 0,
|
|
372
|
+
end_char_index: 0,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
case 'url_citation': {
|
|
378
|
+
if (isURLCitationAnnotation(annotation)) {
|
|
379
|
+
citations.push({
|
|
380
|
+
type: 'web_search_result_location',
|
|
381
|
+
cited_text: '',
|
|
382
|
+
title: annotation.title,
|
|
383
|
+
url: annotation.url,
|
|
384
|
+
encrypted_index: '',
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
case 'file_path': {
|
|
390
|
+
if (isFilePathAnnotation(annotation)) {
|
|
391
|
+
citations.push({
|
|
392
|
+
type: 'char_location',
|
|
393
|
+
cited_text: '',
|
|
394
|
+
document_index: annotation.index,
|
|
395
|
+
document_title: '',
|
|
396
|
+
file_id: annotation.fileId,
|
|
397
|
+
start_char_index: 0,
|
|
398
|
+
end_char_index: 0,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
default: {
|
|
404
|
+
// Exhaustiveness check - TypeScript will error if we don't handle all annotation types
|
|
405
|
+
const exhaustiveCheck = annotation;
|
|
406
|
+
// Cast to unknown for runtime debugging if type system bypassed
|
|
407
|
+
// This should never execute - throw with JSON of the unhandled value
|
|
408
|
+
throw new Error(`Unhandled annotation type. This indicates a new annotation type was added. ` +
|
|
409
|
+
`Annotation: ${JSON.stringify(exhaustiveCheck)}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return citations.length > 0 ? citations : undefined;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Map OpenResponses status to Claude stop reason
|
|
417
|
+
*/
|
|
418
|
+
function mapStopReason(response) {
|
|
419
|
+
// Check if any tool calls exist in the response
|
|
420
|
+
const hasToolCalls = response.output.some((item) => 'type' in item && item.type === 'function_call');
|
|
421
|
+
if (hasToolCalls) {
|
|
422
|
+
return 'tool_use';
|
|
423
|
+
}
|
|
424
|
+
// Check the response status
|
|
425
|
+
if (response.status === 'completed') {
|
|
426
|
+
return 'end_turn';
|
|
427
|
+
}
|
|
428
|
+
if (response.status === 'incomplete') {
|
|
429
|
+
// Check incomplete reason if available
|
|
430
|
+
const incompleteReason = response.incompleteDetails?.reason;
|
|
431
|
+
if (incompleteReason === 'max_output_tokens') {
|
|
432
|
+
return 'max_tokens';
|
|
433
|
+
}
|
|
434
|
+
return 'end_turn';
|
|
435
|
+
}
|
|
436
|
+
return 'end_turn';
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Convert OpenResponsesNonStreamingResponse to ClaudeMessage format
|
|
440
|
+
* Compatible with the Anthropic SDK BetaMessage type
|
|
441
|
+
*/
|
|
442
|
+
export function convertToClaudeMessage(response) {
|
|
443
|
+
const content = [];
|
|
444
|
+
const unsupportedContent = [];
|
|
445
|
+
for (const item of response.output) {
|
|
446
|
+
if (!('type' in item)) {
|
|
447
|
+
// Handle items without type field
|
|
448
|
+
// Convert unknown item to a record format for storage
|
|
449
|
+
const itemData = typeof item === 'object' && item !== null
|
|
450
|
+
? item
|
|
451
|
+
: { value: item };
|
|
452
|
+
unsupportedContent.push({
|
|
453
|
+
original_type: 'unknown',
|
|
454
|
+
data: itemData,
|
|
455
|
+
reason: 'Output item missing type field',
|
|
456
|
+
});
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
switch (item.type) {
|
|
460
|
+
case 'message': {
|
|
461
|
+
if (isOutputMessage(item)) {
|
|
462
|
+
for (const part of item.content) {
|
|
463
|
+
if (!('type' in part)) {
|
|
464
|
+
// Convert unknown part to a record format for storage
|
|
465
|
+
const partData = typeof part === 'object' && part !== null
|
|
466
|
+
? part
|
|
467
|
+
: { value: part };
|
|
468
|
+
unsupportedContent.push({
|
|
469
|
+
original_type: 'unknown_message_part',
|
|
470
|
+
data: partData,
|
|
471
|
+
reason: 'Message content part missing type field',
|
|
472
|
+
});
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (isOutputTextPart(part)) {
|
|
476
|
+
const citations = mapAnnotationsToCitations(part.annotations);
|
|
477
|
+
content.push({
|
|
478
|
+
type: 'text',
|
|
479
|
+
text: part.text,
|
|
480
|
+
...(citations && {
|
|
481
|
+
citations,
|
|
482
|
+
}),
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else if (isRefusalPart(part)) {
|
|
486
|
+
unsupportedContent.push({
|
|
487
|
+
original_type: 'refusal',
|
|
488
|
+
data: {
|
|
489
|
+
refusal: part.refusal,
|
|
490
|
+
},
|
|
491
|
+
reason: 'Claude does not have a native refusal content type',
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
// Exhaustiveness check - TypeScript will error if we don't handle all part types
|
|
496
|
+
const exhaustiveCheck = part;
|
|
497
|
+
// This should never execute - new content type was added
|
|
498
|
+
throw new Error(`Unhandled message content type. This indicates a new content type was added. ` +
|
|
499
|
+
`Part: ${JSON.stringify(exhaustiveCheck)}`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
case 'function_call': {
|
|
506
|
+
if (isFunctionCallOutputItem(item)) {
|
|
507
|
+
let parsedInput;
|
|
508
|
+
try {
|
|
509
|
+
parsedInput = JSON.parse(item.arguments);
|
|
510
|
+
}
|
|
511
|
+
catch (error) {
|
|
512
|
+
console.warn(`Failed to parse tool call arguments for ${item.name}:`, error instanceof Error ? error.message : String(error), `\nArguments: ${item.arguments.substring(0, 100)}${item.arguments.length > 100 ? '...' : ''}`);
|
|
513
|
+
// Preserve raw arguments if JSON parsing fails
|
|
514
|
+
parsedInput = {
|
|
515
|
+
_raw_arguments: item.arguments,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
content.push({
|
|
519
|
+
type: 'tool_use',
|
|
520
|
+
id: item.callId,
|
|
521
|
+
name: item.name,
|
|
522
|
+
input: parsedInput,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
case 'reasoning': {
|
|
528
|
+
if (isReasoningOutputItem(item)) {
|
|
529
|
+
if (item.summary && item.summary.length > 0) {
|
|
530
|
+
for (const summaryItem of item.summary) {
|
|
531
|
+
if (summaryItem.type === 'summary_text' && summaryItem.text) {
|
|
532
|
+
content.push({
|
|
533
|
+
type: 'thinking',
|
|
534
|
+
thinking: summaryItem.text,
|
|
535
|
+
signature: '',
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (item.encryptedContent) {
|
|
541
|
+
unsupportedContent.push({
|
|
542
|
+
original_type: 'reasoning_encrypted',
|
|
543
|
+
data: {
|
|
544
|
+
id: item.id,
|
|
545
|
+
encrypted_content: item.encryptedContent,
|
|
546
|
+
},
|
|
547
|
+
reason: 'Encrypted reasoning content preserved for round-trip',
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case 'web_search_call': {
|
|
554
|
+
if (isWebSearchCallOutputItem(item)) {
|
|
555
|
+
content.push({
|
|
556
|
+
type: 'server_tool_use',
|
|
557
|
+
id: item.id,
|
|
558
|
+
name: 'web_search',
|
|
559
|
+
input: {
|
|
560
|
+
status: item.status,
|
|
561
|
+
},
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
case 'file_search_call': {
|
|
567
|
+
if (isFileSearchCallOutputItem(item)) {
|
|
568
|
+
content.push({
|
|
569
|
+
type: 'tool_use',
|
|
570
|
+
id: item.id,
|
|
571
|
+
name: 'file_search',
|
|
572
|
+
input: {
|
|
573
|
+
queries: item.queries,
|
|
574
|
+
status: item.status,
|
|
575
|
+
},
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
case 'image_generation_call': {
|
|
581
|
+
if (isImageGenerationCallOutputItem(item)) {
|
|
582
|
+
unsupportedContent.push({
|
|
583
|
+
original_type: 'image_generation_call',
|
|
584
|
+
data: {
|
|
585
|
+
id: item.id,
|
|
586
|
+
result: item.result,
|
|
587
|
+
status: item.status,
|
|
588
|
+
},
|
|
589
|
+
reason: 'Claude does not support image outputs in assistant messages',
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
default: {
|
|
595
|
+
// Exhaustiveness check - if a new output type is added, TypeScript will error here
|
|
596
|
+
const exhaustiveCheck = item;
|
|
597
|
+
// This line should never execute - it means a new type was added to the union
|
|
598
|
+
// Throw an error instead of silently continuing to ensure we catch new types
|
|
599
|
+
throw new Error(`Unhandled output item type. This indicates a new output type was added to the API. ` +
|
|
600
|
+
`Item: ${JSON.stringify(exhaustiveCheck)}`);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
id: response.id,
|
|
606
|
+
type: 'message',
|
|
607
|
+
role: 'assistant',
|
|
608
|
+
model: response.model ?? 'unknown',
|
|
609
|
+
content,
|
|
610
|
+
stop_reason: mapStopReason(response),
|
|
611
|
+
stop_sequence: null,
|
|
612
|
+
usage: {
|
|
613
|
+
input_tokens: response.usage?.inputTokens ?? 0,
|
|
614
|
+
output_tokens: response.usage?.outputTokens ?? 0,
|
|
615
|
+
cache_creation_input_tokens: response.usage?.inputTokensDetails?.cachedTokens ?? 0,
|
|
616
|
+
cache_read_input_tokens: 0,
|
|
617
|
+
},
|
|
618
|
+
...(unsupportedContent.length > 0 && {
|
|
619
|
+
unsupported_content: unsupportedContent,
|
|
620
|
+
}),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Extract unsupported content by original type
|
|
625
|
+
*/
|
|
626
|
+
export function extractUnsupportedContent(message, originalType) {
|
|
627
|
+
if (!message.unsupported_content) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
return message.unsupported_content.filter((item) => item.original_type === originalType);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Check if message has any unsupported content
|
|
634
|
+
*/
|
|
635
|
+
export function hasUnsupportedContent(message) {
|
|
636
|
+
return !!(message.unsupported_content && message.unsupported_content.length > 0);
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Get summary of unsupported content types
|
|
640
|
+
*/
|
|
641
|
+
export function getUnsupportedContentSummary(message) {
|
|
642
|
+
if (!message.unsupported_content) {
|
|
643
|
+
return {};
|
|
644
|
+
}
|
|
645
|
+
const summary = {};
|
|
646
|
+
for (const item of message.unsupported_content) {
|
|
647
|
+
summary[item.original_type] = (summary[item.original_type] || 0) + 1;
|
|
648
|
+
}
|
|
649
|
+
return summary;
|
|
650
|
+
}
|
|
282
651
|
//# sourceMappingURL=stream-transformers.js.map
|