@@ -11,6 +11,7 @@ export const endpointBedrockParametersSchema = z.object({
11
11
region : z . string ( ) . default ( "us-east-1" ) ,
12
12
model : z . any ( ) ,
13
13
anthropicVersion : z . string ( ) . default ( "bedrock-2023-05-31" ) ,
14
+ isNova : z . boolean ( ) . default ( false ) ,
14
15
multimodal : z
15
16
. object ( {
16
17
image : createImageProcessorOptionsValidator ( {
@@ -34,7 +35,7 @@ export const endpointBedrockParametersSchema = z.object({
34
35
export async function endpointBedrock (
35
36
input : z . input < typeof endpointBedrockParametersSchema >
36
37
) : Promise < Endpoint > {
37
- const { region, model, anthropicVersion, multimodal } =
38
+ const { region, model, anthropicVersion, multimodal, isNova } =
38
39
endpointBedrockParametersSchema . parse ( input ) ;
39
40
40
41
let BedrockRuntimeClient , InvokeModelWithResponseStreamCommand ;
@@ -59,24 +60,42 @@ export async function endpointBedrock(
59
60
messages = messages . slice ( 1 ) ; // Remove the first system message from the array
60
61
}
61
62
62
- const formattedMessages = await prepareMessages ( messages , imageProcessor ) ;
63
+ const formattedMessages = await prepareMessages ( messages , model . id , imageProcessor ) ;
63
64
64
65
let tokenId = 0 ;
65
66
const parameters = { ...model . parameters , ...generateSettings } ;
66
67
return ( async function * ( ) {
67
- const command = new InvokeModelWithResponseStreamCommand ( {
68
- body : Buffer . from (
69
- JSON . stringify ( {
70
- anthropic_version : anthropicVersion ,
71
- max_tokens : parameters . max_new_tokens ? parameters . max_new_tokens : 4096 ,
72
- messages : formattedMessages ,
73
- system,
74
- } ) ,
75
- "utf-8"
76
- ) ,
68
+ const baseCommandParams = {
77
69
contentType : "application/json" ,
78
70
accept : "application/json" ,
79
71
modelId : model . id ,
72
+ } ;
73
+
74
+ const maxTokens = parameters . max_new_tokens || 4096 ;
75
+
76
+ let bodyContent ;
77
+ if ( isNova ) {
78
+ bodyContent = {
79
+ messages : formattedMessages ,
80
+ inferenceConfig : {
81
+ maxTokens,
82
+ topP : 0.1 ,
83
+ temperature : 1.0 ,
84
+ } ,
85
+ system : [ { text : system } ] ,
86
+ } ;
87
+ } else {
88
+ bodyContent = {
89
+ anthropic_version : anthropicVersion ,
90
+ max_tokens : maxTokens ,
91
+ messages : formattedMessages ,
92
+ system,
93
+ } ;
94
+ }
95
+
96
+ const command = new InvokeModelWithResponseStreamCommand ( {
97
+ ...baseCommandParams ,
98
+ body : Buffer . from ( JSON . stringify ( bodyContent ) , "utf-8" ) ,
80
99
trace : "DISABLED" ,
81
100
} ) ;
82
101
@@ -86,21 +105,20 @@ export async function endpointBedrock(
86
105
87
106
for await ( const item of response . body ?? [ ] ) {
88
107
const chunk = JSON . parse ( new TextDecoder ( ) . decode ( item . chunk ?. bytes ) ) ;
89
- const chunk_type = chunk . type ;
90
-
91
- if ( chunk_type === "content_block_delta" ) {
92
- text += chunk . delta . text ;
108
+ if ( "contentBlockDelta" in chunk || chunk . type === "content_block_delta" ) {
109
+ const chunkText = chunk . contentBlockDelta ?. delta ?. text || chunk . delta ?. text || "" ;
110
+ text += chunkText ;
93
111
yield {
94
112
token : {
95
113
id : tokenId ++ ,
96
- text : chunk . delta . text ,
114
+ text : chunkText ,
97
115
logprob : 0 ,
98
116
special : false ,
99
117
} ,
100
118
generated_text : null ,
101
119
details : null ,
102
120
} satisfies TextGenerationStreamOutput ;
103
- } else if ( chunk_type === "message_stop" ) {
121
+ } else if ( "messageStop" in chunk || chunk . type === "message_stop" ) {
104
122
yield {
105
123
token : {
106
124
id : tokenId ++ ,
@@ -120,6 +138,7 @@ export async function endpointBedrock(
120
138
// Prepare the messages excluding system prompts
121
139
async function prepareMessages (
122
140
messages : EndpointMessage [ ] ,
141
+ isNova : boolean ,
123
142
imageProcessor : ReturnType < typeof makeImageProcessor >
124
143
) {
125
144
const formattedMessages = [ ] ;
@@ -128,9 +147,13 @@ async function prepareMessages(
128
147
const content = [ ] ;
129
148
130
149
if ( message . files ?. length ) {
131
- content . push ( ...( await prepareFiles ( imageProcessor , message . files ) ) ) ;
150
+ content . push ( ...( await prepareFiles ( imageProcessor , isNova , message . files ) ) ) ;
151
+ }
152
+ if ( isNova ) {
153
+ content . push ( { text : message . content } ) ;
154
+ } else {
155
+ content . push ( { type : "text" , text : message . content } ) ;
132
156
}
133
- content . push ( { type : "text" , text : message . content } ) ;
134
157
135
158
const lastMessage = formattedMessages [ formattedMessages . length - 1 ] ;
136
159
if ( lastMessage && lastMessage . role === message . from ) {
@@ -146,11 +169,22 @@ async function prepareMessages(
146
169
// Process files and convert them to base64 encoded strings
147
170
async function prepareFiles (
148
171
imageProcessor : ReturnType < typeof makeImageProcessor > ,
172
+ isNova : boolean ,
149
173
files : MessageFile [ ]
150
174
) {
151
175
const processedFiles = await Promise . all ( files . map ( imageProcessor ) ) ;
152
- return processedFiles . map ( ( file ) => ( {
153
- type : "image" ,
154
- source : { type : "base64" , media_type : "image/jpeg" , data : file . image . toString ( "base64" ) } ,
155
- } ) ) ;
176
+
177
+ if ( isNova ) {
178
+ return processedFiles . map ( ( file ) => ( {
179
+ image : {
180
+ format : file . mime . substring ( "image/" . length ) ,
181
+ source : { bytes : file . image . toString ( "base64" ) } ,
182
+ } ,
183
+ } ) ) ;
184
+ } else {
185
+ return processedFiles . map ( ( file ) => ( {
186
+ type : "image" ,
187
+ source : { type : "base64" , media_type : file . mime , data : file . image . toString ( "base64" ) } ,
188
+ } ) ) ;
189
+ }
156
190
}
0 commit comments