|
| 1 | +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +// snippet-start:[Bedrock.ConverseTool.javascriptv3.SendConverseRequest] |
| 5 | + |
| 6 | +// This example demonstrates how to send a conversation of messages to Amazon Nova using Bedrock's Converse API with a tool configuration. |
| 7 | +// It shows how to: |
| 8 | +// - 1. Set up the Amazon Bedrock runtime client |
| 9 | +// - 2. Define the parameters required enable Amazon Bedrock to use a tool when formulating its response (model ID, user input, system prompt, and the tool spec) |
| 10 | +// - 3. Send the request to Amazon Bedrock, and returns the response. |
| 11 | +// - 4. Add the tool response to the conversation, and send it back to Amazon Bedrock. |
| 12 | +// - 5. Publish the response. |
| 13 | + |
| 14 | +import { |
| 15 | + BedrockRuntimeClient, |
| 16 | + ConverseCommand, |
| 17 | +} from "@aws-sdk/client-bedrock-runtime"; |
| 18 | + |
| 19 | +// Step 1: Create the Amazon Bedrock runtime client |
| 20 | + |
| 21 | +// Credentials will be automatically loaded from the environment |
| 22 | +const bedRockRuntimeClient = new BedrockRuntimeClient({ |
| 23 | + region: "us-east-1", |
| 24 | +}); |
| 25 | + |
| 26 | +// Step 2. Define the parameters required enable Amazon Bedrock to use a tool when formulating its response. |
| 27 | + |
| 28 | +// The Bedrock Model ID. |
| 29 | +const modelId = "amazon.nova-lite-v1:0"; |
| 30 | + |
| 31 | +// The system prompt to help Amazon Bedrock craft it's response. |
| 32 | +const system_prompt = [ |
| 33 | + { |
| 34 | + text: |
| 35 | + "You are a music expert that provides the most popular song played on a radio station, using only the\n" + |
| 36 | + "the top_song tool, which he call sign for the radio station for which you want the most popular song. " + |
| 37 | + "Example calls signs are WZPZ and WKRP. \n" + |
| 38 | + "- Only use the top_song tool. Never guess or make up information. \n" + |
| 39 | + "- If the tool errors, apologize, explain weather is unavailable, and suggest other options.\n" + |
| 40 | + "- Only respond to queries about the most popular song played on a radio station\n" + |
| 41 | + "Remind off-topic users of your purpose. \n" + |
| 42 | + "- Never claim to search online, access external data, or use tools besides the top_song tool.\n", |
| 43 | + }, |
| 44 | +]; |
| 45 | +// The user's question. |
| 46 | +const message = [ |
| 47 | + { |
| 48 | + role: "user", |
| 49 | + content: [{ text: "What is the most popular song on WZPZ?" }], |
| 50 | + }, |
| 51 | +]; |
| 52 | +// The tool specification. In this case, it uses an example schema for |
| 53 | +// a tool that gets the most popular song played on a radio station. |
| 54 | +const tool_config = { |
| 55 | + tools: [ |
| 56 | + { |
| 57 | + toolSpec: { |
| 58 | + name: "top_song", |
| 59 | + description: "Get the most popular song played on a radio station.", |
| 60 | + inputSchema: { |
| 61 | + json: { |
| 62 | + type: "object", |
| 63 | + properties: { |
| 64 | + sign: { |
| 65 | + type: "string", |
| 66 | + description: |
| 67 | + "The call sign for the radio station for which you want the most popular song. Example calls signs are WZPZ and WKRP.", |
| 68 | + }, |
| 69 | + }, |
| 70 | + required: ["sign"], |
| 71 | + }, |
| 72 | + }, |
| 73 | + }, |
| 74 | + }, |
| 75 | + ], |
| 76 | +}; |
| 77 | + |
| 78 | +// Helper function to return the song and artist from top_song tool. |
| 79 | +async function get_top_song(call_sign) { |
| 80 | + try { |
| 81 | + if (call_sign === "WZPZ") { |
| 82 | + const song = "Elemental Hotel"; |
| 83 | + const artist = "8 Storey Hike"; |
| 84 | + return { song, artist }; |
| 85 | + } |
| 86 | + } catch (error) { |
| 87 | + console.log(`${error.message}`); |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +// 3. Send the request to Amazon Bedrock, and returns the response. |
| 92 | +export async function SendConversationtoBedrock( |
| 93 | + modelId, |
| 94 | + message, |
| 95 | + system_prompt, |
| 96 | + tool_config, |
| 97 | +) { |
| 98 | + try { |
| 99 | + const response = await bedRockRuntimeClient.send( |
| 100 | + new ConverseCommand({ |
| 101 | + modelId: modelId, |
| 102 | + messages: message, |
| 103 | + system: system_prompt, |
| 104 | + toolConfig: tool_config, |
| 105 | + }), |
| 106 | + ); |
| 107 | + if (response.stopReason === "tool_use") { |
| 108 | + const toolResultFinal = []; |
| 109 | + try { |
| 110 | + const output_message = response.output.message; |
| 111 | + message.push(output_message); |
| 112 | + const toolRequests = output_message.content; |
| 113 | + const toolMessage = toolRequests[0].text; |
| 114 | + console.log(toolMessage.replace(/<[^>]+>/g, "")); |
| 115 | + for (const toolRequest of toolRequests) { |
| 116 | + if (Object.hasOwn(toolRequest, "toolUse")) { |
| 117 | + const toolUse = toolRequest.toolUse; |
| 118 | + const sign = toolUse.input.sign; |
| 119 | + const toolUseID = toolUse.toolUseId; |
| 120 | + console.log( |
| 121 | + `Requesting tool ${toolUse.name}, Tool use id ${toolUseID}`, |
| 122 | + ); |
| 123 | + if (toolUse.name === "top_song") { |
| 124 | + const toolResult = []; |
| 125 | + try { |
| 126 | + const top_song = await get_top_song(toolUse.input.sign).then( |
| 127 | + (top_song) => top_song, |
| 128 | + ); |
| 129 | + const toolResult = { |
| 130 | + toolResult: { |
| 131 | + toolUseId: toolUseID, |
| 132 | + content: [ |
| 133 | + { |
| 134 | + json: { song: top_song.song, artist: top_song.artist }, |
| 135 | + }, |
| 136 | + ], |
| 137 | + }, |
| 138 | + }; |
| 139 | + toolResultFinal.push(toolResult); |
| 140 | + } catch (err) { |
| 141 | + const toolResult = { |
| 142 | + toolUseId: toolUseID, |
| 143 | + content: [{ json: { text: err.message } }], |
| 144 | + status: "error", |
| 145 | + }; |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | + } |
| 150 | + const toolResultMessage = { |
| 151 | + role: "user", |
| 152 | + content: toolResultFinal, |
| 153 | + }; |
| 154 | + // Step 4. Add the tool response to the conversation, and send it back to Amazon Bedrock. |
| 155 | + |
| 156 | + message.push(toolResultMessage); |
| 157 | + await SendConversationtoBedrock( |
| 158 | + modelId, |
| 159 | + message, |
| 160 | + system_prompt, |
| 161 | + tool_config, |
| 162 | + ); |
| 163 | + } catch (caught) { |
| 164 | + console.error(`${caught.message}`); |
| 165 | + throw caught; |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + // 4. Publish the response. |
| 170 | + if (response.stopReason === "end_turn") { |
| 171 | + const finalMessage = response.output.message.content[0].text; |
| 172 | + const messageToPrint = finalMessage.replace(/<[^>]+>/g); |
| 173 | + console.log(messageToPrint.replace(/<[^>]+>/g)); |
| 174 | + return messageToPrint; |
| 175 | + } |
| 176 | + } catch (caught) { |
| 177 | + if (caught.name === "ModelNotReady") { |
| 178 | + console.log( |
| 179 | + `${caught.name} - Model not ready, please wait and try again.`, |
| 180 | + ); |
| 181 | + throw caught; |
| 182 | + } |
| 183 | + if (caught.name === "BedrockRuntimeException") { |
| 184 | + console.log( |
| 185 | + `${caught.name} - Error occurred while sending Converse request`, |
| 186 | + ); |
| 187 | + throw caught; |
| 188 | + } |
| 189 | + } |
| 190 | +} |
| 191 | +await SendConversationtoBedrock(modelId, message, system_prompt, tool_config); |
| 192 | + |
| 193 | +// snippet-end:[Bedrock.ConverseTool.javascriptv3.SendConverseRequest] |
0 commit comments