ai-functions 0.3.0 → 2.0.1
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/CHANGELOG.md +9 -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/rpc/auth.d.ts +69 -0
- package/dist/rpc/auth.d.ts.map +1 -0
- package/dist/rpc/auth.js +136 -0
- package/dist/rpc/auth.js.map +1 -0
- package/dist/rpc/client.d.ts +62 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +103 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/deferred.d.ts +60 -0
- package/dist/rpc/deferred.d.ts.map +1 -0
- package/dist/rpc/deferred.js +96 -0
- package/dist/rpc/deferred.js.map +1 -0
- package/dist/rpc/index.d.ts +22 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +38 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/local.d.ts +42 -0
- package/dist/rpc/local.d.ts.map +1 -0
- package/dist/rpc/local.js +50 -0
- package/dist/rpc/local.js.map +1 -0
- package/dist/rpc/server.d.ts +165 -0
- package/dist/rpc/server.d.ts.map +1 -0
- package/dist/rpc/server.js +405 -0
- package/dist/rpc/server.js.map +1 -0
- package/dist/rpc/session.d.ts +32 -0
- package/dist/rpc/session.d.ts.map +1 -0
- package/dist/rpc/session.js +43 -0
- package/dist/rpc/session.js.map +1 -0
- package/dist/rpc/transport.d.ts +306 -0
- package/dist/rpc/transport.d.ts.map +1 -0
- package/dist/rpc/transport.js +731 -0
- package/dist/rpc/transport.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,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Tests for Flex Tier Processing
|
|
3
|
+
*
|
|
4
|
+
* These tests hit real APIs to verify the flex tier actually works.
|
|
5
|
+
* Requires OPENAI_API_KEY environment variable.
|
|
6
|
+
*
|
|
7
|
+
* Run with: npx vitest run test/e2e-flex.test.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
11
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable } from '../src/context.js'
|
|
12
|
+
import { getFlexAdapter, type BatchItem, type BatchResult } from '../src/batch-queue.js'
|
|
13
|
+
|
|
14
|
+
// Import the OpenAI adapter to register it
|
|
15
|
+
import { configureOpenAI } from '../src/batch/openai.js'
|
|
16
|
+
import '../src/batch/openai.js'
|
|
17
|
+
|
|
18
|
+
// Skip tests if no API key (either direct or via gateway)
|
|
19
|
+
const hasApiKey = !!(process.env.OPENAI_API_KEY || (process.env.AI_GATEWAY_URL && process.env.AI_GATEWAY_TOKEN))
|
|
20
|
+
|
|
21
|
+
describe.skipIf(!hasApiKey)('E2E Flex Tier Processing', () => {
|
|
22
|
+
beforeAll(() => {
|
|
23
|
+
// If using gateway, configure the base URL
|
|
24
|
+
if (process.env.AI_GATEWAY_URL && process.env.AI_GATEWAY_TOKEN && !process.env.OPENAI_API_KEY) {
|
|
25
|
+
configureOpenAI({
|
|
26
|
+
apiKey: process.env.AI_GATEWAY_TOKEN,
|
|
27
|
+
baseUrl: `${process.env.AI_GATEWAY_URL}/openai`,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
configure({
|
|
32
|
+
provider: 'openai',
|
|
33
|
+
model: 'gpt-4o-mini', // Use mini for faster/cheaper tests
|
|
34
|
+
batchMode: 'auto',
|
|
35
|
+
flexThreshold: 3,
|
|
36
|
+
batchThreshold: 500,
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
afterAll(() => {
|
|
41
|
+
resetContext()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('Flex Adapter Direct', () => {
|
|
45
|
+
it('processes a small batch via flex adapter', async () => {
|
|
46
|
+
const adapter = getFlexAdapter('openai')
|
|
47
|
+
|
|
48
|
+
const items: BatchItem[] = [
|
|
49
|
+
{
|
|
50
|
+
id: 'item_1',
|
|
51
|
+
prompt: 'What is 2 + 2? Reply with just the number.',
|
|
52
|
+
status: 'pending',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'item_2',
|
|
56
|
+
prompt: 'What is 3 + 3? Reply with just the number.',
|
|
57
|
+
status: 'pending',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'item_3',
|
|
61
|
+
prompt: 'What is 4 + 4? Reply with just the number.',
|
|
62
|
+
status: 'pending',
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
67
|
+
|
|
68
|
+
expect(results).toHaveLength(3)
|
|
69
|
+
results.forEach((result) => {
|
|
70
|
+
expect(result.status).toBe('completed')
|
|
71
|
+
expect(result.result).toBeDefined()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Check the actual responses contain numbers
|
|
75
|
+
const result1 = results.find((r) => r.id === 'item_1')
|
|
76
|
+
const result2 = results.find((r) => r.id === 'item_2')
|
|
77
|
+
const result3 = results.find((r) => r.id === 'item_3')
|
|
78
|
+
|
|
79
|
+
expect(result1?.result).toContain('4')
|
|
80
|
+
expect(result2?.result).toContain('6')
|
|
81
|
+
expect(result3?.result).toContain('8')
|
|
82
|
+
}, 30000) // 30 second timeout
|
|
83
|
+
|
|
84
|
+
it('processes items with structured output (JSON schema)', async () => {
|
|
85
|
+
const adapter = getFlexAdapter('openai')
|
|
86
|
+
|
|
87
|
+
const items: BatchItem[] = [
|
|
88
|
+
{
|
|
89
|
+
id: 'structured_1',
|
|
90
|
+
prompt: 'Generate a person with name "Alice" and age 30',
|
|
91
|
+
schema: { name: 'string', age: 'number' },
|
|
92
|
+
status: 'pending',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'structured_2',
|
|
96
|
+
prompt: 'Generate a person with name "Bob" and age 25',
|
|
97
|
+
schema: { name: 'string', age: 'number' },
|
|
98
|
+
status: 'pending',
|
|
99
|
+
},
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
103
|
+
|
|
104
|
+
expect(results).toHaveLength(2)
|
|
105
|
+
results.forEach((result) => {
|
|
106
|
+
expect(result.status).toBe('completed')
|
|
107
|
+
expect(result.result).toBeDefined()
|
|
108
|
+
expect(typeof result.result).toBe('object')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const result1 = results.find((r) => r.id === 'structured_1')
|
|
112
|
+
const result2 = results.find((r) => r.id === 'structured_2')
|
|
113
|
+
|
|
114
|
+
// Results should be parsed JSON objects
|
|
115
|
+
expect((result1?.result as any)?.name).toBeDefined()
|
|
116
|
+
expect((result2?.result as any)?.name).toBeDefined()
|
|
117
|
+
}, 30000)
|
|
118
|
+
|
|
119
|
+
it('handles errors gracefully', async () => {
|
|
120
|
+
const adapter = getFlexAdapter('openai')
|
|
121
|
+
|
|
122
|
+
const items: BatchItem[] = [
|
|
123
|
+
{
|
|
124
|
+
id: 'valid',
|
|
125
|
+
prompt: 'Say hello',
|
|
126
|
+
status: 'pending',
|
|
127
|
+
},
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
// This should work even with a minimal prompt
|
|
131
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
132
|
+
|
|
133
|
+
expect(results).toHaveLength(1)
|
|
134
|
+
expect(results[0].status).toBe('completed')
|
|
135
|
+
}, 30000)
|
|
136
|
+
|
|
137
|
+
it('reports token usage', async () => {
|
|
138
|
+
const adapter = getFlexAdapter('openai')
|
|
139
|
+
|
|
140
|
+
const items: BatchItem[] = [
|
|
141
|
+
{
|
|
142
|
+
id: 'usage_test',
|
|
143
|
+
prompt: 'Count from 1 to 5',
|
|
144
|
+
status: 'pending',
|
|
145
|
+
},
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
149
|
+
|
|
150
|
+
expect(results[0].usage).toBeDefined()
|
|
151
|
+
expect(results[0].usage?.promptTokens).toBeGreaterThan(0)
|
|
152
|
+
expect(results[0].usage?.completionTokens).toBeGreaterThan(0)
|
|
153
|
+
expect(results[0].usage?.totalTokens).toBeGreaterThan(0)
|
|
154
|
+
}, 30000)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('Execution Tier Selection', () => {
|
|
158
|
+
it('selects immediate tier for < flexThreshold items', () => {
|
|
159
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
160
|
+
expect(getExecutionTier(1)).toBe('immediate')
|
|
161
|
+
expect(getExecutionTier(4)).toBe('immediate')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('selects flex tier for flexThreshold to < batchThreshold items', () => {
|
|
165
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
166
|
+
expect(getExecutionTier(5)).toBe('flex')
|
|
167
|
+
expect(getExecutionTier(100)).toBe('flex')
|
|
168
|
+
expect(getExecutionTier(499)).toBe('flex')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('selects batch tier for >= batchThreshold items', () => {
|
|
172
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
173
|
+
expect(getExecutionTier(500)).toBe('batch')
|
|
174
|
+
expect(getExecutionTier(1000)).toBe('batch')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('reports flex as available for openai', () => {
|
|
178
|
+
configure({ provider: 'openai' })
|
|
179
|
+
expect(isFlexAvailable()).toBe(true)
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe('Concurrent Processing', () => {
|
|
184
|
+
it('processes multiple items concurrently', async () => {
|
|
185
|
+
const adapter = getFlexAdapter('openai')
|
|
186
|
+
|
|
187
|
+
// Create 10 items to test concurrent processing
|
|
188
|
+
const items: BatchItem[] = Array.from({ length: 10 }, (_, i) => ({
|
|
189
|
+
id: `concurrent_${i}`,
|
|
190
|
+
prompt: `What is ${i} + 1? Reply with just the number.`,
|
|
191
|
+
status: 'pending' as const,
|
|
192
|
+
}))
|
|
193
|
+
|
|
194
|
+
const startTime = Date.now()
|
|
195
|
+
const results = await adapter.submitFlex(items, { model: 'gpt-4o-mini' })
|
|
196
|
+
const duration = Date.now() - startTime
|
|
197
|
+
|
|
198
|
+
expect(results).toHaveLength(10)
|
|
199
|
+
results.forEach((result, i) => {
|
|
200
|
+
expect(result.status).toBe('completed')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// With concurrency of 10, this should complete much faster than sequential
|
|
204
|
+
// Sequential would be ~10-20 seconds, concurrent should be ~2-5 seconds
|
|
205
|
+
console.log(`Processed 10 items in ${duration}ms`)
|
|
206
|
+
expect(duration).toBeLessThan(20000) // Should be well under 20 seconds
|
|
207
|
+
}, 60000)
|
|
208
|
+
})
|
|
209
|
+
})
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
/**
|
|
3
|
+
* Manual E2E Test for Google GenAI (Gemini) Flex Tier Processing
|
|
4
|
+
*
|
|
5
|
+
* Run with your Google API key:
|
|
6
|
+
*
|
|
7
|
+
* GOOGLE_API_KEY=... npx tsx test/e2e-google-manual.ts
|
|
8
|
+
*
|
|
9
|
+
* Or:
|
|
10
|
+
*
|
|
11
|
+
* GEMINI_API_KEY=... npx tsx test/e2e-google-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 { configureGoogleGenAI, googleFlexAdapter } from '../src/batch/google.js'
|
|
17
|
+
|
|
18
|
+
// Gemini models
|
|
19
|
+
const GEMINI_FLASH = 'gemini-2.0-flash'
|
|
20
|
+
const GEMINI_PRO = 'gemini-1.5-pro'
|
|
21
|
+
|
|
22
|
+
async function main() {
|
|
23
|
+
console.log('\n🧪 E2E Google GenAI (Gemini) Flex Tier Test\n')
|
|
24
|
+
|
|
25
|
+
// Check for API key
|
|
26
|
+
const apiKey = process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY
|
|
27
|
+
if (!apiKey) {
|
|
28
|
+
console.error('❌ Google API key required')
|
|
29
|
+
console.error(' Set GOOGLE_API_KEY or GEMINI_API_KEY')
|
|
30
|
+
console.error(' Get one at: https://aistudio.google.com/app/apikey')
|
|
31
|
+
process.exit(1)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log('✅ Google API key found')
|
|
35
|
+
|
|
36
|
+
// Configure
|
|
37
|
+
configure({
|
|
38
|
+
provider: 'google',
|
|
39
|
+
model: GEMINI_FLASH,
|
|
40
|
+
batchMode: 'auto',
|
|
41
|
+
flexThreshold: 3,
|
|
42
|
+
batchThreshold: 500,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
console.log(`✅ Configured: provider=${getProvider()}, flexAvailable=${isFlexAvailable()}`)
|
|
46
|
+
|
|
47
|
+
// Test 1: Basic flex processing with Gemini 2.0 Flash
|
|
48
|
+
console.log('\n📝 Test 1: Basic Flex Processing (Gemini 2.0 Flash)')
|
|
49
|
+
console.log(' Creating 3 simple prompts...')
|
|
50
|
+
|
|
51
|
+
const items: BatchItem[] = [
|
|
52
|
+
{ id: 'test_1', prompt: 'What is 2 + 2? Reply with just the number.', status: 'pending' },
|
|
53
|
+
{ id: 'test_2', prompt: 'What is 3 + 3? Reply with just the number.', status: 'pending' },
|
|
54
|
+
{ id: 'test_3', prompt: 'What is 4 + 4? 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 googleFlexAdapter.submitFlex(items, { model: GEMINI_FLASH })
|
|
62
|
+
const duration = Date.now() - startTime
|
|
63
|
+
|
|
64
|
+
console.log(` ✅ Completed in ${duration}ms`)
|
|
65
|
+
console.log(' Results:')
|
|
66
|
+
|
|
67
|
+
results.forEach((result) => {
|
|
68
|
+
const status = result.status === 'completed' ? '✅' : '❌'
|
|
69
|
+
console.log(` ${status} ${result.id}: "${result.result}"`)
|
|
70
|
+
if (result.error) {
|
|
71
|
+
console.log(` Error: ${result.error}`)
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error(` ❌ Error: ${error}`)
|
|
76
|
+
process.exit(1)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Test 2: Token usage
|
|
80
|
+
console.log('\n📝 Test 2: Token Usage Tracking')
|
|
81
|
+
|
|
82
|
+
const usageItems: BatchItem[] = [
|
|
83
|
+
{ id: 'usage', prompt: 'Count from 1 to 5', status: 'pending' },
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const results = await googleFlexAdapter.submitFlex(usageItems, { model: GEMINI_FLASH })
|
|
88
|
+
const usage = results[0].usage
|
|
89
|
+
|
|
90
|
+
if (usage) {
|
|
91
|
+
console.log(` Prompt tokens: ${usage.promptTokens}`)
|
|
92
|
+
console.log(` Completion tokens: ${usage.completionTokens}`)
|
|
93
|
+
console.log(` Total tokens: ${usage.totalTokens}`)
|
|
94
|
+
console.log(' ✅ Token usage tracking works')
|
|
95
|
+
} else {
|
|
96
|
+
console.log(' ⚠️ No usage data returned')
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(` ❌ Error: ${error}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Test 3: Structured output (JSON)
|
|
103
|
+
console.log('\n📝 Test 3: Structured Output (JSON)')
|
|
104
|
+
|
|
105
|
+
const jsonItems: BatchItem[] = [
|
|
106
|
+
{
|
|
107
|
+
id: 'json_test',
|
|
108
|
+
prompt: 'Generate a JSON object with name "Alice" and age 30. Return only valid JSON, no markdown.',
|
|
109
|
+
schema: { name: 'string', age: 'number' },
|
|
110
|
+
status: 'pending',
|
|
111
|
+
},
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const results = await googleFlexAdapter.submitFlex(jsonItems, { model: GEMINI_FLASH })
|
|
116
|
+
console.log(` Result: ${JSON.stringify(results[0].result)}`)
|
|
117
|
+
console.log(' ✅ Structured output works')
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error(` ❌ Error: ${error}`)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Test 4: Concurrent processing
|
|
123
|
+
console.log('\n📝 Test 4: Concurrent Processing (10 items)')
|
|
124
|
+
|
|
125
|
+
const concurrentItems: BatchItem[] = Array.from({ length: 10 }, (_, i) => ({
|
|
126
|
+
id: `concurrent_${i}`,
|
|
127
|
+
prompt: `What is ${i + 1} * 2? Reply with just the number.`,
|
|
128
|
+
status: 'pending' as const,
|
|
129
|
+
}))
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const startTime = Date.now()
|
|
133
|
+
const results = await googleFlexAdapter.submitFlex(concurrentItems, { model: GEMINI_FLASH })
|
|
134
|
+
const duration = Date.now() - startTime
|
|
135
|
+
|
|
136
|
+
const successCount = results.filter((r) => r.status === 'completed').length
|
|
137
|
+
console.log(` ✅ Processed ${successCount}/10 items in ${duration}ms`)
|
|
138
|
+
console.log(` Average: ${Math.round(duration / 10)}ms per item`)
|
|
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: Gemini 1.5 Pro
|
|
148
|
+
console.log('\n📝 Test 5: Gemini 1.5 Pro')
|
|
149
|
+
|
|
150
|
+
const proItems: BatchItem[] = [
|
|
151
|
+
{ id: 'pro_test', prompt: 'Write a haiku about AI.', status: 'pending' },
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const results = await googleFlexAdapter.submitFlex(proItems, { model: GEMINI_PRO })
|
|
156
|
+
console.log(` ✅ Gemini 1.5 Pro response:`)
|
|
157
|
+
console.log(` ${results[0].result}`)
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error(` ❌ Error: ${error}`)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Test 6: Tier selection
|
|
163
|
+
console.log('\n📝 Test 6: Execution Tier Selection')
|
|
164
|
+
|
|
165
|
+
console.log(` 1 item → ${getExecutionTier(1)} (expected: immediate)`)
|
|
166
|
+
console.log(` 3 items → ${getExecutionTier(3)} (expected: flex)`)
|
|
167
|
+
console.log(` 10 items → ${getExecutionTier(10)} (expected: flex)`)
|
|
168
|
+
console.log(` 500 items → ${getExecutionTier(500)} (expected: batch)`)
|
|
169
|
+
|
|
170
|
+
console.log('\n✨ E2E Tests Complete!\n')
|
|
171
|
+
|
|
172
|
+
resetContext()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
main().catch((error) => {
|
|
176
|
+
console.error('Fatal error:', error)
|
|
177
|
+
process.exit(1)
|
|
178
|
+
})
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Tests for Google GenAI (Gemini) Flex Tier Processing
|
|
3
|
+
*
|
|
4
|
+
* These tests hit real Google GenAI APIs to verify the flex tier actually works.
|
|
5
|
+
* Requires Google API key:
|
|
6
|
+
* - GOOGLE_API_KEY or GEMINI_API_KEY
|
|
7
|
+
*
|
|
8
|
+
* Run with: npx vitest run test/e2e-google.test.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
12
|
+
import { configure, resetContext, getExecutionTier, isFlexAvailable } from '../src/context.js'
|
|
13
|
+
import { getFlexAdapter, type BatchItem } from '../src/batch-queue.js'
|
|
14
|
+
|
|
15
|
+
// Import the Google adapter to register it
|
|
16
|
+
import { configureGoogleGenAI, googleFlexAdapter } from '../src/batch/google.js'
|
|
17
|
+
import '../src/batch/google.js'
|
|
18
|
+
|
|
19
|
+
// Skip tests if no Google API key or gateway
|
|
20
|
+
const hasApiKey = !!(
|
|
21
|
+
process.env.GOOGLE_API_KEY ||
|
|
22
|
+
process.env.GEMINI_API_KEY ||
|
|
23
|
+
(process.env.AI_GATEWAY_URL && process.env.AI_GATEWAY_TOKEN)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
// Gemini 2.0 Flash model
|
|
27
|
+
const GEMINI_MODEL = 'gemini-2.0-flash'
|
|
28
|
+
|
|
29
|
+
describe.skipIf(!hasApiKey)('E2E Google GenAI Flex Tier Processing', () => {
|
|
30
|
+
beforeAll(() => {
|
|
31
|
+
// Configure Google GenAI - can use either direct API key or AI Gateway
|
|
32
|
+
configureGoogleGenAI({
|
|
33
|
+
gatewayUrl: process.env.AI_GATEWAY_URL,
|
|
34
|
+
gatewayToken: process.env.AI_GATEWAY_TOKEN,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
configure({
|
|
38
|
+
provider: 'google',
|
|
39
|
+
model: GEMINI_MODEL,
|
|
40
|
+
batchMode: 'auto',
|
|
41
|
+
flexThreshold: 3,
|
|
42
|
+
batchThreshold: 500,
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
afterAll(() => {
|
|
47
|
+
resetContext()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('Flex Adapter Direct', () => {
|
|
51
|
+
it('processes a small batch via flex adapter', async () => {
|
|
52
|
+
const items: BatchItem[] = [
|
|
53
|
+
{
|
|
54
|
+
id: 'item_1',
|
|
55
|
+
prompt: 'What is 2 + 2? Reply with just the number.',
|
|
56
|
+
status: 'pending',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'item_2',
|
|
60
|
+
prompt: 'What is 3 + 3? Reply with just the number.',
|
|
61
|
+
status: 'pending',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'item_3',
|
|
65
|
+
prompt: 'What is 4 + 4? Reply with just the number.',
|
|
66
|
+
status: 'pending',
|
|
67
|
+
},
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: GEMINI_MODEL })
|
|
71
|
+
|
|
72
|
+
expect(results).toHaveLength(3)
|
|
73
|
+
results.forEach((result) => {
|
|
74
|
+
expect(result.status).toBe('completed')
|
|
75
|
+
expect(result.result).toBeDefined()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Check the actual responses contain numbers
|
|
79
|
+
const result1 = results.find((r) => r.id === 'item_1')
|
|
80
|
+
const result2 = results.find((r) => r.id === 'item_2')
|
|
81
|
+
const result3 = results.find((r) => r.id === 'item_3')
|
|
82
|
+
|
|
83
|
+
expect(String(result1?.result)).toContain('4')
|
|
84
|
+
expect(String(result2?.result)).toContain('6')
|
|
85
|
+
expect(String(result3?.result)).toContain('8')
|
|
86
|
+
}, 30000)
|
|
87
|
+
|
|
88
|
+
it('reports token usage', async () => {
|
|
89
|
+
const items: BatchItem[] = [
|
|
90
|
+
{
|
|
91
|
+
id: 'usage_test',
|
|
92
|
+
prompt: 'Count from 1 to 5',
|
|
93
|
+
status: 'pending',
|
|
94
|
+
},
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: GEMINI_MODEL })
|
|
98
|
+
|
|
99
|
+
expect(results[0].usage).toBeDefined()
|
|
100
|
+
expect(results[0].usage?.promptTokens).toBeGreaterThan(0)
|
|
101
|
+
expect(results[0].usage?.completionTokens).toBeGreaterThan(0)
|
|
102
|
+
expect(results[0].usage?.totalTokens).toBeGreaterThan(0)
|
|
103
|
+
}, 30000)
|
|
104
|
+
|
|
105
|
+
it('handles system prompts', async () => {
|
|
106
|
+
const items: BatchItem[] = [
|
|
107
|
+
{
|
|
108
|
+
id: 'system_test',
|
|
109
|
+
prompt: 'What should I say?',
|
|
110
|
+
options: {
|
|
111
|
+
system: 'You are a helpful assistant that always responds with exactly "Hello World"',
|
|
112
|
+
},
|
|
113
|
+
status: 'pending',
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: GEMINI_MODEL })
|
|
118
|
+
|
|
119
|
+
expect(results[0].status).toBe('completed')
|
|
120
|
+
expect(String(results[0].result).toLowerCase()).toContain('hello')
|
|
121
|
+
}, 30000)
|
|
122
|
+
|
|
123
|
+
it('handles structured output (JSON)', async () => {
|
|
124
|
+
const items: BatchItem[] = [
|
|
125
|
+
{
|
|
126
|
+
id: 'json_test',
|
|
127
|
+
prompt: 'Generate a JSON object with name "Alice" and age 30. Return only valid JSON.',
|
|
128
|
+
schema: { name: 'string', age: 'number' },
|
|
129
|
+
status: 'pending',
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: GEMINI_MODEL })
|
|
134
|
+
|
|
135
|
+
expect(results[0].status).toBe('completed')
|
|
136
|
+
const result = results[0].result as { name?: string; age?: number }
|
|
137
|
+
expect(result).toBeDefined()
|
|
138
|
+
// The result should be parsed JSON
|
|
139
|
+
expect(typeof result === 'object').toBe(true)
|
|
140
|
+
}, 30000)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
describe('Execution Tier Selection', () => {
|
|
144
|
+
it('selects immediate tier for < flexThreshold items', () => {
|
|
145
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
146
|
+
expect(getExecutionTier(1)).toBe('immediate')
|
|
147
|
+
expect(getExecutionTier(4)).toBe('immediate')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('selects flex tier for flexThreshold to < batchThreshold items', () => {
|
|
151
|
+
configure({ batchMode: 'auto', flexThreshold: 5, batchThreshold: 500 })
|
|
152
|
+
expect(getExecutionTier(5)).toBe('flex')
|
|
153
|
+
expect(getExecutionTier(100)).toBe('flex')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('reports flex as available for google', () => {
|
|
157
|
+
configure({ provider: 'google' })
|
|
158
|
+
expect(isFlexAvailable()).toBe(true)
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('Concurrent Processing', () => {
|
|
163
|
+
it('processes multiple items concurrently', async () => {
|
|
164
|
+
// Create 10 items to test concurrent processing
|
|
165
|
+
const items: BatchItem[] = Array.from({ length: 10 }, (_, i) => ({
|
|
166
|
+
id: `concurrent_${i}`,
|
|
167
|
+
prompt: `What is ${i} + 1? Reply with just the number.`,
|
|
168
|
+
status: 'pending' as const,
|
|
169
|
+
}))
|
|
170
|
+
|
|
171
|
+
const startTime = Date.now()
|
|
172
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: GEMINI_MODEL })
|
|
173
|
+
const duration = Date.now() - startTime
|
|
174
|
+
|
|
175
|
+
expect(results).toHaveLength(10)
|
|
176
|
+
results.forEach((result) => {
|
|
177
|
+
expect(result.status).toBe('completed')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
console.log(`Processed 10 items in ${duration}ms`)
|
|
181
|
+
// With concurrency, should be much faster than sequential
|
|
182
|
+
expect(duration).toBeLessThan(30000) // Should complete in under 30 seconds
|
|
183
|
+
}, 60000)
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
// Test with different Gemini models (optional - may not be available via gateway)
|
|
188
|
+
describe.skipIf(!hasApiKey)('E2E Google GenAI with Different Models', () => {
|
|
189
|
+
it.skip('works with gemini-1.5-flash (may not be in gateway)', async () => {
|
|
190
|
+
const items: BatchItem[] = [
|
|
191
|
+
{
|
|
192
|
+
id: 'flash_test',
|
|
193
|
+
prompt: 'Say "hello" and nothing else.',
|
|
194
|
+
status: 'pending',
|
|
195
|
+
},
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: 'gemini-1.5-flash' })
|
|
199
|
+
expect(results[0].status).toBe('completed')
|
|
200
|
+
expect(String(results[0].result).toLowerCase()).toContain('hello')
|
|
201
|
+
}, 30000)
|
|
202
|
+
|
|
203
|
+
it.skip('works with gemini-1.5-pro (may not be in gateway)', async () => {
|
|
204
|
+
const items: BatchItem[] = [
|
|
205
|
+
{
|
|
206
|
+
id: 'pro_test',
|
|
207
|
+
prompt: 'Say "hello" and nothing else.',
|
|
208
|
+
status: 'pending',
|
|
209
|
+
},
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
const results = await googleFlexAdapter.submitFlex(items, { model: 'gemini-1.5-pro' })
|
|
213
|
+
expect(results[0].status).toBe('completed')
|
|
214
|
+
expect(String(results[0].result).toLowerCase()).toContain('hello')
|
|
215
|
+
}, 30000)
|
|
216
|
+
})
|