ai-functions 2.1.3 → 2.4.0
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +90 -1
- package/README.md +38 -0
- package/dist/ai-promise.d.ts +3 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +135 -64
- package/dist/ai-promise.js.map +1 -1
- package/dist/ai-schemas.d.ts +56 -0
- package/dist/ai-schemas.d.ts.map +1 -0
- package/dist/ai-schemas.js +53 -0
- package/dist/ai-schemas.js.map +1 -0
- package/dist/ai.d.ts +16 -242
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +51 -858
- package/dist/ai.js.map +1 -1
- package/dist/batch/anthropic.d.ts +6 -4
- package/dist/batch/anthropic.d.ts.map +1 -1
- package/dist/batch/anthropic.js +83 -145
- package/dist/batch/anthropic.js.map +1 -1
- package/dist/batch/bedrock.d.ts +8 -30
- package/dist/batch/bedrock.d.ts.map +1 -1
- package/dist/batch/bedrock.js +155 -338
- package/dist/batch/bedrock.js.map +1 -1
- package/dist/batch/cloudflare.d.ts +8 -20
- package/dist/batch/cloudflare.d.ts.map +1 -1
- package/dist/batch/cloudflare.js +68 -189
- package/dist/batch/cloudflare.js.map +1 -1
- package/dist/batch/google.d.ts +6 -20
- package/dist/batch/google.d.ts.map +1 -1
- package/dist/batch/google.js +70 -238
- package/dist/batch/google.js.map +1 -1
- package/dist/batch/index.d.ts +4 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +4 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/memory.d.ts +1 -1
- package/dist/batch/memory.d.ts.map +1 -1
- package/dist/batch/memory.js +14 -10
- package/dist/batch/memory.js.map +1 -1
- package/dist/batch/openai.d.ts +11 -14
- package/dist/batch/openai.d.ts.map +1 -1
- package/dist/batch/openai.js +52 -156
- package/dist/batch/openai.js.map +1 -1
- package/dist/batch/provider.d.ts +111 -0
- package/dist/batch/provider.d.ts.map +1 -0
- package/dist/batch/provider.js +233 -0
- package/dist/batch/provider.js.map +1 -0
- package/dist/batch-map.d.ts.map +1 -1
- package/dist/batch-map.js +23 -17
- package/dist/batch-map.js.map +1 -1
- package/dist/batch-queue.d.ts +65 -0
- package/dist/batch-queue.d.ts.map +1 -1
- package/dist/batch-queue.js +169 -14
- package/dist/batch-queue.js.map +1 -1
- package/dist/budget.d.ts.map +1 -1
- package/dist/budget.js +27 -14
- package/dist/budget.js.map +1 -1
- package/dist/cache.d.ts +23 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +36 -15
- package/dist/cache.js.map +1 -1
- package/dist/context.d.ts +26 -8
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -62
- package/dist/context.js.map +1 -1
- package/dist/digital-objects-registry.d.ts +229 -0
- package/dist/digital-objects-registry.d.ts.map +1 -0
- package/dist/digital-objects-registry.js +617 -0
- package/dist/digital-objects-registry.js.map +1 -0
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/eval/runner.d.ts +8 -0
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +41 -35
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval-log/in-memory.d.ts +34 -0
- package/dist/eval-log/in-memory.d.ts.map +1 -0
- package/dist/eval-log/in-memory.js +84 -0
- package/dist/eval-log/in-memory.js.map +1 -0
- package/dist/eval-log/index.d.ts +29 -0
- package/dist/eval-log/index.d.ts.map +1 -0
- package/dist/eval-log/index.js +39 -0
- package/dist/eval-log/index.js.map +1 -0
- package/dist/eval-log/types.d.ts +101 -0
- package/dist/eval-log/types.d.ts.map +1 -0
- package/dist/eval-log/types.js +16 -0
- package/dist/eval-log/types.js.map +1 -0
- package/dist/function-registry.d.ts +176 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +685 -0
- package/dist/function-registry.js.map +1 -0
- package/dist/generate.d.ts +9 -3
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +18 -18
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -18
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +118 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/budget.d.ts +84 -0
- package/dist/middleware/budget.d.ts.map +1 -0
- package/dist/middleware/budget.js +110 -0
- package/dist/middleware/budget.js.map +1 -0
- package/dist/middleware/cache.d.ts +103 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +228 -0
- package/dist/middleware/cache.js.map +1 -0
- package/dist/middleware/embed-cache.d.ts +99 -0
- package/dist/middleware/embed-cache.d.ts.map +1 -0
- package/dist/middleware/embed-cache.js +128 -0
- package/dist/middleware/embed-cache.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/trace.d.ts +103 -0
- package/dist/middleware/trace.d.ts.map +1 -0
- package/dist/middleware/trace.js +176 -0
- package/dist/middleware/trace.js.map +1 -0
- package/dist/primitives.d.ts +120 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +398 -26
- package/dist/primitives.js.map +1 -1
- package/dist/retry.d.ts +66 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +115 -8
- package/dist/retry.js.map +1 -1
- package/dist/sandbox.d.ts +36 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +44 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/schema.js +2 -2
- package/dist/schema.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +285 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +6 -1
- package/dist/template.js.map +1 -1
- package/dist/tool-orchestration.d.ts +66 -4
- package/dist/tool-orchestration.d.ts.map +1 -1
- package/dist/tool-orchestration.js +123 -23
- package/dist/tool-orchestration.js.map +1 -1
- package/dist/type-guards.d.ts +28 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +29 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +155 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +36 -1
- package/dist/types.js.map +1 -1
- package/dist/wrap-for-v3.d.ts +80 -0
- package/dist/wrap-for-v3.d.ts.map +1 -0
- package/dist/wrap-for-v3.js +89 -0
- package/dist/wrap-for-v3.js.map +1 -0
- package/examples/00-quickstart.ts +232 -0
- package/examples/01-rag-chatbot.ts +212 -0
- package/examples/02-multi-agent-research.ts +290 -0
- package/examples/03-email-classification.ts +379 -0
- package/examples/04-content-moderation.ts +400 -0
- package/examples/05-document-extraction.ts +455 -0
- package/examples/06-streaming-chat-nextjs.ts +437 -0
- package/examples/07-cloudflare-worker.ts +483 -0
- package/examples/08-batch-processing.ts +491 -0
- package/examples/09-budget-constrained.ts +527 -0
- package/examples/10-tool-orchestration.ts +565 -0
- package/examples/11-retry-resilience.ts +403 -0
- package/examples/12-caching-strategies.ts +422 -0
- package/examples/README.md +145 -0
- package/package.json +29 -25
- package/src/ai-promise.ts +226 -140
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +71 -1176
- package/src/batch/anthropic.ts +96 -161
- package/src/batch/bedrock.ts +203 -454
- package/src/batch/cloudflare.ts +99 -282
- package/src/batch/google.ts +91 -297
- package/src/batch/index.ts +4 -1
- package/src/batch/memory.ts +15 -10
- package/src/batch/openai.ts +65 -193
- package/src/batch/provider.ts +336 -0
- package/src/batch-map.ts +29 -24
- package/src/batch-queue.ts +200 -11
- package/src/budget.ts +31 -18
- package/src/cache.ts +45 -17
- package/src/context.ts +106 -77
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +60 -36
- package/src/eval-log/in-memory.ts +90 -0
- package/src/eval-log/index.ts +46 -0
- package/src/eval-log/types.ts +110 -0
- package/src/function-registry.ts +874 -0
- package/src/generate.ts +33 -28
- package/src/index.ts +122 -21
- package/src/logger.ts +232 -0
- package/src/middleware/budget.ts +171 -0
- package/src/middleware/cache.ts +299 -0
- package/src/middleware/embed-cache.ts +195 -0
- package/src/middleware/index.ts +23 -0
- package/src/middleware/trace.ts +248 -0
- package/src/primitives.ts +589 -62
- package/src/retry.ts +144 -18
- package/src/sandbox.ts +52 -0
- package/src/schema.ts +8 -8
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +213 -48
- package/src/type-guards.ts +31 -0
- package/src/types.ts +186 -27
- package/src/wrap-for-v3.ts +105 -0
- package/test/ai-promise.test.ts +1080 -0
- package/test/ai-proxy.test.ts +1 -1
- package/test/batch-autosubmit-errors.test.ts +49 -37
- package/test/batch-blog-posts.test.ts +87 -129
- package/test/core-functions.test.ts +183 -579
- package/test/decide.test.ts +154 -322
- package/test/define.test.ts +211 -8
- package/test/digital-objects-registry.test.ts +760 -0
- package/test/embedding-cache-middleware.test.ts +140 -0
- package/test/fill-template.test.ts +89 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/sandbox-execution.test.ts +155 -0
- package/test/schema.test.ts +55 -19
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +270 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- package/LICENSE +0 -21
- package/dist/rpc/auth.d.ts +0 -69
- package/dist/rpc/auth.d.ts.map +0 -1
- package/dist/rpc/auth.js +0 -136
- package/dist/rpc/auth.js.map +0 -1
- package/dist/rpc/client.d.ts +0 -62
- package/dist/rpc/client.d.ts.map +0 -1
- package/dist/rpc/client.js +0 -103
- package/dist/rpc/client.js.map +0 -1
- package/dist/rpc/deferred.d.ts +0 -60
- package/dist/rpc/deferred.d.ts.map +0 -1
- package/dist/rpc/deferred.js +0 -96
- package/dist/rpc/deferred.js.map +0 -1
- package/dist/rpc/index.d.ts +0 -22
- package/dist/rpc/index.d.ts.map +0 -1
- package/dist/rpc/index.js +0 -38
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/local.d.ts +0 -42
- package/dist/rpc/local.d.ts.map +0 -1
- package/dist/rpc/local.js +0 -50
- package/dist/rpc/local.js.map +0 -1
- package/dist/rpc/server.d.ts +0 -165
- package/dist/rpc/server.d.ts.map +0 -1
- package/dist/rpc/server.js +0 -405
- package/dist/rpc/server.js.map +0 -1
- package/dist/rpc/session.d.ts +0 -32
- package/dist/rpc/session.d.ts.map +0 -1
- package/dist/rpc/session.js +0 -43
- package/dist/rpc/session.js.map +0 -1
- package/dist/rpc/transport.d.ts +0 -306
- package/dist/rpc/transport.d.ts.map +0 -1
- package/dist/rpc/transport.js +0 -731
- package/dist/rpc/transport.js.map +0 -1
- package/src/batch/anthropic.js +0 -256
- package/src/batch/bedrock.js +0 -584
- package/src/batch/cloudflare.js +0 -287
- package/src/batch/google.js +0 -359
- package/src/batch/index.js +0 -30
- package/src/batch/memory.js +0 -187
- package/src/batch/openai.js +0 -402
- package/src/eval/index.js +0 -7
- package/src/eval/models.js +0 -119
- package/src/eval/runner.js +0 -147
- package/test/schema.test.js +0 -96
package/dist/batch/bedrock.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AWS Bedrock Batch Inference Adapter
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Bedrock has a true batch inference API (S3-driven) and a runtime invoke API.
|
|
5
|
+
* The "batch" adapter here uses concurrent runtime invocations as a fallback
|
|
6
|
+
* (no S3 setup required); `createBedrockBatchJob` is exported separately for
|
|
7
|
+
* callers who want to drive the real S3-based batch flow directly.
|
|
6
8
|
*
|
|
7
9
|
* @see https://docs.aws.amazon.com/bedrock/latest/userguide/batch-inference.html
|
|
8
10
|
*
|
|
9
11
|
* @packageDocumentation
|
|
10
12
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
+
import { getLogger } from '../logger.js';
|
|
14
|
+
import { LocalJobStore, processConcurrently, registerBatchAdapter, registerFlexAdapter, tryParseJson, } from './provider.js';
|
|
13
15
|
// ============================================================================
|
|
14
|
-
// AWS
|
|
16
|
+
// AWS configuration
|
|
15
17
|
// ============================================================================
|
|
16
18
|
let awsRegion;
|
|
17
19
|
let awsAccessKeyId;
|
|
@@ -19,12 +21,9 @@ let awsSecretAccessKey;
|
|
|
19
21
|
let awsSessionToken;
|
|
20
22
|
let s3Bucket;
|
|
21
23
|
let roleArn;
|
|
22
|
-
// AI Gateway configuration (optional - for routing through Cloudflare AI Gateway)
|
|
23
24
|
let gatewayUrl;
|
|
24
25
|
let gatewayToken;
|
|
25
|
-
/**
|
|
26
|
-
* Configure AWS credentials and settings
|
|
27
|
-
*/
|
|
26
|
+
/** Configure AWS credentials and settings. */
|
|
28
27
|
export function configureAWSBedrock(options) {
|
|
29
28
|
if (options.region)
|
|
30
29
|
awsRegion = options.region;
|
|
@@ -44,16 +43,14 @@ export function configureAWSBedrock(options) {
|
|
|
44
43
|
gatewayToken = options.gatewayToken;
|
|
45
44
|
}
|
|
46
45
|
function getConfig() {
|
|
47
|
-
const region = awsRegion || process.env
|
|
48
|
-
const accessKeyId = awsAccessKeyId || process.env
|
|
49
|
-
const secretAccessKey = awsSecretAccessKey || process.env
|
|
50
|
-
const sessionToken = awsSessionToken || process.env
|
|
51
|
-
const bucket = s3Bucket || process.env
|
|
52
|
-
const role = roleArn || process.env
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const gwToken = gatewayToken || process.env.AI_GATEWAY_TOKEN;
|
|
56
|
-
// If using gateway, we don't need AWS credentials
|
|
46
|
+
const region = awsRegion || process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION'] || 'us-east-1';
|
|
47
|
+
const accessKeyId = awsAccessKeyId || process.env['AWS_ACCESS_KEY_ID'];
|
|
48
|
+
const secretAccessKey = awsSecretAccessKey || process.env['AWS_SECRET_ACCESS_KEY'];
|
|
49
|
+
const sessionToken = awsSessionToken || process.env['AWS_SESSION_TOKEN'];
|
|
50
|
+
const bucket = s3Bucket || process.env['BEDROCK_BATCH_S3_BUCKET'];
|
|
51
|
+
const role = roleArn || process.env['BEDROCK_BATCH_ROLE_ARN'];
|
|
52
|
+
const gwUrl = gatewayUrl || process.env['AI_GATEWAY_URL'];
|
|
53
|
+
const gwToken = gatewayToken || process.env['AI_GATEWAY_TOKEN'];
|
|
57
54
|
if (gwUrl && gwToken) {
|
|
58
55
|
return {
|
|
59
56
|
region,
|
|
@@ -72,14 +69,21 @@ function getConfig() {
|
|
|
72
69
|
if (!bucket) {
|
|
73
70
|
throw new Error('S3 bucket for Bedrock batch not configured. Set BEDROCK_BATCH_S3_BUCKET');
|
|
74
71
|
}
|
|
75
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
region,
|
|
74
|
+
accessKeyId,
|
|
75
|
+
secretAccessKey,
|
|
76
|
+
sessionToken,
|
|
77
|
+
bucket,
|
|
78
|
+
role,
|
|
79
|
+
gatewayUrl: undefined,
|
|
80
|
+
gatewayToken: undefined,
|
|
81
|
+
};
|
|
76
82
|
}
|
|
77
83
|
// ============================================================================
|
|
78
|
-
// AWS
|
|
84
|
+
// AWS SigV4 (delegated to optional @smithy/signature-v4 if available)
|
|
79
85
|
// ============================================================================
|
|
80
86
|
async function signRequest(method, url, body, config, service) {
|
|
81
|
-
// In production, use @aws-sdk/signature-v4 or similar
|
|
82
|
-
// This is a simplified implementation for demonstration
|
|
83
87
|
const headers = new Headers({
|
|
84
88
|
'Content-Type': 'application/json',
|
|
85
89
|
'X-Amz-Date': new Date().toISOString().replace(/[:-]|\.\d{3}/g, ''),
|
|
@@ -87,18 +91,13 @@ async function signRequest(method, url, body, config, service) {
|
|
|
87
91
|
if (config.sessionToken) {
|
|
88
92
|
headers.set('X-Amz-Security-Token', config.sessionToken);
|
|
89
93
|
}
|
|
90
|
-
// For actual implementation, compute proper AWS Signature V4
|
|
91
|
-
// This requires crypto operations that vary by environment
|
|
92
|
-
// Fallback: Use AWS SDK if available
|
|
93
94
|
try {
|
|
94
|
-
//
|
|
95
|
+
// Optional dependency — present in production, absent in dev/test.
|
|
95
96
|
// @ts-expect-error - Optional dependency
|
|
96
97
|
const signatureV4Module = await import('@smithy/signature-v4');
|
|
97
98
|
// @ts-expect-error - Optional dependency
|
|
98
99
|
const sha256Module = await import('@aws-crypto/sha256-js');
|
|
99
|
-
const
|
|
100
|
-
const Sha256 = sha256Module.Sha256;
|
|
101
|
-
const signer = new SignatureV4({
|
|
100
|
+
const signer = new signatureV4Module.SignatureV4({
|
|
102
101
|
service,
|
|
103
102
|
region: config.region,
|
|
104
103
|
credentials: {
|
|
@@ -106,7 +105,7 @@ async function signRequest(method, url, body, config, service) {
|
|
|
106
105
|
secretAccessKey: config.secretAccessKey,
|
|
107
106
|
sessionToken: config.sessionToken,
|
|
108
107
|
},
|
|
109
|
-
sha256: Sha256,
|
|
108
|
+
sha256: sha256Module.Sha256,
|
|
110
109
|
});
|
|
111
110
|
const signedRequest = await signer.sign({
|
|
112
111
|
method,
|
|
@@ -118,185 +117,140 @@ async function signRequest(method, url, body, config, service) {
|
|
|
118
117
|
return new Headers(signedRequest.headers);
|
|
119
118
|
}
|
|
120
119
|
catch {
|
|
121
|
-
|
|
122
|
-
// In production, the SDK should always be available
|
|
123
|
-
console.warn('AWS SDK not available for request signing. Install @smithy/signature-v4 and @aws-crypto/sha256-js');
|
|
120
|
+
getLogger().warn('AWS SDK not available for request signing. Install @smithy/signature-v4 and @aws-crypto/sha256-js');
|
|
124
121
|
return headers;
|
|
125
122
|
}
|
|
126
123
|
}
|
|
127
124
|
// ============================================================================
|
|
128
|
-
//
|
|
125
|
+
// Local job tracking
|
|
129
126
|
// ============================================================================
|
|
130
|
-
const
|
|
131
|
-
let jobCounter = 0;
|
|
127
|
+
const jobs = new LocalJobStore('bedrock_batch');
|
|
132
128
|
// ============================================================================
|
|
133
|
-
// Bedrock
|
|
129
|
+
// Bedrock batch adapter (BatchProvider port)
|
|
134
130
|
// ============================================================================
|
|
135
|
-
/**
|
|
136
|
-
* AWS Bedrock batch adapter
|
|
137
|
-
*
|
|
138
|
-
* Bedrock batch inference:
|
|
139
|
-
* 1. Uploads input JSONL to S3
|
|
140
|
-
* 2. Creates a batch inference job
|
|
141
|
-
* 3. Results are written to S3
|
|
142
|
-
* 4. Download and parse results
|
|
143
|
-
*
|
|
144
|
-
* Note: This requires S3 bucket access and proper IAM roles.
|
|
145
|
-
*/
|
|
146
131
|
const bedrockAdapter = {
|
|
147
132
|
async submit(items, options) {
|
|
148
133
|
const config = getConfig();
|
|
149
|
-
const jobId = `bedrock_batch_${++jobCounter}_${Date.now()}`;
|
|
150
|
-
// Default to Claude on Bedrock
|
|
151
134
|
const model = options.model || 'anthropic.claude-3-sonnet-20240229-v1:0';
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
results
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const completion = processBedrockRequestsConcurrently(jobId, items, config, model, options);
|
|
135
|
+
const { id, state } = jobs.create(items, options);
|
|
136
|
+
// Drive the job state machine in the background.
|
|
137
|
+
const completion = (async () => {
|
|
138
|
+
state.status = 'in_progress';
|
|
139
|
+
const results = await processConcurrently(items, (item) => processBedrockItem(item, config, model), {
|
|
140
|
+
concurrency: 5, // Bedrock has stricter rate limits.
|
|
141
|
+
delayBetweenWaves: 1000,
|
|
142
|
+
onWaveComplete: (partial) => {
|
|
143
|
+
state.results = partial;
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
state.results = results;
|
|
147
|
+
state.status = results.every((r) => r.status === 'completed') ? 'completed' : 'failed';
|
|
148
|
+
state.completedAt = new Date();
|
|
149
|
+
return results;
|
|
150
|
+
})();
|
|
169
151
|
const job = {
|
|
170
|
-
id
|
|
152
|
+
id,
|
|
171
153
|
provider: 'bedrock',
|
|
172
154
|
status: 'pending',
|
|
173
155
|
totalItems: items.length,
|
|
174
156
|
completedItems: 0,
|
|
175
157
|
failedItems: 0,
|
|
176
|
-
createdAt:
|
|
177
|
-
webhookUrl: options.webhookUrl,
|
|
158
|
+
createdAt: state.createdAt,
|
|
159
|
+
...(options.webhookUrl !== undefined && { webhookUrl: options.webhookUrl }),
|
|
178
160
|
};
|
|
179
161
|
return { job, completion };
|
|
180
162
|
},
|
|
181
163
|
async getStatus(batchId) {
|
|
182
|
-
|
|
183
|
-
if (!job) {
|
|
184
|
-
throw new Error(`Batch not found: ${batchId}`);
|
|
185
|
-
}
|
|
186
|
-
const completedItems = job.results.filter((r) => r.status === 'completed').length;
|
|
187
|
-
const failedItems = job.results.filter((r) => r.status === 'failed').length;
|
|
188
|
-
return {
|
|
189
|
-
id: batchId,
|
|
190
|
-
provider: 'bedrock',
|
|
191
|
-
status: job.status,
|
|
192
|
-
totalItems: job.items.length,
|
|
193
|
-
completedItems,
|
|
194
|
-
failedItems,
|
|
195
|
-
createdAt: job.createdAt,
|
|
196
|
-
completedAt: job.completedAt,
|
|
197
|
-
};
|
|
164
|
+
return jobs.snapshot(batchId, 'bedrock');
|
|
198
165
|
},
|
|
199
166
|
async cancel(batchId) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
167
|
+
if (!jobs.has(batchId))
|
|
168
|
+
return;
|
|
169
|
+
const state = jobs.get(batchId);
|
|
170
|
+
state.status = 'cancelled';
|
|
171
|
+
const jobArn = state.meta?.['jobArn'];
|
|
172
|
+
if (jobArn) {
|
|
173
|
+
const config = getConfig();
|
|
174
|
+
const url = `https://bedrock.${config.region}.amazonaws.com/model-invocation-job/${encodeURIComponent(jobArn)}/stop`;
|
|
175
|
+
try {
|
|
176
|
+
await fetch(url, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
headers: await signRequest('POST', url, '', config, 'bedrock'),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
getLogger().warn('Failed to cancel Bedrock job:', error);
|
|
216
183
|
}
|
|
217
184
|
}
|
|
218
185
|
},
|
|
219
186
|
async getResults(batchId) {
|
|
220
|
-
|
|
221
|
-
if (!job) {
|
|
222
|
-
throw new Error(`Batch not found: ${batchId}`);
|
|
223
|
-
}
|
|
224
|
-
return job.results;
|
|
187
|
+
return jobs.get(batchId).results;
|
|
225
188
|
},
|
|
226
189
|
async waitForCompletion(batchId, pollInterval = 5000) {
|
|
227
|
-
|
|
228
|
-
if (!job) {
|
|
229
|
-
throw new Error(`Batch not found: ${batchId}`);
|
|
230
|
-
}
|
|
231
|
-
while (job.status !== 'completed' && job.status !== 'failed' && job.status !== 'cancelled') {
|
|
232
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
233
|
-
}
|
|
234
|
-
return job.results;
|
|
190
|
+
return jobs.waitForCompletion(batchId, pollInterval);
|
|
235
191
|
},
|
|
236
192
|
};
|
|
237
193
|
// ============================================================================
|
|
238
|
-
//
|
|
194
|
+
// Per-item processing
|
|
239
195
|
// ============================================================================
|
|
240
|
-
/**
|
|
241
|
-
* Process Bedrock requests concurrently
|
|
242
|
-
* This is a fallback when true batch inference isn't configured
|
|
243
|
-
*/
|
|
244
|
-
async function processBedrockRequestsConcurrently(jobId, items, config, model, options) {
|
|
245
|
-
const job = pendingJobs.get(jobId);
|
|
246
|
-
if (!job) {
|
|
247
|
-
throw new Error(`Job not found: ${jobId}`);
|
|
248
|
-
}
|
|
249
|
-
job.status = 'in_progress';
|
|
250
|
-
// Process with concurrency limit
|
|
251
|
-
const CONCURRENCY = 5; // Bedrock has stricter rate limits
|
|
252
|
-
const results = [];
|
|
253
|
-
for (let i = 0; i < items.length; i += CONCURRENCY) {
|
|
254
|
-
const batch = items.slice(i, i + CONCURRENCY);
|
|
255
|
-
const batchResults = await Promise.all(batch.map(async (item) => {
|
|
256
|
-
try {
|
|
257
|
-
return await processBedrockItem(item, config, model);
|
|
258
|
-
}
|
|
259
|
-
catch (error) {
|
|
260
|
-
return {
|
|
261
|
-
id: item.id,
|
|
262
|
-
customId: item.id,
|
|
263
|
-
status: 'failed',
|
|
264
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
}));
|
|
268
|
-
results.push(...batchResults);
|
|
269
|
-
job.results = results;
|
|
270
|
-
// Respect rate limits
|
|
271
|
-
if (i + CONCURRENCY < items.length) {
|
|
272
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
job.status = results.every((r) => r.status === 'completed') ? 'completed' : 'failed';
|
|
276
|
-
job.completedAt = new Date();
|
|
277
|
-
return results;
|
|
278
|
-
}
|
|
279
196
|
async function processBedrockItem(item, config, model) {
|
|
280
|
-
// Check if using AI Gateway
|
|
281
197
|
if (config.gatewayUrl && config.gatewayToken) {
|
|
282
198
|
return processBedrockItemViaGateway(item, config, model);
|
|
283
199
|
}
|
|
284
200
|
const url = `https://bedrock-runtime.${config.region}.amazonaws.com/model/${encodeURIComponent(model)}/invoke`;
|
|
285
|
-
|
|
286
|
-
|
|
201
|
+
const body = buildBedrockRequestBody(item, model);
|
|
202
|
+
const bodyStr = JSON.stringify(body);
|
|
203
|
+
const headers = await signRequest('POST', url, bodyStr, config, 'bedrock');
|
|
204
|
+
const response = await fetch(url, { method: 'POST', headers, body: bodyStr });
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
const error = await response.text();
|
|
207
|
+
throw new Error(`Bedrock API error: ${response.status} ${error}`);
|
|
208
|
+
}
|
|
209
|
+
return parseBedrockResponse(item, await response.json());
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Process a Bedrock item via Cloudflare AI Gateway.
|
|
213
|
+
*
|
|
214
|
+
* Note: AI Gateway routes the request but doesn't handle authentication —
|
|
215
|
+
* Bedrock still requires AWS SigV4 signing.
|
|
216
|
+
* @see https://developers.cloudflare.com/ai-gateway/usage/providers/bedrock/
|
|
217
|
+
*/
|
|
218
|
+
async function processBedrockItemViaGateway(item, config, model) {
|
|
219
|
+
const url = `${config.gatewayUrl}/aws-bedrock/bedrock-runtime/${config.region}/model/${encodeURIComponent(model)}/invoke`;
|
|
220
|
+
const body = {
|
|
221
|
+
anthropic_version: 'bedrock-2023-05-31',
|
|
222
|
+
max_tokens: item.options?.maxTokens || 4096,
|
|
223
|
+
messages: [{ role: 'user', content: item.prompt }],
|
|
224
|
+
...(item.options?.system !== undefined && { system: item.options.system }),
|
|
225
|
+
...(item.options?.temperature !== undefined && { temperature: item.options.temperature }),
|
|
226
|
+
};
|
|
227
|
+
const bodyStr = JSON.stringify(body);
|
|
228
|
+
if (!config.accessKeyId || !config.secretAccessKey) {
|
|
229
|
+
throw new Error('Bedrock via AI Gateway still requires AWS credentials for SigV4 signing. ' +
|
|
230
|
+
'Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.');
|
|
231
|
+
}
|
|
232
|
+
const headers = await signRequest('POST', url, bodyStr, config, 'bedrock');
|
|
233
|
+
headers.set('cf-aig-authorization', `Bearer ${config.gatewayToken}`);
|
|
234
|
+
const response = await fetch(url, { method: 'POST', headers, body: bodyStr });
|
|
235
|
+
if (!response.ok) {
|
|
236
|
+
const error = await response.text();
|
|
237
|
+
throw new Error(`Bedrock via Gateway error: ${response.status} ${error}`);
|
|
238
|
+
}
|
|
239
|
+
return parseBedrockResponse(item, await response.json());
|
|
240
|
+
}
|
|
241
|
+
/** Build the Bedrock invoke body for the model family. */
|
|
242
|
+
function buildBedrockRequestBody(item, model) {
|
|
287
243
|
if (model.includes('anthropic')) {
|
|
288
|
-
|
|
289
|
-
body = {
|
|
244
|
+
return {
|
|
290
245
|
anthropic_version: 'bedrock-2023-05-31',
|
|
291
246
|
max_tokens: item.options?.maxTokens || 4096,
|
|
292
247
|
messages: [{ role: 'user', content: item.prompt }],
|
|
293
|
-
system: item.options
|
|
294
|
-
temperature: item.options
|
|
248
|
+
...(item.options?.system !== undefined && { system: item.options.system }),
|
|
249
|
+
...(item.options?.temperature !== undefined && { temperature: item.options.temperature }),
|
|
295
250
|
};
|
|
296
251
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
body = {
|
|
252
|
+
if (model.includes('amazon')) {
|
|
253
|
+
return {
|
|
300
254
|
inputText: item.prompt,
|
|
301
255
|
textGenerationConfig: {
|
|
302
256
|
maxTokenCount: item.options?.maxTokens || 4096,
|
|
@@ -304,50 +258,35 @@ async function processBedrockItem(item, config, model) {
|
|
|
304
258
|
},
|
|
305
259
|
};
|
|
306
260
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
body = {
|
|
261
|
+
if (model.includes('meta')) {
|
|
262
|
+
return {
|
|
310
263
|
prompt: item.prompt,
|
|
311
264
|
max_gen_len: item.options?.maxTokens || 4096,
|
|
312
265
|
temperature: item.options?.temperature || 0.7,
|
|
313
266
|
};
|
|
314
267
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
body = {
|
|
268
|
+
if (model.includes('mistral')) {
|
|
269
|
+
return {
|
|
318
270
|
prompt: `<s>[INST] ${item.prompt} [/INST]`,
|
|
319
271
|
max_tokens: item.options?.maxTokens || 4096,
|
|
320
272
|
temperature: item.options?.temperature || 0.7,
|
|
321
273
|
};
|
|
322
274
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
const response = await fetch(url, {
|
|
335
|
-
method: 'POST',
|
|
336
|
-
headers,
|
|
337
|
-
body: bodyStr,
|
|
338
|
-
});
|
|
339
|
-
if (!response.ok) {
|
|
340
|
-
const error = await response.text();
|
|
341
|
-
throw new Error(`Bedrock API error: ${response.status} ${error}`);
|
|
342
|
-
}
|
|
343
|
-
const data = await response.json();
|
|
344
|
-
// Extract content based on model response format
|
|
275
|
+
// Default: Claude-style.
|
|
276
|
+
return {
|
|
277
|
+
anthropic_version: 'bedrock-2023-05-31',
|
|
278
|
+
max_tokens: item.options?.maxTokens || 4096,
|
|
279
|
+
messages: [{ role: 'user', content: item.prompt }],
|
|
280
|
+
...(item.options?.temperature !== undefined && { temperature: item.options.temperature }),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/** Parse a Bedrock invoke response across model families. */
|
|
284
|
+
function parseBedrockResponse(item, raw) {
|
|
285
|
+
const data = raw;
|
|
345
286
|
let content;
|
|
346
287
|
let usage;
|
|
347
288
|
if (data.content) {
|
|
348
|
-
|
|
349
|
-
const textContent = data.content.find((c) => c.type === 'text');
|
|
350
|
-
content = textContent?.text;
|
|
289
|
+
content = data.content.find((c) => c.type === 'text')?.text;
|
|
351
290
|
if (data.usage) {
|
|
352
291
|
usage = {
|
|
353
292
|
promptTokens: data.usage.input_tokens,
|
|
@@ -357,16 +296,14 @@ async function processBedrockItem(item, config, model) {
|
|
|
357
296
|
}
|
|
358
297
|
}
|
|
359
298
|
else if (data.results?.[0]) {
|
|
360
|
-
// Titan format
|
|
361
299
|
content = data.results[0].outputText;
|
|
362
300
|
usage = {
|
|
363
|
-
promptTokens: 0,
|
|
301
|
+
promptTokens: 0,
|
|
364
302
|
completionTokens: data.results[0].tokenCount || 0,
|
|
365
303
|
totalTokens: data.results[0].tokenCount || 0,
|
|
366
304
|
};
|
|
367
305
|
}
|
|
368
306
|
else if (data.generation) {
|
|
369
|
-
// Llama/Mistral format
|
|
370
307
|
content = data.generation;
|
|
371
308
|
if (data.generation_token_count !== undefined) {
|
|
372
309
|
usage = {
|
|
@@ -376,103 +313,23 @@ async function processBedrockItem(item, config, model) {
|
|
|
376
313
|
};
|
|
377
314
|
}
|
|
378
315
|
}
|
|
379
|
-
let result = content;
|
|
380
|
-
// Try to parse JSON if schema was provided
|
|
381
|
-
if (item.schema && content) {
|
|
382
|
-
try {
|
|
383
|
-
result = JSON.parse(content);
|
|
384
|
-
}
|
|
385
|
-
catch {
|
|
386
|
-
// Keep as string
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
316
|
return {
|
|
390
317
|
id: item.id,
|
|
391
318
|
customId: item.id,
|
|
392
319
|
status: 'completed',
|
|
393
|
-
result,
|
|
394
|
-
usage,
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Process a Bedrock item via Cloudflare AI Gateway
|
|
399
|
-
*
|
|
400
|
-
* NOTE: Unlike OpenAI and Google, Bedrock via AI Gateway still requires AWS Signature V4 signing.
|
|
401
|
-
* The gateway routes the request but doesn't handle authentication.
|
|
402
|
-
* @see https://developers.cloudflare.com/ai-gateway/usage/providers/bedrock/
|
|
403
|
-
*
|
|
404
|
-
* Gateway URL format: {gateway_url}/aws-bedrock/bedrock-runtime/{region}/model/{model}/invoke
|
|
405
|
-
*/
|
|
406
|
-
async function processBedrockItemViaGateway(item, config, model) {
|
|
407
|
-
// AI Gateway URL for Bedrock - requires full path including region
|
|
408
|
-
// Format: {gateway_url}/aws-bedrock/bedrock-runtime/{region}/model/{model}/invoke
|
|
409
|
-
const url = `${config.gatewayUrl}/aws-bedrock/bedrock-runtime/${config.region}/model/${encodeURIComponent(model)}/invoke`;
|
|
410
|
-
// Build the request body (Anthropic format for Claude models)
|
|
411
|
-
const body = {
|
|
412
|
-
anthropic_version: 'bedrock-2023-05-31',
|
|
413
|
-
max_tokens: item.options?.maxTokens || 4096,
|
|
414
|
-
messages: [{ role: 'user', content: item.prompt }],
|
|
415
|
-
system: item.options?.system,
|
|
416
|
-
temperature: item.options?.temperature,
|
|
417
|
-
};
|
|
418
|
-
const bodyStr = JSON.stringify(body);
|
|
419
|
-
// NOTE: Bedrock via Gateway still requires AWS SigV4 signing
|
|
420
|
-
// We need both the gateway token AND AWS credentials
|
|
421
|
-
if (!config.accessKeyId || !config.secretAccessKey) {
|
|
422
|
-
throw new Error('Bedrock via AI Gateway still requires AWS credentials for SigV4 signing. ' +
|
|
423
|
-
'Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.');
|
|
424
|
-
}
|
|
425
|
-
const headers = await signRequest('POST', url, bodyStr, config, 'bedrock');
|
|
426
|
-
headers.set('cf-aig-authorization', `Bearer ${config.gatewayToken}`);
|
|
427
|
-
const response = await fetch(url, {
|
|
428
|
-
method: 'POST',
|
|
429
|
-
headers,
|
|
430
|
-
body: bodyStr,
|
|
431
|
-
});
|
|
432
|
-
if (!response.ok) {
|
|
433
|
-
const error = await response.text();
|
|
434
|
-
throw new Error(`Bedrock via Gateway error: ${response.status} ${error}`);
|
|
435
|
-
}
|
|
436
|
-
const data = await response.json();
|
|
437
|
-
// Extract content (Anthropic format)
|
|
438
|
-
const textContent = data.content?.find((c) => c.type === 'text');
|
|
439
|
-
let content = textContent?.text;
|
|
440
|
-
let usage;
|
|
441
|
-
if (data.usage) {
|
|
442
|
-
usage = {
|
|
443
|
-
promptTokens: data.usage.input_tokens,
|
|
444
|
-
completionTokens: data.usage.output_tokens,
|
|
445
|
-
totalTokens: data.usage.input_tokens + data.usage.output_tokens,
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
let result = content;
|
|
449
|
-
// Try to parse JSON if schema was provided
|
|
450
|
-
if (item.schema && content) {
|
|
451
|
-
try {
|
|
452
|
-
result = JSON.parse(content);
|
|
453
|
-
}
|
|
454
|
-
catch {
|
|
455
|
-
// Keep as string
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
return {
|
|
459
|
-
id: item.id,
|
|
460
|
-
customId: item.id,
|
|
461
|
-
status: 'completed',
|
|
462
|
-
result,
|
|
463
|
-
usage,
|
|
320
|
+
result: tryParseJson(content, !!item.schema),
|
|
321
|
+
...(usage && { usage }),
|
|
464
322
|
};
|
|
465
323
|
}
|
|
466
324
|
// ============================================================================
|
|
467
|
-
// True
|
|
325
|
+
// True S3-based batch inference (separate from the BatchProvider adapter)
|
|
468
326
|
// ============================================================================
|
|
469
327
|
/**
|
|
470
|
-
* Create and submit a true Bedrock batch inference job
|
|
471
|
-
*
|
|
328
|
+
* Create and submit a true Bedrock batch inference job.
|
|
329
|
+
* Requires S3 bucket access and proper IAM setup.
|
|
472
330
|
*/
|
|
473
331
|
export async function createBedrockBatchJob(items, model, options) {
|
|
474
332
|
const config = getConfig();
|
|
475
|
-
// Build JSONL content
|
|
476
333
|
const jsonlLines = items.map((item) => {
|
|
477
334
|
const request = {
|
|
478
335
|
recordId: item.id,
|
|
@@ -480,16 +337,16 @@ export async function createBedrockBatchJob(items, model, options) {
|
|
|
480
337
|
anthropic_version: 'bedrock-2023-05-31',
|
|
481
338
|
max_tokens: item.options?.maxTokens || 4096,
|
|
482
339
|
messages: [{ role: 'user', content: item.prompt }],
|
|
483
|
-
system: item.options
|
|
484
|
-
|
|
340
|
+
...(item.options?.system !== undefined && { system: item.options.system }),
|
|
341
|
+
...(item.options?.temperature !== undefined && {
|
|
342
|
+
temperature: item.options.temperature,
|
|
343
|
+
}),
|
|
485
344
|
},
|
|
486
345
|
};
|
|
487
346
|
return JSON.stringify(request);
|
|
488
347
|
});
|
|
489
348
|
const inputKey = `${options.s3InputPrefix || 'bedrock-batch/input'}/${options.jobName}.jsonl`;
|
|
490
349
|
const outputPrefix = `${options.s3OutputPrefix || 'bedrock-batch/output'}/${options.jobName}/`;
|
|
491
|
-
// Upload to S3
|
|
492
|
-
// In production, use @aws-sdk/client-s3
|
|
493
350
|
const s3Url = `https://${config.bucket}.s3.${config.region}.amazonaws.com/${inputKey}`;
|
|
494
351
|
const content = jsonlLines.join('\n');
|
|
495
352
|
const s3Response = await fetch(s3Url, {
|
|
@@ -500,21 +357,16 @@ export async function createBedrockBatchJob(items, model, options) {
|
|
|
500
357
|
if (!s3Response.ok) {
|
|
501
358
|
throw new Error(`Failed to upload to S3: ${s3Response.status}`);
|
|
502
359
|
}
|
|
503
|
-
// Create batch inference job
|
|
504
360
|
const jobUrl = `https://bedrock.${config.region}.amazonaws.com/model-invocation-job`;
|
|
505
361
|
const jobBody = JSON.stringify({
|
|
506
362
|
jobName: options.jobName,
|
|
507
363
|
modelId: model,
|
|
508
364
|
roleArn: options.roleArn,
|
|
509
365
|
inputDataConfig: {
|
|
510
|
-
s3InputDataConfig: {
|
|
511
|
-
s3Uri: `s3://${config.bucket}/${inputKey}`,
|
|
512
|
-
},
|
|
366
|
+
s3InputDataConfig: { s3Uri: `s3://${config.bucket}/${inputKey}` },
|
|
513
367
|
},
|
|
514
368
|
outputDataConfig: {
|
|
515
|
-
s3OutputDataConfig: {
|
|
516
|
-
s3Uri: `s3://${config.bucket}/${outputPrefix}`,
|
|
517
|
-
},
|
|
369
|
+
s3OutputDataConfig: { s3Uri: `s3://${config.bucket}/${outputPrefix}` },
|
|
518
370
|
},
|
|
519
371
|
});
|
|
520
372
|
const jobResponse = await fetch(jobUrl, {
|
|
@@ -526,59 +378,24 @@ export async function createBedrockBatchJob(items, model, options) {
|
|
|
526
378
|
const error = await jobResponse.text();
|
|
527
379
|
throw new Error(`Failed to create Bedrock batch job: ${jobResponse.status} ${error}`);
|
|
528
380
|
}
|
|
529
|
-
const jobData = await jobResponse.json();
|
|
381
|
+
const jobData = (await jobResponse.json());
|
|
530
382
|
return jobData;
|
|
531
383
|
}
|
|
532
384
|
// ============================================================================
|
|
533
|
-
//
|
|
534
|
-
// ============================================================================
|
|
385
|
+
// Bedrock flex adapter (FlexAdapter port)
|
|
535
386
|
// ============================================================================
|
|
536
|
-
// Bedrock Flex Adapter
|
|
537
|
-
// ============================================================================
|
|
538
|
-
/**
|
|
539
|
-
* AWS Bedrock Flex Adapter
|
|
540
|
-
*
|
|
541
|
-
* Flex processing uses concurrent requests for medium-sized batches (5-500 items).
|
|
542
|
-
* This provides a balance between:
|
|
543
|
-
* - Immediate execution (fast but full price, <5 items)
|
|
544
|
-
* - Full batch inference (50% discount but 24hr turnaround, 500+ items)
|
|
545
|
-
*
|
|
546
|
-
* Flex tier uses concurrent API calls with rate limiting, providing results
|
|
547
|
-
* in minutes rather than hours while still benefiting from efficient processing.
|
|
548
|
-
*/
|
|
549
387
|
const bedrockFlexAdapter = {
|
|
550
388
|
async submitFlex(items, options) {
|
|
551
389
|
const config = getConfig();
|
|
552
390
|
const model = options.model || 'anthropic.claude-3-sonnet-20240229-v1:0';
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
const batch = items.slice(i, i + CONCURRENCY);
|
|
558
|
-
const batchResults = await Promise.all(batch.map(async (item) => {
|
|
559
|
-
try {
|
|
560
|
-
return await processBedrockItem(item, config, model);
|
|
561
|
-
}
|
|
562
|
-
catch (error) {
|
|
563
|
-
return {
|
|
564
|
-
id: item.id,
|
|
565
|
-
customId: item.id,
|
|
566
|
-
status: 'failed',
|
|
567
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
}));
|
|
571
|
-
results.push(...batchResults);
|
|
572
|
-
// Add delay between batches to respect rate limits
|
|
573
|
-
if (i + CONCURRENCY < items.length) {
|
|
574
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
return results;
|
|
391
|
+
return processConcurrently(items, (item) => processBedrockItem(item, config, model), {
|
|
392
|
+
concurrency: 8,
|
|
393
|
+
delayBetweenWaves: 500,
|
|
394
|
+
});
|
|
578
395
|
},
|
|
579
396
|
};
|
|
580
397
|
// ============================================================================
|
|
581
|
-
// Register
|
|
398
|
+
// Register adapters
|
|
582
399
|
// ============================================================================
|
|
583
400
|
registerBatchAdapter('bedrock', bedrockAdapter);
|
|
584
401
|
registerFlexAdapter('bedrock', bedrockFlexAdapter);
|