wirejs-deploy-amplify-basic 0.0.162 → 0.0.164-llm

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.
@@ -213,6 +213,18 @@ const apiUrl = backend.api.resources.lambda.addFunctionUrl({
213
213
  });
214
214
  apiUrl.grantInvokeUrl(new AnyPrincipal());
215
215
 
216
+ backend.api.resources.lambda.addToRolePolicy(new PolicyStatement({
217
+ actions: [
218
+ 'bedrock:InvokeModel',
219
+ 'bedrock:InvokeModelWithResponseStream'
220
+ ],
221
+ resources: [
222
+ 'arn:aws:bedrock:*::foundation-model/*',
223
+ 'arn:aws:bedrock:*:*:custom-model/*'
224
+ ]
225
+ }));
226
+
227
+
216
228
  backend.addOutput({
217
229
  custom: {
218
230
  api: apiUrl.url
@@ -60,7 +60,7 @@ export class RealtimeService extends Construct {
60
60
  const iamProvider: AppSyncAuthProvider = { authorizationType: IAM };
61
61
 
62
62
  realtimeService = new EventApi(this, 'realtime', {
63
- apiName: `${props.appId}-${props.branchId}-realtime-api`,
63
+ apiName: `${props.appId.slice(0, 18)}-${props.branchId.slice(0, 18)}-realtime-api`,
64
64
  authorizationConfig: {
65
65
  authProviders: [iamProvider, lambdaProvider],
66
66
  connectionAuthModeTypes: [LAMBDA],
@@ -3,6 +3,6 @@
3
3
  "dependencies": {
4
4
  "jsdom": "^25.0.1",
5
5
  "wirejs-dom": "^1.0.42",
6
- "wirejs-resources": "^0.1.130"
6
+ "wirejs-resources": "^0.1.132-llm"
7
7
  }
8
8
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from 'wirejs-resources';
2
2
  export { FileService } from './services/file.js';
3
3
  export { AuthenticationService } from './services/authentication.js';
4
+ export { LLM } from './services/llm.js';
4
5
  export { DistributedTable } from './resources/distributed-table.js';
5
6
  export { RealtimeService } from './services/realtime.js';
6
7
  export { BackgroundJob } from './resources/background-job.js';
package/dist/index.js CHANGED
@@ -6,6 +6,8 @@ import { FileService } from './services/file.js';
6
6
  export { FileService } from './services/file.js';
7
7
  import { AuthenticationService } from './services/authentication.js';
8
8
  export { AuthenticationService } from './services/authentication.js';
9
+ import { LLM } from './services/llm.js';
10
+ export { LLM } from './services/llm.js';
9
11
  import { DistributedTable } from './resources/distributed-table.js';
10
12
  export { DistributedTable } from './resources/distributed-table.js';
11
13
  import { RealtimeService } from './services/realtime.js';
@@ -21,3 +23,4 @@ overrides.FileService = FileService;
21
23
  overrides.RealtimeService = RealtimeService;
22
24
  overrides.BackgroundJob = BackgroundJob;
23
25
  overrides.Endpoint = Endpoint;
26
+ overrides.LLM = LLM;
@@ -0,0 +1,14 @@
1
+ import { LLM as BaseLLM, LLMMessage, LLMChunk, Resource } from 'wirejs-resources';
2
+ export declare class LLM extends BaseLLM {
3
+ private bedrockClient;
4
+ constructor(scope: Resource | string, id: string, options: {
5
+ models: string[];
6
+ });
7
+ private createBedrockInstructionMessage;
8
+ private convertToBedrockFormat;
9
+ private getModelId;
10
+ private invokeBedrock;
11
+ private streamBedrock;
12
+ private invokeModel;
13
+ continueConversation(history: LLMMessage[], onChunk?: (chunk: LLMChunk) => void | Promise<void>): Promise<LLMMessage>;
14
+ }
@@ -0,0 +1,152 @@
1
+ import { LLM as BaseLLM } from 'wirejs-resources';
2
+ import { BedrockRuntimeClient, InvokeModelCommand, InvokeModelWithResponseStreamCommand } from '@aws-sdk/client-bedrock-runtime';
3
+ import { defaultProvider } from '@aws-sdk/credential-provider-node';
4
+ export class LLM extends BaseLLM {
5
+ bedrockClient;
6
+ constructor(scope, id, options) {
7
+ super(scope, id, options);
8
+ this.models = options.models;
9
+ this.bedrockClient = new BedrockRuntimeClient({
10
+ credentials: defaultProvider(),
11
+ });
12
+ }
13
+ createBedrockInstructionMessage(message) {
14
+ return {
15
+ role: 'assistant',
16
+ content: message
17
+ };
18
+ }
19
+ convertToBedrockFormat(messages) {
20
+ return messages.map(msg => ({
21
+ role: msg.role === 'user' ? 'user' : 'assistant',
22
+ content: msg.content
23
+ }));
24
+ }
25
+ getModelId(model) {
26
+ // small set of convenience identifier aliases. maybe worth breaking out into
27
+ // a larger, shared, canonical JSON later?
28
+ const modelMap = {
29
+ 'claude': 'anthropic.claude-3-haiku-20240307-v1:0',
30
+ 'claude-haiku': 'anthropic.claude-3-haiku-20240307-v1:0',
31
+ 'claude-sonnet': 'anthropic.claude-3-sonnet-20240229-v1:0',
32
+ 'claude-opus': 'anthropic.claude-3-opus-20240229-v1:0',
33
+ 'llama2': 'meta.llama2-70b-chat-v1',
34
+ 'llama3': 'meta.llama3-70b-instruct-v1:0',
35
+ };
36
+ return modelMap[model] || model;
37
+ }
38
+ async invokeBedrock(modelId, messages, stream) {
39
+ const body = JSON.stringify({
40
+ anthropic_version: "bedrock-2023-05-31",
41
+ max_tokens: 10000,
42
+ messages: this.convertToBedrockFormat(messages)
43
+ });
44
+ if (stream) {
45
+ const command = new InvokeModelWithResponseStreamCommand({
46
+ modelId,
47
+ body,
48
+ contentType: 'application/json',
49
+ accept: 'application/json'
50
+ });
51
+ return await this.bedrockClient.send(command);
52
+ }
53
+ else {
54
+ const command = new InvokeModelCommand({
55
+ modelId,
56
+ body,
57
+ contentType: 'application/json',
58
+ accept: 'application/json'
59
+ });
60
+ return await this.bedrockClient.send(command);
61
+ }
62
+ }
63
+ async streamBedrock(response, onChunk) {
64
+ let content = '';
65
+ if (response.body) {
66
+ for await (const chunk of response.body) {
67
+ if (chunk.chunk?.bytes) {
68
+ const data = JSON.parse(new TextDecoder().decode(chunk.chunk.bytes));
69
+ if (data.delta?.text) {
70
+ content += data.delta.text;
71
+ const llmChunk = {
72
+ created_at: new Date().toISOString(),
73
+ message: {
74
+ role: 'assistant',
75
+ content: data.delta.text
76
+ },
77
+ done: false
78
+ };
79
+ if (onChunk) {
80
+ try {
81
+ await onChunk(llmChunk);
82
+ }
83
+ catch (error) {
84
+ console.error(error);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ return {
92
+ role: 'assistant',
93
+ content
94
+ };
95
+ }
96
+ async invokeModel(model, history, onChunk, maxRetries = 10) {
97
+ const stream = typeof onChunk === 'function';
98
+ for (let i = 0; i < maxRetries; i++) {
99
+ try {
100
+ const modelId = this.getModelId(model);
101
+ const response = await this.invokeBedrock(modelId, history, stream);
102
+ if (stream) {
103
+ return this.streamBedrock(response, onChunk);
104
+ }
105
+ else {
106
+ const data = JSON.parse(new TextDecoder().decode(response.body));
107
+ return {
108
+ role: 'assistant',
109
+ content: data.content?.[0]?.text || 'No response generated'
110
+ };
111
+ }
112
+ }
113
+ catch (error) {
114
+ if (error.name === 'ThrottlingException') {
115
+ console.warn(`ThrottlingException encountered for model ${model}. Retrying...`);
116
+ await new Promise(resolve => setTimeout(resolve, i * 1000 + Math.random() * 1000));
117
+ continue;
118
+ }
119
+ else {
120
+ throw error;
121
+ }
122
+ }
123
+ }
124
+ throw new Error("Exceeded max retries trying to invoke " + model);
125
+ }
126
+ async continueConversation(history, onChunk) {
127
+ // models are expected to be given in priority order. first one that doesn't
128
+ // throw a fit wins.
129
+ for (const model of this.models) {
130
+ try {
131
+ return await this.invokeModel(model, history, onChunk);
132
+ }
133
+ catch (error) {
134
+ console.log(error);
135
+ if (error.name === 'ValidationException' && error.message?.includes('model')) {
136
+ continue;
137
+ }
138
+ if (error.name === 'AccessDeniedException') {
139
+ continue;
140
+ }
141
+ }
142
+ }
143
+ return this.createBedrockInstructionMessage(`None of the attempted are not available or not enabled in your AWS account. ` +
144
+ `Please enable it in the AWS Bedrock console:\n\n` +
145
+ `1. Go to AWS Bedrock Console (https://console.aws.amazon.com/bedrock/)\n` +
146
+ `2. Navigate to "Model access"\n` +
147
+ `3. Request access to the model\n` +
148
+ `4. Accept the End User License Agreement (EULA)\n\n` +
149
+ `Available models attempted: ${this.models.join(', ')}\n` +
150
+ `You may need to enable these models: ${this.models.map(m => this.getModelId(m)).join(', ')}`);
151
+ }
152
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wirejs-deploy-amplify-basic",
3
- "version": "0.0.162",
3
+ "version": "0.0.164-llm",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@aws-crypto/sha256-js": "^5.2.0",
31
+ "@aws-sdk/client-bedrock-runtime": "^3.821.0",
31
32
  "@aws-sdk/client-cognito-identity-provider": "^3.741.0",
32
33
  "@aws-sdk/client-dynamodb": "^3.774.0",
33
34
  "@aws-sdk/client-s3": "^3.738.0",
@@ -42,7 +43,7 @@
42
43
  "recursive-copy": "^2.0.14",
43
44
  "rimraf": "^6.0.1",
44
45
  "wirejs-dom": "^1.0.42",
45
- "wirejs-resources": "^0.1.130"
46
+ "wirejs-resources": "^0.1.132-llm"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@aws-amplify/backend": "^1.14.0",