Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat (provider/amazon-bedrock): remove dependence on AWS SDK Bedrock library #4582

Open
wants to merge 37 commits into
base: main
Choose a base branch
from

Conversation

shaper
Copy link
Contributor

@shaper shaper commented Jan 29, 2025

  • tool calls
  • backwards-compatibility review
  • docs incl. bedrock request-id detail
  • fix CI failure
  • object generation
  • embed
  • validate bedrock request-id detail in responseHeaders

@shaper shaper changed the title feat (provider/amazon-bedrock): remove dependency on AWS SDK Bedrock … feat (provider/amazon-bedrock): remove dependency on AWS SDK Bedrock library Jan 29, 2025
@shaper shaper force-pushed the shaper/pr/bedrock-2a branch from d77b110 to d7c55ea Compare January 29, 2025 01:18
@shaper shaper force-pushed the shaper/pr/bedrock-2a branch from d7c55ea to 6b38a54 Compare January 29, 2025 01:48
@shaper shaper force-pushed the shaper/pr/bedrock-2a branch from 6b38a54 to ad9719a Compare February 1, 2025 07:47
@shaper shaper changed the title feat (provider/amazon-bedrock): remove dependency on AWS SDK Bedrock library feat (provider/amazon-bedrock): remove dependence on AWS SDK Bedrock library Feb 1, 2025
model: bedrock('anthropic.claude-3-haiku-20240307-v1:0'),
prompt: 'Invent a new holiday and describe its traditions.',
model: bedrock(
'arn:aws:bedrock:us-east-2:474668406012:inference-profile/us.anthropic.claude-3-5-sonnet-20240620-v1:0',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to ideally figure out how to make it backwards compatible, or we need to announce breaking changes somehow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proposal:

  • ship as a major version update
  • (breaking change) we removed BedrockOptions from the provider settings (updated documentation to note)
    • note unless we rename the environment variables to prefix with AI_SDK_ or similar, we continue to have the issue where folks could unknowingly inherit serverless runtime environment variables. Should we consider adding this prefix?
  • I am still reviewing the model-id/ARN discrepancy issue, and we will either make that transparent (preserve existing behavior) or update docs to reflect a change
  • we could improve backwards-compatibility a bit if we keep the old BedrockOptions for the credentials fields. Some folks were using that. Is it worth the extra code/complexity?

@shaper shaper marked this pull request as ready for review February 7, 2025 04:45
if (topK != null) {
warnings.push({
type: 'unsupported-setting',
setting: 'topK',
});
}

// TODO: validate this is still the case.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgrammel do you remember the backstory on this warning below?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably didn't work back then - let's test if it works now

@@ -5,7 +5,9 @@ import { z } from 'zod';

async function main() {
const result = await generateObject({
model: bedrock('anthropic.claude-3-5-sonnet-20240620-v1:0'),
model: bedrock(
`arn:aws:bedrock:${process.env.AWS_REGION}:${process.env.AWS_ACCOUNT_ID}:inference-profile/us.anthropic.claude-3-5-sonnet-20240620-v1:0`,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the simple ids here?

@@ -212,49 +220,50 @@ export class BedrockChatLanguageModel implements LanguageModelV1 {
toolName: part.toolUse?.name ?? `tool-${this.config.generateId()}`,
args: JSON.stringify(part.toolUse?.input ?? ''),
})),
finishReason: mapBedrockFinishReason(response.stopReason),
finishReason: mapBedrockFinishReason(
response.stopReason as BedrockStopReason,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the as needed here? shouldn't zod validation narrow the types correctly?

LanguageModelV1StreamPart
>({
stream: response.pipeThrough(
new TransformStream<ParseResult<any>, LanguageModelV1StreamPart>({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any should be replaced with the actual type from parsing. What is the type of the chunks? we are parsing with Zod?


// Process the message.
if (decoded.headers[':message-type']?.value === 'event') {
const data = new TextDecoder().decode(decoded.body);
Copy link
Collaborator

@lgrammel lgrammel Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract new TextDecoder(), this is most likely a hot loop and we could init it before the loop (i.e. outside of the transform stream)


// Wrap the data in the `:event-type` field to match the expected schema.
const parsedDataResult = safeParseJSON({ text: data });
let wrappedData;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push down to first use

};

// Re-parse with the expected schema.
const parsedWrappedData = safeParseJSON({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to JSON.stringify and parse again, use safeValidate instead

rawValue: parsedWrappedData.rawValue,
});
}
} catch (e) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the error be forward in some fashion?

Comment on lines +84 to +93
if (!parsedWrappedData.success) {
controller.enqueue(parsedWrappedData);
break;
}

controller.enqueue({
success: true,
value: parsedWrappedData.value,
rawValue: parsedWrappedData.rawValue,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't both cases the same, i.e. controller.enqueue(parsedWrappedData); is enough?

},
);
})}.amazonaws.com`,
) ?? '';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the ?? '' could hide errors

Comment on lines -76 to -93
accessKeyId: loadSetting({
settingValue: options.accessKeyId,
settingName: 'accessKeyId',
environmentVariableName: 'AWS_ACCESS_KEY_ID',
description: 'AWS access key ID',
}),
secretAccessKey: loadSetting({
settingValue: options.secretAccessKey,
settingName: 'secretAccessKey',
environmentVariableName: 'AWS_SECRET_ACCESS_KEY',
description: 'AWS secret access key',
}),
sessionToken: loadOptionalSetting({
settingValue: options.sessionToken,
environmentVariableName: 'AWS_SESSION_TOKEN',
}),
},
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still feel we are delaying errors by pushing this down but could be wrong.

Comment on lines +57 to +59
// TODO: explore avoiding the below stringify since we do it again at
// post-time and the content could be large with attachments.
body: JSON.stringify(body),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be worth resolving before landing considering attachments

would the fetch wrapper approach solve this?

Comment on lines +74 to +76
bytes: Buffer.from(
part.image ?? (part.image as Uint8Array),
).toString('base64'),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a helper for this in provider utils?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants