ai-functions 0.3.0 ā 0.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 +5 -0
- package/.turbo/turbo-test.log +105 -0
- package/README.md +190 -86
- package/TODO.md +138 -0
- package/dist/ai-promise.d.ts +219 -0
- package/dist/ai-promise.d.ts.map +1 -0
- package/dist/ai-promise.js +610 -0
- package/dist/ai-promise.js.map +1 -0
- package/dist/ai.d.ts +285 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +842 -0
- package/dist/ai.js.map +1 -0
- package/dist/batch/anthropic.d.ts +23 -0
- package/dist/batch/anthropic.d.ts.map +1 -0
- package/dist/batch/anthropic.js +257 -0
- package/dist/batch/anthropic.js.map +1 -0
- package/dist/batch/bedrock.d.ts +64 -0
- package/dist/batch/bedrock.d.ts.map +1 -0
- package/dist/batch/bedrock.js +586 -0
- package/dist/batch/bedrock.js.map +1 -0
- package/dist/batch/cloudflare.d.ts +37 -0
- package/dist/batch/cloudflare.d.ts.map +1 -0
- package/dist/batch/cloudflare.js +289 -0
- package/dist/batch/cloudflare.js.map +1 -0
- package/dist/batch/google.d.ts +41 -0
- package/dist/batch/google.d.ts.map +1 -0
- package/dist/batch/google.js +360 -0
- package/dist/batch/google.js.map +1 -0
- package/dist/batch/index.d.ts +31 -0
- package/dist/batch/index.d.ts.map +1 -0
- package/dist/batch/index.js +31 -0
- package/dist/batch/index.js.map +1 -0
- package/dist/batch/memory.d.ts +44 -0
- package/dist/batch/memory.d.ts.map +1 -0
- package/dist/batch/memory.js +188 -0
- package/dist/batch/memory.js.map +1 -0
- package/dist/batch/openai.d.ts +37 -0
- package/dist/batch/openai.d.ts.map +1 -0
- package/dist/batch/openai.js +403 -0
- package/dist/batch/openai.js.map +1 -0
- package/dist/batch-map.d.ts +125 -0
- package/dist/batch-map.d.ts.map +1 -0
- package/dist/batch-map.js +406 -0
- package/dist/batch-map.js.map +1 -0
- package/dist/batch-queue.d.ts +273 -0
- package/dist/batch-queue.d.ts.map +1 -0
- package/dist/batch-queue.js +271 -0
- package/dist/batch-queue.js.map +1 -0
- package/dist/context.d.ts +133 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +267 -0
- package/dist/context.js.map +1 -0
- package/dist/embeddings.d.ts +123 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +170 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/eval/index.d.ts +8 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +8 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/models.d.ts +66 -0
- package/dist/eval/models.d.ts.map +1 -0
- package/dist/eval/models.js +120 -0
- package/dist/eval/models.js.map +1 -0
- package/dist/eval/runner.d.ts +64 -0
- package/dist/eval/runner.d.ts.map +1 -0
- package/dist/eval/runner.js +148 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/generate.d.ts +168 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +174 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +29 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -52
- package/dist/index.js.map +1 -1
- package/dist/primitives.d.ts +292 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +471 -0
- package/dist/primitives.js.map +1 -0
- package/dist/providers/cloudflare.d.ts +9 -0
- package/dist/providers/cloudflare.d.ts.map +1 -0
- package/dist/providers/cloudflare.js +9 -0
- package/dist/providers/cloudflare.js.map +1 -0
- package/dist/providers/index.d.ts +9 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/schema.d.ts +54 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +109 -0
- package/dist/schema.js.map +1 -0
- package/dist/template.d.ts +73 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +129 -0
- package/dist/template.js.map +1 -0
- package/dist/types.d.ts +474 -106
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -8
- package/dist/types.js.map +1 -1
- package/evalite.config.ts +19 -0
- package/evals/README.md +212 -0
- package/evals/classification.eval.ts +108 -0
- package/evals/marketing.eval.ts +370 -0
- package/evals/math.eval.ts +94 -0
- package/evals/run-evals.ts +166 -0
- package/evals/structured-output.eval.ts +143 -0
- package/evals/writing.eval.ts +117 -0
- package/examples/batch-blog-posts.ts +160 -0
- package/package.json +57 -57
- package/src/ai-promise.ts +784 -0
- package/src/ai.ts +1183 -0
- package/src/batch/anthropic.ts +375 -0
- package/src/batch/bedrock.ts +801 -0
- package/src/batch/cloudflare.ts +421 -0
- package/src/batch/google.ts +491 -0
- package/src/batch/index.ts +31 -0
- package/src/batch/memory.ts +253 -0
- package/src/batch/openai.ts +557 -0
- package/src/batch-map.ts +534 -0
- package/src/batch-queue.ts +493 -0
- package/src/context.ts +332 -0
- package/src/embeddings.ts +244 -0
- package/src/eval/index.ts +8 -0
- package/src/eval/models.ts +158 -0
- package/src/eval/runner.ts +217 -0
- package/src/generate.ts +245 -0
- package/src/index.ts +154 -0
- package/src/primitives.ts +612 -0
- package/src/providers/cloudflare.ts +15 -0
- package/src/providers/index.ts +14 -0
- package/src/schema.ts +147 -0
- package/src/template.ts +209 -0
- package/src/types.ts +540 -0
- package/test/README.md +105 -0
- package/test/ai-proxy.test.ts +192 -0
- package/test/async-iterators.test.ts +327 -0
- package/test/batch-background.test.ts +482 -0
- package/test/batch-blog-posts.test.ts +387 -0
- package/test/blog-generation.test.ts +510 -0
- package/test/browse-read.test.ts +611 -0
- package/test/core-functions.test.ts +694 -0
- package/test/decide.test.ts +393 -0
- package/test/define.test.ts +274 -0
- package/test/e2e-bedrock-manual.ts +163 -0
- package/test/e2e-bedrock.test.ts +191 -0
- package/test/e2e-flex-gateway.ts +157 -0
- package/test/e2e-flex-manual.ts +183 -0
- package/test/e2e-flex.test.ts +209 -0
- package/test/e2e-google-manual.ts +178 -0
- package/test/e2e-google.test.ts +216 -0
- package/test/embeddings.test.ts +284 -0
- package/test/evals/define-function.eval.test.ts +379 -0
- package/test/evals/primitives.eval.test.ts +384 -0
- package/test/function-types.test.ts +492 -0
- package/test/generate-core.test.ts +319 -0
- package/test/generate.test.ts +163 -0
- package/test/implicit-batch.test.ts +422 -0
- package/test/schema.test.ts +109 -0
- package/test/tagged-templates.test.ts +302 -0
- package/tsconfig.json +10 -0
- package/vitest.config.ts +42 -0
- package/LICENSE +0 -21
- package/bin/cli.js +0 -5
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -38
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.test.d.ts +0 -2
- package/dist/cli/index.test.d.ts.map +0 -1
- package/dist/cli/index.test.js +0 -35
- package/dist/cli/index.test.js.map +0 -1
- package/dist/constants/models.d.ts +0 -10
- package/dist/constants/models.d.ts.map +0 -1
- package/dist/constants/models.js +0 -12
- package/dist/constants/models.js.map +0 -1
- package/dist/converters/index.d.ts +0 -3
- package/dist/converters/index.d.ts.map +0 -1
- package/dist/converters/index.js +0 -3
- package/dist/converters/index.js.map +0 -1
- package/dist/converters/model.d.ts +0 -4
- package/dist/converters/model.d.ts.map +0 -1
- package/dist/converters/model.js +0 -19
- package/dist/converters/model.js.map +0 -1
- package/dist/converters/schema.d.ts +0 -4
- package/dist/converters/schema.d.ts.map +0 -1
- package/dist/converters/schema.js +0 -25
- package/dist/converters/schema.js.map +0 -1
- package/dist/core/responses.d.ts +0 -5
- package/dist/core/responses.d.ts.map +0 -1
- package/dist/core/responses.js +0 -16
- package/dist/core/responses.js.map +0 -1
- package/dist/core/responses.test.d.ts +0 -2
- package/dist/core/responses.test.d.ts.map +0 -1
- package/dist/core/responses.test.js +0 -31
- package/dist/core/responses.test.js.map +0 -1
- package/dist/errors.d.ts +0 -6
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -9
- package/dist/errors.js.map +0 -1
- package/dist/examples/streaming.test.d.ts +0 -2
- package/dist/examples/streaming.test.d.ts.map +0 -1
- package/dist/examples/streaming.test.js +0 -176
- package/dist/examples/streaming.test.js.map +0 -1
- package/dist/factory/__tests__/index.test.d.ts +0 -2
- package/dist/factory/__tests__/index.test.d.ts.map +0 -1
- package/dist/factory/__tests__/index.test.js +0 -430
- package/dist/factory/__tests__/index.test.js.map +0 -1
- package/dist/factory/__tests__/list.test.d.ts +0 -2
- package/dist/factory/__tests__/list.test.d.ts.map +0 -1
- package/dist/factory/__tests__/list.test.js +0 -92
- package/dist/factory/__tests__/list.test.js.map +0 -1
- package/dist/factory/index.d.ts +0 -20
- package/dist/factory/index.d.ts.map +0 -1
- package/dist/factory/index.js +0 -287
- package/dist/factory/index.js.map +0 -1
- package/dist/factory/index.test.d.ts +0 -2
- package/dist/factory/index.test.d.ts.map +0 -1
- package/dist/factory/index.test.js +0 -287
- package/dist/factory/index.test.js.map +0 -1
- package/dist/factory/list.d.ts +0 -3
- package/dist/factory/list.d.ts.map +0 -1
- package/dist/factory/list.js +0 -221
- package/dist/factory/list.js.map +0 -1
- package/dist/factory/list.test.d.ts +0 -2
- package/dist/factory/list.test.d.ts.map +0 -1
- package/dist/factory/list.test.js +0 -84
- package/dist/factory/list.test.js.map +0 -1
- package/dist/generate/index.d.ts +0 -5
- package/dist/generate/index.d.ts.map +0 -1
- package/dist/generate/index.js +0 -17
- package/dist/generate/index.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -59
- package/dist/index.test.js.map +0 -1
- package/dist/list/await.d.ts +0 -3
- package/dist/list/await.d.ts.map +0 -1
- package/dist/list/await.js +0 -28
- package/dist/list/await.js.map +0 -1
- package/dist/list/constants.d.ts +0 -4
- package/dist/list/constants.d.ts.map +0 -1
- package/dist/list/constants.js +0 -5
- package/dist/list/constants.js.map +0 -1
- package/dist/list/create-function.d.ts +0 -3
- package/dist/list/create-function.d.ts.map +0 -1
- package/dist/list/create-function.js +0 -11
- package/dist/list/create-function.js.map +0 -1
- package/dist/list/index.d.ts +0 -4
- package/dist/list/index.d.ts.map +0 -1
- package/dist/list/index.js +0 -5
- package/dist/list/index.js.map +0 -1
- package/dist/list/prompt.d.ts +0 -3
- package/dist/list/prompt.d.ts.map +0 -1
- package/dist/list/prompt.js +0 -6
- package/dist/list/prompt.js.map +0 -1
- package/dist/list/schemas.d.ts +0 -4
- package/dist/list/schemas.d.ts.map +0 -1
- package/dist/list/schemas.js +0 -8
- package/dist/list/schemas.js.map +0 -1
- package/dist/list/stream.d.ts +0 -3
- package/dist/list/stream.d.ts.map +0 -1
- package/dist/list/stream.js +0 -33
- package/dist/list/stream.js.map +0 -1
- package/dist/list/types.d.ts +0 -11
- package/dist/list/types.d.ts.map +0 -1
- package/dist/list/types.js +0 -2
- package/dist/list/types.js.map +0 -1
- package/dist/list/validation.d.ts +0 -3
- package/dist/list/validation.d.ts.map +0 -1
- package/dist/list/validation.js +0 -12
- package/dist/list/validation.js.map +0 -1
- package/dist/providers/config.d.ts +0 -4
- package/dist/providers/config.d.ts.map +0 -1
- package/dist/providers/config.js +0 -21
- package/dist/providers/config.js.map +0 -1
- package/dist/providers/config.test.d.ts +0 -2
- package/dist/providers/config.test.d.ts.map +0 -1
- package/dist/providers/config.test.js +0 -37
- package/dist/providers/config.test.js.map +0 -1
- package/dist/proxy/constants.d.ts +0 -4
- package/dist/proxy/constants.d.ts.map +0 -1
- package/dist/proxy/constants.js +0 -5
- package/dist/proxy/constants.js.map +0 -1
- package/dist/proxy/create-function.d.ts +0 -4
- package/dist/proxy/create-function.d.ts.map +0 -1
- package/dist/proxy/create-function.js +0 -24
- package/dist/proxy/create-function.js.map +0 -1
- package/dist/proxy/create-proxy.d.ts +0 -2
- package/dist/proxy/create-proxy.d.ts.map +0 -1
- package/dist/proxy/create-proxy.js +0 -11
- package/dist/proxy/create-proxy.js.map +0 -1
- package/dist/proxy/function-generator.d.ts +0 -9
- package/dist/proxy/function-generator.d.ts.map +0 -1
- package/dist/proxy/function-generator.js +0 -29
- package/dist/proxy/function-generator.js.map +0 -1
- package/dist/proxy/index.d.ts +0 -4
- package/dist/proxy/index.d.ts.map +0 -1
- package/dist/proxy/index.js +0 -4
- package/dist/proxy/index.js.map +0 -1
- package/dist/proxy/prompt.d.ts +0 -2
- package/dist/proxy/prompt.d.ts.map +0 -1
- package/dist/proxy/prompt.js +0 -6
- package/dist/proxy/prompt.js.map +0 -1
- package/dist/proxy/types.d.ts +0 -7
- package/dist/proxy/types.d.ts.map +0 -1
- package/dist/proxy/types.js +0 -2
- package/dist/proxy/types.js.map +0 -1
- package/dist/queue/manager.d.ts +0 -5
- package/dist/queue/manager.d.ts.map +0 -1
- package/dist/queue/manager.js +0 -37
- package/dist/queue/manager.js.map +0 -1
- package/dist/queue/manager.test.d.ts +0 -2
- package/dist/queue/manager.test.d.ts.map +0 -1
- package/dist/queue/manager.test.js +0 -52
- package/dist/queue/manager.test.js.map +0 -1
- package/dist/schema-converter.d.ts +0 -4
- package/dist/schema-converter.d.ts.map +0 -1
- package/dist/schema-converter.js +0 -30
- package/dist/schema-converter.js.map +0 -1
- package/dist/stream/index.d.ts +0 -7
- package/dist/stream/index.d.ts.map +0 -1
- package/dist/stream/index.js +0 -23
- package/dist/stream/index.js.map +0 -1
- package/dist/streaming/utils.d.ts +0 -4
- package/dist/streaming/utils.d.ts.map +0 -1
- package/dist/streaming/utils.js +0 -131
- package/dist/streaming/utils.js.map +0 -1
- package/dist/streaming/utils.test.d.ts +0 -2
- package/dist/streaming/utils.test.d.ts.map +0 -1
- package/dist/streaming/utils.test.js +0 -84
- package/dist/streaming/utils.test.js.map +0 -1
- package/dist/templates/result.d.ts +0 -7
- package/dist/templates/result.d.ts.map +0 -1
- package/dist/templates/result.js +0 -40
- package/dist/templates/result.js.map +0 -1
- package/dist/templates/result.test.d.ts +0 -2
- package/dist/templates/result.test.d.ts.map +0 -1
- package/dist/templates/result.test.js +0 -75
- package/dist/templates/result.test.js.map +0 -1
- package/dist/test/setup.d.ts +0 -2
- package/dist/test/setup.d.ts.map +0 -1
- package/dist/test/setup.js +0 -21
- package/dist/test/setup.js.map +0 -1
- package/dist/test-types.d.ts +0 -13
- package/dist/test-types.d.ts.map +0 -1
- package/dist/test-types.js +0 -55
- package/dist/test-types.js.map +0 -1
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -4
- package/dist/types/index.js.map +0 -1
- package/dist/types/list.d.ts +0 -10
- package/dist/types/list.d.ts.map +0 -1
- package/dist/types/list.js +0 -2
- package/dist/types/list.js.map +0 -1
- package/dist/types/model.d.ts +0 -7
- package/dist/types/model.d.ts.map +0 -1
- package/dist/types/model.js +0 -2
- package/dist/types/model.js.map +0 -1
- package/dist/types/options.d.ts +0 -25
- package/dist/types/options.d.ts.map +0 -1
- package/dist/types/options.js +0 -2
- package/dist/types/options.js.map +0 -1
- package/dist/types/schema.d.ts +0 -5
- package/dist/types/schema.d.ts.map +0 -1
- package/dist/types/schema.js +0 -2
- package/dist/types/schema.js.map +0 -1
- package/dist/utils/__tests__/request-handler.test.d.ts +0 -2
- package/dist/utils/__tests__/request-handler.test.d.ts.map +0 -1
- package/dist/utils/__tests__/request-handler.test.js +0 -134
- package/dist/utils/__tests__/request-handler.test.js.map +0 -1
- package/dist/utils/__tests__/schema.test.d.ts +0 -2
- package/dist/utils/__tests__/schema.test.d.ts.map +0 -1
- package/dist/utils/__tests__/schema.test.js +0 -49
- package/dist/utils/__tests__/schema.test.js.map +0 -1
- package/dist/utils/__tests__/stream-progress.test.d.ts +0 -2
- package/dist/utils/__tests__/stream-progress.test.d.ts.map +0 -1
- package/dist/utils/__tests__/stream-progress.test.js +0 -85
- package/dist/utils/__tests__/stream-progress.test.js.map +0 -1
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -2
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/request-handler.d.ts +0 -17
- package/dist/utils/request-handler.d.ts.map +0 -1
- package/dist/utils/request-handler.js +0 -105
- package/dist/utils/request-handler.js.map +0 -1
- package/dist/utils/schema.d.ts +0 -11
- package/dist/utils/schema.d.ts.map +0 -1
- package/dist/utils/schema.js +0 -51
- package/dist/utils/schema.js.map +0 -1
- package/dist/utils/stream-progress.d.ts +0 -17
- package/dist/utils/stream-progress.d.ts.map +0 -1
- package/dist/utils/stream-progress.js +0 -86
- package/dist/utils/stream-progress.js.map +0 -1
- package/dist/utils/validation.d.ts +0 -3
- package/dist/utils/validation.d.ts.map +0 -1
- package/dist/utils/validation.js +0 -30
- package/dist/utils/validation.js.map +0 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Manual E2E Test for AWS Bedrock Flex Tier Processing
|
|
4
|
+
*
|
|
5
|
+
* Run with your AWS credentials:
|
|
6
|
+
*
|
|
7
|
+
* AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... npx tsx test/e2e-bedrock-manual.ts
|
|
8
|
+
*
|
|
9
|
+
* Or if using AWS SSO/profiles:
|
|
10
|
+
*
|
|
11
|
+
* AWS_PROFILE=your-profile npx tsx test/e2e-bedrock-manual.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable, getProvider } from '../src/context.js'
|
|
15
|
+
import { type BatchItem } from '../src/batch-queue.js'
|
|
16
|
+
import { configureAWSBedrock, bedrockFlexAdapter } from '../src/batch/bedrock.js'
|
|
17
|
+
|
|
18
|
+
// Model IDs on Bedrock
|
|
19
|
+
const CLAUDE_OPUS_MODEL = 'anthropic.claude-opus-4-20250514-v1:0'
|
|
20
|
+
const CLAUDE_SONNET_MODEL = 'anthropic.claude-sonnet-4-20250514-v1:0'
|
|
21
|
+
|
|
22
|
+
async function main() {
|
|
23
|
+
console.log('\nš§Ŗ E2E AWS Bedrock Flex Tier Test\n')
|
|
24
|
+
|
|
25
|
+
// Check for AWS credentials
|
|
26
|
+
if (!process.env.AWS_ACCESS_KEY_ID && !process.env.AWS_PROFILE) {
|
|
27
|
+
console.error('ā AWS credentials required')
|
|
28
|
+
console.error(' Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY')
|
|
29
|
+
console.error(' Or use AWS_PROFILE for SSO/credential profiles')
|
|
30
|
+
process.exit(1)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('ā
AWS credentials found')
|
|
34
|
+
console.log(` Region: ${process.env.AWS_REGION || 'us-east-1'}`)
|
|
35
|
+
|
|
36
|
+
// Configure Bedrock
|
|
37
|
+
configureAWSBedrock({
|
|
38
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
39
|
+
s3Bucket: 'dummy-bucket', // Flex mode doesn't use S3
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
configure({
|
|
43
|
+
provider: 'bedrock',
|
|
44
|
+
model: CLAUDE_SONNET_MODEL,
|
|
45
|
+
batchMode: 'auto',
|
|
46
|
+
flexThreshold: 3,
|
|
47
|
+
batchThreshold: 500,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
console.log(`ā
Configured: provider=${getProvider()}, flexAvailable=${isFlexAvailable()}`)
|
|
51
|
+
|
|
52
|
+
// Test 1: Basic flex processing with Claude Sonnet
|
|
53
|
+
console.log('\nš Test 1: Basic Flex Processing (Claude Sonnet)')
|
|
54
|
+
console.log(' Creating 3 simple prompts...')
|
|
55
|
+
|
|
56
|
+
const items: BatchItem[] = [
|
|
57
|
+
{ id: 'test_1', prompt: 'What is 2 + 2? Reply with just the number.', status: 'pending' },
|
|
58
|
+
{ id: 'test_2', prompt: 'What is 3 + 3? Reply with just the number.', status: 'pending' },
|
|
59
|
+
{ id: 'test_3', prompt: 'What is 4 + 4? Reply with just the number.', status: 'pending' },
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
console.log(' Submitting via flex adapter...')
|
|
63
|
+
const startTime = Date.now()
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_SONNET_MODEL })
|
|
67
|
+
const duration = Date.now() - startTime
|
|
68
|
+
|
|
69
|
+
console.log(` ā
Completed in ${duration}ms`)
|
|
70
|
+
console.log(' Results:')
|
|
71
|
+
|
|
72
|
+
results.forEach((result) => {
|
|
73
|
+
const status = result.status === 'completed' ? 'ā
' : 'ā'
|
|
74
|
+
console.log(` ${status} ${result.id}: "${result.result}"`)
|
|
75
|
+
if (result.error) {
|
|
76
|
+
console.log(` Error: ${result.error}`)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(` ā Error: ${error}`)
|
|
81
|
+
process.exit(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Test 2: Token usage
|
|
85
|
+
console.log('\nš Test 2: Token Usage Tracking')
|
|
86
|
+
|
|
87
|
+
const usageItems: BatchItem[] = [
|
|
88
|
+
{ id: 'usage', prompt: 'Count from 1 to 5', status: 'pending' },
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const results = await bedrockFlexAdapter.submitFlex(usageItems, { model: CLAUDE_SONNET_MODEL })
|
|
93
|
+
const usage = results[0].usage
|
|
94
|
+
|
|
95
|
+
if (usage) {
|
|
96
|
+
console.log(` Prompt tokens: ${usage.promptTokens}`)
|
|
97
|
+
console.log(` Completion tokens: ${usage.completionTokens}`)
|
|
98
|
+
console.log(` Total tokens: ${usage.totalTokens}`)
|
|
99
|
+
console.log(' ā
Token usage tracking works')
|
|
100
|
+
} else {
|
|
101
|
+
console.log(' ā ļø No usage data returned')
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(` ā Error: ${error}`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Test 3: Try Claude Opus 4.5 (may not be available)
|
|
108
|
+
console.log('\nš Test 3: Claude Opus 4.5 (optional)')
|
|
109
|
+
|
|
110
|
+
const opusItems: BatchItem[] = [
|
|
111
|
+
{ id: 'opus', prompt: 'Write a haiku about AI.', status: 'pending' },
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const results = await bedrockFlexAdapter.submitFlex(opusItems, { model: CLAUDE_OPUS_MODEL })
|
|
116
|
+
console.log(` ā
Claude Opus 4.5 response:`)
|
|
117
|
+
console.log(` ${results[0].result}`)
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.log(` ā ļø Claude Opus 4.5 not available: ${error}`)
|
|
120
|
+
console.log(' (This is expected if Opus is not enabled in your AWS account)')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Test 4: Concurrent processing
|
|
124
|
+
console.log('\nš Test 4: Concurrent Processing (5 items)')
|
|
125
|
+
|
|
126
|
+
const concurrentItems: BatchItem[] = Array.from({ length: 5 }, (_, i) => ({
|
|
127
|
+
id: `concurrent_${i}`,
|
|
128
|
+
prompt: `What is ${i + 1} * 2? Reply with just the number.`,
|
|
129
|
+
status: 'pending' as const,
|
|
130
|
+
}))
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const startTime = Date.now()
|
|
134
|
+
const results = await bedrockFlexAdapter.submitFlex(concurrentItems, { model: CLAUDE_SONNET_MODEL })
|
|
135
|
+
const duration = Date.now() - startTime
|
|
136
|
+
|
|
137
|
+
const successCount = results.filter((r) => r.status === 'completed').length
|
|
138
|
+
console.log(` ā
Processed ${successCount}/5 items in ${duration}ms`)
|
|
139
|
+
|
|
140
|
+
results.forEach((result) => {
|
|
141
|
+
console.log(` ${result.id}: "${result.result}"`)
|
|
142
|
+
})
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(` ā Error: ${error}`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Test 5: Tier selection
|
|
148
|
+
console.log('\nš Test 5: Execution Tier Selection')
|
|
149
|
+
|
|
150
|
+
console.log(` 1 item ā ${getExecutionTier(1)} (expected: immediate)`)
|
|
151
|
+
console.log(` 3 items ā ${getExecutionTier(3)} (expected: flex)`)
|
|
152
|
+
console.log(` 10 items ā ${getExecutionTier(10)} (expected: flex)`)
|
|
153
|
+
console.log(` 500 items ā ${getExecutionTier(500)} (expected: batch)`)
|
|
154
|
+
|
|
155
|
+
console.log('\n⨠E2E Tests Complete!\n')
|
|
156
|
+
|
|
157
|
+
resetContext()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
main().catch((error) => {
|
|
161
|
+
console.error('Fatal error:', error)
|
|
162
|
+
process.exit(1)
|
|
163
|
+
})
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Tests for AWS Bedrock Flex Tier Processing
|
|
3
|
+
*
|
|
4
|
+
* These tests hit real AWS Bedrock APIs to verify the flex tier actually works.
|
|
5
|
+
* Requires AWS credentials:
|
|
6
|
+
* - AWS_ACCESS_KEY_ID
|
|
7
|
+
* - AWS_SECRET_ACCESS_KEY
|
|
8
|
+
* - AWS_REGION (optional, defaults to us-east-1)
|
|
9
|
+
*
|
|
10
|
+
* Run with: npx vitest run test/e2e-bedrock.test.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
14
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable } from '../src/context.js'
|
|
15
|
+
import { getFlexAdapter, type BatchItem } from '../src/batch-queue.js'
|
|
16
|
+
|
|
17
|
+
// Import the Bedrock adapter to register it
|
|
18
|
+
import { configureAWSBedrock, bedrockFlexAdapter } from '../src/batch/bedrock.js'
|
|
19
|
+
import '../src/batch/bedrock.js'
|
|
20
|
+
|
|
21
|
+
// Skip tests if no AWS credentials
|
|
22
|
+
// NOTE: Unlike OpenAI/Google, Bedrock via AI Gateway still requires AWS SigV4 signing
|
|
23
|
+
// Gateway alone is NOT sufficient - you need AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
24
|
+
const hasCredentials = !!(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY)
|
|
25
|
+
|
|
26
|
+
// Claude Opus 4.5 model ID on Bedrock
|
|
27
|
+
const CLAUDE_OPUS_MODEL = 'anthropic.claude-opus-4-20250514-v1:0'
|
|
28
|
+
// Fallback to Sonnet if Opus isn't available
|
|
29
|
+
const CLAUDE_SONNET_MODEL = 'anthropic.claude-sonnet-4-20250514-v1:0'
|
|
30
|
+
|
|
31
|
+
describe.skipIf(!hasCredentials)('E2E Bedrock Flex Tier Processing', () => {
|
|
32
|
+
beforeAll(() => {
|
|
33
|
+
// Configure Bedrock - can use either direct AWS credentials or AI Gateway
|
|
34
|
+
configureAWSBedrock({
|
|
35
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
36
|
+
s3Bucket: process.env.BEDROCK_BATCH_S3_BUCKET || 'dummy-bucket',
|
|
37
|
+
// AI Gateway configuration (optional)
|
|
38
|
+
gatewayUrl: process.env.AI_GATEWAY_URL,
|
|
39
|
+
gatewayToken: process.env.AI_GATEWAY_TOKEN,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
configure({
|
|
43
|
+
provider: 'bedrock',
|
|
44
|
+
model: CLAUDE_SONNET_MODEL, // Use Sonnet by default (more available)
|
|
45
|
+
batchMode: 'auto',
|
|
46
|
+
flexThreshold: 3,
|
|
47
|
+
batchThreshold: 500,
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
afterAll(() => {
|
|
52
|
+
resetContext()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe('Flex Adapter Direct', () => {
|
|
56
|
+
it('processes a small batch via flex adapter', async () => {
|
|
57
|
+
const items: BatchItem[] = [
|
|
58
|
+
{
|
|
59
|
+
id: 'item_1',
|
|
60
|
+
prompt: 'What is 2 + 2? Reply with just the number.',
|
|
61
|
+
status: 'pending',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'item_2',
|
|
65
|
+
prompt: 'What is 3 + 3? Reply with just the number.',
|
|
66
|
+
status: 'pending',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'item_3',
|
|
70
|
+
prompt: 'What is 4 + 4? Reply with just the number.',
|
|
71
|
+
status: 'pending',
|
|
72
|
+
},
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_SONNET_MODEL })
|
|
76
|
+
|
|
77
|
+
expect(results).toHaveLength(3)
|
|
78
|
+
results.forEach((result) => {
|
|
79
|
+
expect(result.status).toBe('completed')
|
|
80
|
+
expect(result.result).toBeDefined()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// Check the actual responses contain numbers
|
|
84
|
+
const result1 = results.find((r) => r.id === 'item_1')
|
|
85
|
+
const result2 = results.find((r) => r.id === 'item_2')
|
|
86
|
+
const result3 = results.find((r) => r.id === 'item_3')
|
|
87
|
+
|
|
88
|
+
expect(String(result1?.result)).toContain('4')
|
|
89
|
+
expect(String(result2?.result)).toContain('6')
|
|
90
|
+
expect(String(result3?.result)).toContain('8')
|
|
91
|
+
}, 60000) // 60 second timeout for Bedrock
|
|
92
|
+
|
|
93
|
+
it('reports token usage', async () => {
|
|
94
|
+
const items: BatchItem[] = [
|
|
95
|
+
{
|
|
96
|
+
id: 'usage_test',
|
|
97
|
+
prompt: 'Count from 1 to 5',
|
|
98
|
+
status: 'pending',
|
|
99
|
+
},
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_SONNET_MODEL })
|
|
103
|
+
|
|
104
|
+
expect(results[0].usage).toBeDefined()
|
|
105
|
+
expect(results[0].usage?.promptTokens).toBeGreaterThan(0)
|
|
106
|
+
expect(results[0].usage?.completionTokens).toBeGreaterThan(0)
|
|
107
|
+
expect(results[0].usage?.totalTokens).toBeGreaterThan(0)
|
|
108
|
+
}, 60000)
|
|
109
|
+
|
|
110
|
+
it('handles system prompts', async () => {
|
|
111
|
+
const items: BatchItem[] = [
|
|
112
|
+
{
|
|
113
|
+
id: 'system_test',
|
|
114
|
+
prompt: 'What should I say?',
|
|
115
|
+
options: {
|
|
116
|
+
system: 'You are a helpful assistant that always responds with exactly "Hello World"',
|
|
117
|
+
},
|
|
118
|
+
status: 'pending',
|
|
119
|
+
},
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_SONNET_MODEL })
|
|
123
|
+
|
|
124
|
+
expect(results[0].status).toBe('completed')
|
|
125
|
+
expect(String(results[0].result).toLowerCase()).toContain('hello')
|
|
126
|
+
}, 60000)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
describe('Execution Tier Selection', () => {
|
|
130
|
+
it('selects immediate tier for < flexThreshold items', () => {
|
|
131
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
132
|
+
expect(getExecutionTier(1)).toBe('immediate')
|
|
133
|
+
expect(getExecutionTier(4)).toBe('immediate')
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('selects flex tier for flexThreshold to < batchThreshold items', () => {
|
|
137
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
138
|
+
expect(getExecutionTier(5)).toBe('flex')
|
|
139
|
+
expect(getExecutionTier(100)).toBe('flex')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('reports flex as available for bedrock', () => {
|
|
143
|
+
configure({ provider: 'bedrock' })
|
|
144
|
+
expect(isFlexAvailable()).toBe(true)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe('Concurrent Processing', () => {
|
|
149
|
+
it('processes multiple items concurrently', async () => {
|
|
150
|
+
// Create 5 items to test concurrent processing
|
|
151
|
+
const items: BatchItem[] = Array.from({ length: 5 }, (_, i) => ({
|
|
152
|
+
id: `concurrent_${i}`,
|
|
153
|
+
prompt: `What is ${i} + 1? Reply with just the number.`,
|
|
154
|
+
status: 'pending' as const,
|
|
155
|
+
}))
|
|
156
|
+
|
|
157
|
+
const startTime = Date.now()
|
|
158
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_SONNET_MODEL })
|
|
159
|
+
const duration = Date.now() - startTime
|
|
160
|
+
|
|
161
|
+
expect(results).toHaveLength(5)
|
|
162
|
+
results.forEach((result) => {
|
|
163
|
+
expect(result.status).toBe('completed')
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
console.log(`Processed 5 items in ${duration}ms`)
|
|
167
|
+
}, 120000)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// Optional test with Claude Opus 4.5 (may not be available in all regions)
|
|
172
|
+
describe.skipIf(!hasCredentials)('E2E Bedrock with Claude Opus 4.5', () => {
|
|
173
|
+
it.skip('processes with Claude Opus 4.5', async () => {
|
|
174
|
+
const items: BatchItem[] = [
|
|
175
|
+
{
|
|
176
|
+
id: 'opus_test',
|
|
177
|
+
prompt: 'Write a haiku about AI.',
|
|
178
|
+
status: 'pending',
|
|
179
|
+
},
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const results = await bedrockFlexAdapter.submitFlex(items, { model: CLAUDE_OPUS_MODEL })
|
|
184
|
+
expect(results[0].status).toBe('completed')
|
|
185
|
+
expect(results[0].result).toBeDefined()
|
|
186
|
+
console.log('Claude Opus 4.5 response:', results[0].result)
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.log('Claude Opus 4.5 not available in this region:', error)
|
|
189
|
+
}
|
|
190
|
+
}, 120000)
|
|
191
|
+
})
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* E2E Test for Flex Tier via Cloudflare AI Gateway
|
|
4
|
+
*
|
|
5
|
+
* This test uses the Cloudflare AI Gateway to route requests to OpenAI,
|
|
6
|
+
* using the AI_GATEWAY_TOKEN and AI_GATEWAY_URL environment variables.
|
|
7
|
+
*
|
|
8
|
+
* Run with:
|
|
9
|
+
* npx tsx test/e2e-flex-gateway.ts
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable, getProvider } from '../src/context.js'
|
|
13
|
+
import { getFlexAdapter, type BatchItem } from '../src/batch-queue.js'
|
|
14
|
+
import { configureOpenAI, openaiFlexAdapter } from '../src/batch/openai.js'
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
console.log('\nš§Ŗ E2E Flex Tier Test (via Cloudflare AI Gateway)\n')
|
|
18
|
+
|
|
19
|
+
// Check for gateway config
|
|
20
|
+
const gatewayUrl = process.env.AI_GATEWAY_URL
|
|
21
|
+
const gatewayToken = process.env.AI_GATEWAY_TOKEN
|
|
22
|
+
|
|
23
|
+
if (!gatewayUrl || !gatewayToken) {
|
|
24
|
+
console.error('ā AI_GATEWAY_URL and AI_GATEWAY_TOKEN environment variables are required')
|
|
25
|
+
console.error(' These should be in .env at the repo root')
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log(`ā
Gateway URL: ${gatewayUrl}`)
|
|
30
|
+
console.log('ā
Gateway Token found')
|
|
31
|
+
|
|
32
|
+
// Configure OpenAI adapter to use the gateway
|
|
33
|
+
// The gateway URL format is: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}
|
|
34
|
+
// We need to append /openai to route to OpenAI
|
|
35
|
+
const openaiGatewayUrl = `${gatewayUrl}/openai`
|
|
36
|
+
console.log(` Using base URL: ${openaiGatewayUrl}`)
|
|
37
|
+
|
|
38
|
+
configureOpenAI({
|
|
39
|
+
apiKey: gatewayToken,
|
|
40
|
+
baseUrl: openaiGatewayUrl,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Configure context
|
|
44
|
+
configure({
|
|
45
|
+
provider: 'openai',
|
|
46
|
+
model: 'gpt-4o-mini',
|
|
47
|
+
batchMode: 'auto',
|
|
48
|
+
flexThreshold: 3,
|
|
49
|
+
batchThreshold: 500,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
console.log(`ā
Configured: provider=${getProvider()}, flexAvailable=${isFlexAvailable()}`)
|
|
53
|
+
|
|
54
|
+
// Test 1: Basic flex processing
|
|
55
|
+
console.log('\nš Test 1: Basic Flex Processing')
|
|
56
|
+
console.log(' Creating 3 simple prompts...')
|
|
57
|
+
|
|
58
|
+
const items: BatchItem[] = [
|
|
59
|
+
{ id: 'test_1', prompt: 'Say "hello" and nothing else.', status: 'pending' },
|
|
60
|
+
{ id: 'test_2', prompt: 'Say "world" and nothing else.', status: 'pending' },
|
|
61
|
+
{ id: 'test_3', prompt: 'Say "test" and nothing else.', status: 'pending' },
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
console.log(' Submitting via flex adapter...')
|
|
65
|
+
const startTime = Date.now()
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const results = await openaiFlexAdapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
69
|
+
const duration = Date.now() - startTime
|
|
70
|
+
|
|
71
|
+
console.log(` ā
Completed in ${duration}ms`)
|
|
72
|
+
console.log(' Results:')
|
|
73
|
+
|
|
74
|
+
results.forEach((result) => {
|
|
75
|
+
const status = result.status === 'completed' ? 'ā
' : 'ā'
|
|
76
|
+
console.log(` ${status} ${result.id}: "${result.result}"`)
|
|
77
|
+
if (result.error) {
|
|
78
|
+
console.log(` Error: ${result.error}`)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const successCount = results.filter((r) => r.status === 'completed').length
|
|
83
|
+
if (successCount === results.length) {
|
|
84
|
+
console.log(` ā
All ${successCount} items completed successfully`)
|
|
85
|
+
} else {
|
|
86
|
+
console.log(` ā ļø ${successCount}/${results.length} items completed`)
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(` ā Error: ${error}`)
|
|
90
|
+
process.exit(1)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Test 2: Token usage
|
|
94
|
+
console.log('\nš Test 2: Token Usage Tracking')
|
|
95
|
+
|
|
96
|
+
const usageItems: BatchItem[] = [
|
|
97
|
+
{ id: 'usage', prompt: 'Count from 1 to 5', status: 'pending' },
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const results = await openaiFlexAdapter.submitFlex(usageItems, { model: 'gpt-4o-mini' })
|
|
102
|
+
const usage = results[0].usage
|
|
103
|
+
|
|
104
|
+
if (usage) {
|
|
105
|
+
console.log(` Prompt tokens: ${usage.promptTokens}`)
|
|
106
|
+
console.log(` Completion tokens: ${usage.completionTokens}`)
|
|
107
|
+
console.log(` Total tokens: ${usage.totalTokens}`)
|
|
108
|
+
console.log(' ā
Token usage tracking works')
|
|
109
|
+
} else {
|
|
110
|
+
console.log(' ā ļø No usage data returned')
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(` ā Error: ${error}`)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Test 3: Concurrent processing
|
|
117
|
+
console.log('\nš Test 3: Concurrent Processing (5 items)')
|
|
118
|
+
|
|
119
|
+
const concurrentItems: BatchItem[] = Array.from({ length: 5 }, (_, i) => ({
|
|
120
|
+
id: `concurrent_${i}`,
|
|
121
|
+
prompt: `What is ${i + 1} + ${i + 1}? Reply with just the number.`,
|
|
122
|
+
status: 'pending' as const,
|
|
123
|
+
}))
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const startTime = Date.now()
|
|
127
|
+
const results = await openaiFlexAdapter.submitFlex(concurrentItems, { model: 'gpt-4o-mini' })
|
|
128
|
+
const duration = Date.now() - startTime
|
|
129
|
+
|
|
130
|
+
const successCount = results.filter((r) => r.status === 'completed').length
|
|
131
|
+
console.log(` ā
Processed ${successCount}/5 items in ${duration}ms`)
|
|
132
|
+
console.log(` Average: ${Math.round(duration / 5)}ms per item`)
|
|
133
|
+
|
|
134
|
+
results.forEach((result) => {
|
|
135
|
+
console.log(` ${result.id}: "${result.result}"`)
|
|
136
|
+
})
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error(` ā Error: ${error}`)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Test 4: Tier selection
|
|
142
|
+
console.log('\nš Test 4: Execution Tier Selection')
|
|
143
|
+
|
|
144
|
+
console.log(` 1 item ā ${getExecutionTier(1)} (expected: immediate)`)
|
|
145
|
+
console.log(` 3 items ā ${getExecutionTier(3)} (expected: flex)`)
|
|
146
|
+
console.log(` 10 items ā ${getExecutionTier(10)} (expected: flex)`)
|
|
147
|
+
console.log(` 500 items ā ${getExecutionTier(500)} (expected: batch)`)
|
|
148
|
+
|
|
149
|
+
console.log('\n⨠E2E Tests Complete!\n')
|
|
150
|
+
|
|
151
|
+
resetContext()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
main().catch((error) => {
|
|
155
|
+
console.error('Fatal error:', error)
|
|
156
|
+
process.exit(1)
|
|
157
|
+
})
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Manual E2E Test for Flex Tier Processing
|
|
4
|
+
*
|
|
5
|
+
* Run this script manually with your OpenAI API key:
|
|
6
|
+
*
|
|
7
|
+
* OPENAI_API_KEY=sk-... npx tsx test/e2e-flex-manual.ts
|
|
8
|
+
*
|
|
9
|
+
* Or if you have the key in your environment:
|
|
10
|
+
*
|
|
11
|
+
* npx tsx test/e2e-flex-manual.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable, getProvider } from '../src/context.js'
|
|
15
|
+
import { getFlexAdapter, type BatchItem } from '../src/batch-queue.js'
|
|
16
|
+
|
|
17
|
+
// Import the OpenAI adapter to register it
|
|
18
|
+
import '../src/batch/openai.js'
|
|
19
|
+
|
|
20
|
+
async function main() {
|
|
21
|
+
console.log('\nš§Ŗ E2E Flex Tier Test\n')
|
|
22
|
+
|
|
23
|
+
// Check for API key
|
|
24
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
25
|
+
console.error('ā OPENAI_API_KEY environment variable is required')
|
|
26
|
+
console.error(' Run with: OPENAI_API_KEY=sk-... npx tsx test/e2e-flex-manual.ts')
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log('ā
OpenAI API key found')
|
|
31
|
+
|
|
32
|
+
// Configure
|
|
33
|
+
configure({
|
|
34
|
+
provider: 'openai',
|
|
35
|
+
model: 'gpt-4o-mini',
|
|
36
|
+
batchMode: 'auto',
|
|
37
|
+
flexThreshold: 3,
|
|
38
|
+
batchThreshold: 500,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
console.log(`ā
Configured: provider=${getProvider()}, flexAvailable=${isFlexAvailable()}`)
|
|
42
|
+
|
|
43
|
+
// Test 1: Basic flex processing
|
|
44
|
+
console.log('\nš Test 1: Basic Flex Processing')
|
|
45
|
+
console.log(' Creating 5 simple math prompts...')
|
|
46
|
+
|
|
47
|
+
const adapter = getFlexAdapter('openai')
|
|
48
|
+
|
|
49
|
+
const items: BatchItem[] = [
|
|
50
|
+
{ id: 'math_1', prompt: 'What is 2 + 2? Reply with just the number.', status: 'pending' },
|
|
51
|
+
{ id: 'math_2', prompt: 'What is 3 + 3? Reply with just the number.', status: 'pending' },
|
|
52
|
+
{ id: 'math_3', prompt: 'What is 4 + 4? Reply with just the number.', status: 'pending' },
|
|
53
|
+
{ id: 'math_4', prompt: 'What is 5 + 5? Reply with just the number.', status: 'pending' },
|
|
54
|
+
{ id: 'math_5', prompt: 'What is 6 + 6? Reply with just the number.', status: 'pending' },
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
console.log(' Submitting via flex adapter...')
|
|
58
|
+
const startTime = Date.now()
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
62
|
+
const duration = Date.now() - startTime
|
|
63
|
+
|
|
64
|
+
console.log(` ā
Completed in ${duration}ms`)
|
|
65
|
+
console.log(' Results:')
|
|
66
|
+
|
|
67
|
+
let allPassed = true
|
|
68
|
+
const expected = ['4', '6', '8', '10', '12']
|
|
69
|
+
|
|
70
|
+
results.forEach((result, i) => {
|
|
71
|
+
const passed = result.status === 'completed' && result.result?.toString().includes(expected[i])
|
|
72
|
+
const icon = passed ? 'ā
' : 'ā'
|
|
73
|
+
console.log(` ${icon} ${result.id}: "${result.result}" (expected: ${expected[i]})`)
|
|
74
|
+
if (!passed) allPassed = false
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
if (!allPassed) {
|
|
78
|
+
console.log('\nā ļø Some results did not match expected values')
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(` ā Error: ${error}`)
|
|
82
|
+
process.exit(1)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Test 2: Structured output
|
|
86
|
+
console.log('\nš Test 2: Structured Output (JSON Schema)')
|
|
87
|
+
|
|
88
|
+
const structuredItems: BatchItem[] = [
|
|
89
|
+
{
|
|
90
|
+
id: 'person_1',
|
|
91
|
+
prompt: 'Generate a JSON object with name "Alice" and age 30. Format: {"name": "...", "age": ...}',
|
|
92
|
+
schema: { name: 'string', age: 'number' },
|
|
93
|
+
status: 'pending',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'person_2',
|
|
97
|
+
prompt: 'Generate a JSON object with name "Bob" and age 25. Format: {"name": "...", "age": ...}',
|
|
98
|
+
schema: { name: 'string', age: 'number' },
|
|
99
|
+
status: 'pending',
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const results = await adapter.submitFlex(structuredItems, { model: 'gpt-4o-mini' })
|
|
105
|
+
|
|
106
|
+
console.log(' Results:')
|
|
107
|
+
results.forEach((result) => {
|
|
108
|
+
const obj = result.result as { name?: string; age?: number }
|
|
109
|
+
console.log(` ${result.id}: name="${obj?.name}", age=${obj?.age}`)
|
|
110
|
+
})
|
|
111
|
+
console.log(' ā
Structured output works')
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error(` ā Error: ${error}`)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Test 3: Token usage
|
|
117
|
+
console.log('\nš Test 3: Token Usage Tracking')
|
|
118
|
+
|
|
119
|
+
const usageItems: BatchItem[] = [
|
|
120
|
+
{ id: 'usage', prompt: 'Count from 1 to 10', status: 'pending' },
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const results = await adapter.submitFlex(usageItems, { model: 'gpt-4o-mini' })
|
|
125
|
+
const usage = results[0].usage
|
|
126
|
+
|
|
127
|
+
if (usage) {
|
|
128
|
+
console.log(` Prompt tokens: ${usage.promptTokens}`)
|
|
129
|
+
console.log(` Completion tokens: ${usage.completionTokens}`)
|
|
130
|
+
console.log(` Total tokens: ${usage.totalTokens}`)
|
|
131
|
+
console.log(' ā
Token usage tracking works')
|
|
132
|
+
} else {
|
|
133
|
+
console.log(' ā ļø No usage data returned')
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(` ā Error: ${error}`)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Test 4: Concurrent processing performance
|
|
140
|
+
console.log('\nš Test 4: Concurrent Processing Performance')
|
|
141
|
+
console.log(' Creating 10 items to test concurrency...')
|
|
142
|
+
|
|
143
|
+
const concurrentItems: BatchItem[] = Array.from({ length: 10 }, (_, i) => ({
|
|
144
|
+
id: `concurrent_${i}`,
|
|
145
|
+
prompt: `What is ${i + 1} * 2? Reply with just the number.`,
|
|
146
|
+
status: 'pending' as const,
|
|
147
|
+
}))
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const startTime = Date.now()
|
|
151
|
+
const results = await adapter.submitFlex(concurrentItems, { model: 'gpt-4o-mini' })
|
|
152
|
+
const duration = Date.now() - startTime
|
|
153
|
+
|
|
154
|
+
const successCount = results.filter((r) => r.status === 'completed').length
|
|
155
|
+
console.log(` ā
Processed ${successCount}/10 items in ${duration}ms`)
|
|
156
|
+
console.log(` Average: ${Math.round(duration / 10)}ms per item`)
|
|
157
|
+
|
|
158
|
+
if (duration < 10000) {
|
|
159
|
+
console.log(' ā
Concurrent processing is working (< 10s for 10 items)')
|
|
160
|
+
} else {
|
|
161
|
+
console.log(' ā ļø Slower than expected, may not be fully concurrent')
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error(` ā Error: ${error}`)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Test 5: Tier selection
|
|
168
|
+
console.log('\nš Test 5: Execution Tier Selection')
|
|
169
|
+
|
|
170
|
+
console.log(` 1 item ā ${getExecutionTier(1)} (expected: immediate)`)
|
|
171
|
+
console.log(` 3 item ā ${getExecutionTier(3)} (expected: flex, threshold=3)`)
|
|
172
|
+
console.log(` 10 items ā ${getExecutionTier(10)} (expected: flex)`)
|
|
173
|
+
console.log(` 500 items ā ${getExecutionTier(500)} (expected: batch)`)
|
|
174
|
+
|
|
175
|
+
console.log('\n⨠E2E Tests Complete!\n')
|
|
176
|
+
|
|
177
|
+
resetContext()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
main().catch((error) => {
|
|
181
|
+
console.error('Fatal error:', error)
|
|
182
|
+
process.exit(1)
|
|
183
|
+
})
|