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
package/src/types.ts
ADDED
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for AI functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Use Promise directly for interface definitions
|
|
6
|
+
// The actual RPC layer handles serialization
|
|
7
|
+
type RpcPromise<T> = Promise<T>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A function definition that can be called by AI
|
|
11
|
+
*/
|
|
12
|
+
export interface AIFunctionDefinition<
|
|
13
|
+
TInput = unknown,
|
|
14
|
+
TOutput = unknown
|
|
15
|
+
> {
|
|
16
|
+
/** Unique name for the function */
|
|
17
|
+
name: string
|
|
18
|
+
/** Human-readable description for the AI */
|
|
19
|
+
description: string
|
|
20
|
+
/** JSON Schema for the input parameters */
|
|
21
|
+
parameters: JSONSchema
|
|
22
|
+
/** The implementation */
|
|
23
|
+
handler: (input: TInput) => TOutput | Promise<TOutput>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* JSON Schema type (simplified)
|
|
28
|
+
*/
|
|
29
|
+
export interface JSONSchema {
|
|
30
|
+
type?: string
|
|
31
|
+
properties?: Record<string, JSONSchema>
|
|
32
|
+
items?: JSONSchema
|
|
33
|
+
required?: string[]
|
|
34
|
+
description?: string
|
|
35
|
+
enum?: unknown[]
|
|
36
|
+
default?: unknown
|
|
37
|
+
[key: string]: unknown
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Options for AI generation
|
|
42
|
+
*/
|
|
43
|
+
export interface AIGenerateOptions {
|
|
44
|
+
/** The prompt or input */
|
|
45
|
+
prompt?: string
|
|
46
|
+
/** System message */
|
|
47
|
+
system?: string
|
|
48
|
+
/** Model to use */
|
|
49
|
+
model?: string
|
|
50
|
+
/** Temperature (0-1) */
|
|
51
|
+
temperature?: number
|
|
52
|
+
/** Maximum tokens to generate */
|
|
53
|
+
maxTokens?: number
|
|
54
|
+
/** Stop sequences */
|
|
55
|
+
stop?: string[]
|
|
56
|
+
/** Structured output schema */
|
|
57
|
+
schema?: JSONSchema
|
|
58
|
+
/** Available functions */
|
|
59
|
+
functions?: AIFunctionDefinition[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result of AI generation
|
|
64
|
+
*/
|
|
65
|
+
export interface AIGenerateResult {
|
|
66
|
+
/** Generated text */
|
|
67
|
+
text: string
|
|
68
|
+
/** Structured output (if schema was provided) */
|
|
69
|
+
object?: unknown
|
|
70
|
+
/** Function calls (if functions were provided) */
|
|
71
|
+
functionCalls?: AIFunctionCall[]
|
|
72
|
+
/** Token usage */
|
|
73
|
+
usage?: {
|
|
74
|
+
promptTokens: number
|
|
75
|
+
completionTokens: number
|
|
76
|
+
totalTokens: number
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A function call made by the AI
|
|
82
|
+
*/
|
|
83
|
+
export interface AIFunctionCall {
|
|
84
|
+
/** Name of the function to call */
|
|
85
|
+
name: string
|
|
86
|
+
/** Arguments as JSON */
|
|
87
|
+
arguments: unknown
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* AI client interface - all methods return RpcPromise for pipelining
|
|
92
|
+
*/
|
|
93
|
+
export interface AIClient {
|
|
94
|
+
/** Generate text or structured output */
|
|
95
|
+
generate(options: AIGenerateOptions): RpcPromise<AIGenerateResult>
|
|
96
|
+
|
|
97
|
+
/** Execute an action */
|
|
98
|
+
do(action: string, context?: unknown): RpcPromise<unknown>
|
|
99
|
+
|
|
100
|
+
/** Type checking / validation */
|
|
101
|
+
is(value: unknown, type: string | JSONSchema): RpcPromise<boolean>
|
|
102
|
+
|
|
103
|
+
/** Generate code */
|
|
104
|
+
code(prompt: string, language?: string): RpcPromise<string>
|
|
105
|
+
|
|
106
|
+
/** Make a decision */
|
|
107
|
+
decide<T extends string>(options: T[], context?: string): RpcPromise<T>
|
|
108
|
+
|
|
109
|
+
/** Generate a diagram */
|
|
110
|
+
diagram(description: string, format?: 'mermaid' | 'svg' | 'ascii'): RpcPromise<string>
|
|
111
|
+
|
|
112
|
+
/** Generate an image */
|
|
113
|
+
image(prompt: string, options?: ImageOptions): RpcPromise<ImageResult>
|
|
114
|
+
|
|
115
|
+
/** Generate a video */
|
|
116
|
+
video(prompt: string, options?: VideoOptions): RpcPromise<VideoResult>
|
|
117
|
+
|
|
118
|
+
/** Write/generate text content */
|
|
119
|
+
write(prompt: string, options?: WriteOptions): RpcPromise<string>
|
|
120
|
+
|
|
121
|
+
/** Generate a list of items with names and descriptions */
|
|
122
|
+
list(prompt: string): RpcPromise<ListResult>
|
|
123
|
+
|
|
124
|
+
/** Generate multiple named lists of items */
|
|
125
|
+
lists(prompt: string): RpcPromise<ListsResult>
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface ImageOptions {
|
|
129
|
+
width?: number
|
|
130
|
+
height?: number
|
|
131
|
+
style?: string
|
|
132
|
+
model?: string
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface ImageResult {
|
|
136
|
+
url: string
|
|
137
|
+
base64?: string
|
|
138
|
+
width: number
|
|
139
|
+
height: number
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface VideoOptions {
|
|
143
|
+
duration?: number
|
|
144
|
+
width?: number
|
|
145
|
+
height?: number
|
|
146
|
+
fps?: number
|
|
147
|
+
model?: string
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface VideoResult {
|
|
151
|
+
url: string
|
|
152
|
+
duration: number
|
|
153
|
+
width: number
|
|
154
|
+
height: number
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface WriteOptions {
|
|
158
|
+
tone?: string
|
|
159
|
+
length?: 'short' | 'medium' | 'long'
|
|
160
|
+
format?: 'text' | 'markdown' | 'html'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Type for functions that support both regular calls and tagged template literals
|
|
165
|
+
*/
|
|
166
|
+
export type TemplateFunction<TArgs extends unknown[], TReturn> =
|
|
167
|
+
& ((prompt: string, ...args: TArgs) => TReturn)
|
|
168
|
+
& ((strings: TemplateStringsArray, ...values: unknown[]) => TReturn)
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* A single item in a list
|
|
172
|
+
*/
|
|
173
|
+
export interface ListItem {
|
|
174
|
+
name: string
|
|
175
|
+
description: string
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Result of the list() function
|
|
180
|
+
*/
|
|
181
|
+
export interface ListResult {
|
|
182
|
+
items: ListItem[]
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* A named list containing items
|
|
187
|
+
*/
|
|
188
|
+
export interface NamedList {
|
|
189
|
+
name: string
|
|
190
|
+
items: ListItem[]
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Result of the lists() function
|
|
195
|
+
*/
|
|
196
|
+
export interface ListsResult {
|
|
197
|
+
lists: NamedList[]
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Function Definition Types
|
|
202
|
+
// ============================================================================
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Supported programming languages for code generation
|
|
206
|
+
*/
|
|
207
|
+
export type CodeLanguage = 'typescript' | 'javascript' | 'python' | 'go' | 'rust'
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Output types for generative functions
|
|
211
|
+
*/
|
|
212
|
+
export type GenerativeOutputType = 'string' | 'object' | 'image' | 'video' | 'audio'
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Human interaction channels
|
|
216
|
+
*
|
|
217
|
+
* - chat: Real-time messaging (WebSocket, in-app)
|
|
218
|
+
* - email: Async email communication
|
|
219
|
+
* - phone: Voice calls
|
|
220
|
+
* - sms: SMS text messages
|
|
221
|
+
* - workspace: Team collaboration platforms (Slack, Teams, Discord)
|
|
222
|
+
* - web: Web-based interface (browser, web app)
|
|
223
|
+
*/
|
|
224
|
+
export type HumanChannel = 'chat' | 'email' | 'phone' | 'sms' | 'workspace' | 'web'
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Legacy channel type for backwards compatibility
|
|
228
|
+
* @deprecated Use HumanChannel instead
|
|
229
|
+
*/
|
|
230
|
+
export type LegacyHumanChannel = 'slack' | 'email' | 'web' | 'sms' | 'custom'
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Schema limitations that apply across providers
|
|
234
|
+
* These constraints ensure compatibility with OpenAI, Anthropic, and Google
|
|
235
|
+
*/
|
|
236
|
+
export interface SchemaLimitations {
|
|
237
|
+
/** OpenAI requires additionalProperties: false on all objects */
|
|
238
|
+
noAdditionalProperties: true
|
|
239
|
+
/** OpenAI requires all properties in 'required' - no optional keys */
|
|
240
|
+
allPropertiesRequired: true
|
|
241
|
+
/** OpenAI doesn't support default values */
|
|
242
|
+
noDefaultValues: true
|
|
243
|
+
/** No recursive schema definitions (all providers) */
|
|
244
|
+
noRecursiveSchemas: true
|
|
245
|
+
/** No external $ref URLs (all providers) */
|
|
246
|
+
noExternalRefs: true
|
|
247
|
+
/** Anthropic doesn't support min/max on numbers */
|
|
248
|
+
noNumericBounds: true
|
|
249
|
+
/** Anthropic doesn't support minLength/maxLength on strings */
|
|
250
|
+
noStringLengthBounds: true
|
|
251
|
+
/** Anthropic only supports minItems of 0 or 1 */
|
|
252
|
+
limitedArrayMinItems: true
|
|
253
|
+
/** Anthropic doesn't support complex types in enums */
|
|
254
|
+
simpleEnumsOnly: true
|
|
255
|
+
/** Anthropic doesn't support lookahead/lookbehind in regex */
|
|
256
|
+
simpleRegexOnly: true
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Base definition shared by all function types
|
|
261
|
+
*/
|
|
262
|
+
export interface BaseFunctionDefinition<TArgs = unknown, TReturn = unknown> {
|
|
263
|
+
/** Function name (used as the callable identifier) */
|
|
264
|
+
name: string
|
|
265
|
+
/** Human-readable description of what this function does */
|
|
266
|
+
description?: string
|
|
267
|
+
/** Arguments schema - SimpleSchema or Zod schema */
|
|
268
|
+
args: TArgs
|
|
269
|
+
/** Return type schema - SimpleSchema or Zod schema (optional) */
|
|
270
|
+
returnType?: TReturn
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Code function - generates actual executable code
|
|
275
|
+
*
|
|
276
|
+
* When called, this generates:
|
|
277
|
+
* - Implementation code with JSDoc comments
|
|
278
|
+
* - Vitest test cases
|
|
279
|
+
* - Example usage scripts
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* ```ts
|
|
283
|
+
* defineFunction({
|
|
284
|
+
* type: 'code',
|
|
285
|
+
* name: 'calculateTax',
|
|
286
|
+
* args: {
|
|
287
|
+
* amount: 'The amount to calculate tax on (number)',
|
|
288
|
+
* rate: 'Tax rate as decimal (number)',
|
|
289
|
+
* },
|
|
290
|
+
* returnType: 'The calculated tax amount (number)',
|
|
291
|
+
* language: 'typescript',
|
|
292
|
+
* })
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
export interface CodeFunctionDefinition<TArgs = unknown, TReturn = unknown>
|
|
296
|
+
extends BaseFunctionDefinition<TArgs, TReturn> {
|
|
297
|
+
type: 'code'
|
|
298
|
+
/** Target programming language */
|
|
299
|
+
language?: CodeLanguage
|
|
300
|
+
/** Additional context or requirements for code generation */
|
|
301
|
+
instructions?: string
|
|
302
|
+
/** Whether to include vitest tests (default: true) */
|
|
303
|
+
includeTests?: boolean
|
|
304
|
+
/** Whether to include example usage (default: true) */
|
|
305
|
+
includeExamples?: boolean
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Code function result with generated artifacts
|
|
310
|
+
*/
|
|
311
|
+
export interface CodeFunctionResult {
|
|
312
|
+
/** The generated implementation code */
|
|
313
|
+
code: string
|
|
314
|
+
/** Generated vitest test code */
|
|
315
|
+
tests?: string
|
|
316
|
+
/** Generated example usage code */
|
|
317
|
+
examples?: string
|
|
318
|
+
/** The language the code was generated in */
|
|
319
|
+
language: CodeLanguage
|
|
320
|
+
/** JSDoc or equivalent documentation */
|
|
321
|
+
documentation: string
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Generative function - uses AI to generate text, objects, or media
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* defineFunction({
|
|
330
|
+
* type: 'generative',
|
|
331
|
+
* name: 'summarize',
|
|
332
|
+
* args: { text: 'The text to summarize' },
|
|
333
|
+
* output: 'string',
|
|
334
|
+
* system: 'You are an expert summarizer.',
|
|
335
|
+
* promptTemplate: 'Summarize the following text:\n\n{{text}}',
|
|
336
|
+
* })
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
export interface GenerativeFunctionDefinition<TArgs = unknown, TReturn = unknown>
|
|
340
|
+
extends BaseFunctionDefinition<TArgs, TReturn> {
|
|
341
|
+
type: 'generative'
|
|
342
|
+
/** What type of output this function produces */
|
|
343
|
+
output: GenerativeOutputType
|
|
344
|
+
/** System prompt for the AI */
|
|
345
|
+
system?: string
|
|
346
|
+
/** Prompt template with {{arg}} placeholders */
|
|
347
|
+
promptTemplate?: string
|
|
348
|
+
/** Model to use (defaults to 'sonnet') */
|
|
349
|
+
model?: string
|
|
350
|
+
/** Temperature for generation (0-2) */
|
|
351
|
+
temperature?: number
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Generative function result
|
|
356
|
+
*/
|
|
357
|
+
export interface GenerativeFunctionResult<T = unknown> {
|
|
358
|
+
/** Generated text (if output is 'string') */
|
|
359
|
+
text?: string
|
|
360
|
+
/** Generated object (if output is 'object') */
|
|
361
|
+
object?: T
|
|
362
|
+
/** Generated image (if output is 'image') */
|
|
363
|
+
image?: ImageResult
|
|
364
|
+
/** Generated video (if output is 'video') */
|
|
365
|
+
video?: VideoResult
|
|
366
|
+
/** Generated audio URL (if output is 'audio') */
|
|
367
|
+
audio?: { url: string; duration: number }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Agentic function - runs in a loop with tools until completion
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* defineFunction({
|
|
376
|
+
* type: 'agentic',
|
|
377
|
+
* name: 'researchTopic',
|
|
378
|
+
* args: { topic: 'The topic to research' },
|
|
379
|
+
* returnType: {
|
|
380
|
+
* summary: 'Research summary',
|
|
381
|
+
* sources: ['List of sources'],
|
|
382
|
+
* },
|
|
383
|
+
* instructions: 'Research the topic thoroughly using available tools.',
|
|
384
|
+
* tools: [searchTool, fetchTool],
|
|
385
|
+
* maxIterations: 10,
|
|
386
|
+
* })
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
export interface AgenticFunctionDefinition<TArgs = unknown, TReturn = unknown>
|
|
390
|
+
extends BaseFunctionDefinition<TArgs, TReturn> {
|
|
391
|
+
type: 'agentic'
|
|
392
|
+
/** Instructions for the agent on how to accomplish the task */
|
|
393
|
+
instructions: string
|
|
394
|
+
/** Prompt template with {{arg}} placeholders */
|
|
395
|
+
promptTemplate?: string
|
|
396
|
+
/** Tools available to the agent */
|
|
397
|
+
tools?: AIFunctionDefinition[]
|
|
398
|
+
/** Maximum number of iterations before stopping (default: 10) */
|
|
399
|
+
maxIterations?: number
|
|
400
|
+
/** Model to use for the agent (defaults to 'sonnet') */
|
|
401
|
+
model?: string
|
|
402
|
+
/** Whether to stream intermediate results */
|
|
403
|
+
stream?: boolean
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Agentic function execution state
|
|
408
|
+
*/
|
|
409
|
+
export interface AgenticExecutionState {
|
|
410
|
+
/** Current iteration number */
|
|
411
|
+
iteration: number
|
|
412
|
+
/** Tool calls made so far */
|
|
413
|
+
toolCalls: AIFunctionCall[]
|
|
414
|
+
/** Intermediate results */
|
|
415
|
+
intermediateResults: unknown[]
|
|
416
|
+
/** Whether the agent has completed */
|
|
417
|
+
completed: boolean
|
|
418
|
+
/** Final result (if completed) */
|
|
419
|
+
result?: unknown
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Human function - requires human input/approval
|
|
424
|
+
*
|
|
425
|
+
* Generates appropriate UI/interaction for the specified channel:
|
|
426
|
+
* - slack: Generates Slack BlockKit JSON
|
|
427
|
+
* - email: Generates email template
|
|
428
|
+
* - web: Generates form/UI component
|
|
429
|
+
* - sms: Generates SMS-friendly text
|
|
430
|
+
* - custom: Provides structured data for custom implementation
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* ```ts
|
|
434
|
+
* defineFunction({
|
|
435
|
+
* type: 'human',
|
|
436
|
+
* name: 'approveExpense',
|
|
437
|
+
* args: {
|
|
438
|
+
* amount: 'Expense amount (number)',
|
|
439
|
+
* description: 'What the expense is for',
|
|
440
|
+
* submitter: 'Who submitted the expense',
|
|
441
|
+
* },
|
|
442
|
+
* returnType: {
|
|
443
|
+
* approved: 'Whether the expense was approved (boolean)',
|
|
444
|
+
* notes: 'Any notes from the approver',
|
|
445
|
+
* },
|
|
446
|
+
* channel: 'workspace',
|
|
447
|
+
* instructions: 'Review the expense request and approve or reject it.',
|
|
448
|
+
* })
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
export interface HumanFunctionDefinition<TArgs = unknown, TReturn = unknown>
|
|
452
|
+
extends BaseFunctionDefinition<TArgs, TReturn> {
|
|
453
|
+
type: 'human'
|
|
454
|
+
/** How to interact with the human */
|
|
455
|
+
channel: HumanChannel
|
|
456
|
+
/** Instructions shown to the human */
|
|
457
|
+
instructions: string
|
|
458
|
+
/** Prompt template with {{arg}} placeholders for the request */
|
|
459
|
+
promptTemplate?: string
|
|
460
|
+
/** Timeout in milliseconds (default: none - wait indefinitely) */
|
|
461
|
+
timeout?: number
|
|
462
|
+
/** Who should handle this (e.g., user ID, email, channel ID) */
|
|
463
|
+
assignee?: string
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Human function result with channel-specific artifacts
|
|
468
|
+
*/
|
|
469
|
+
export interface HumanFunctionResult<T = unknown> {
|
|
470
|
+
/** The human's response */
|
|
471
|
+
response: T
|
|
472
|
+
/** Who responded */
|
|
473
|
+
respondedBy?: string
|
|
474
|
+
/** When they responded */
|
|
475
|
+
respondedAt?: Date
|
|
476
|
+
/** Channel-specific artifacts */
|
|
477
|
+
artifacts?: {
|
|
478
|
+
/** Slack BlockKit JSON */
|
|
479
|
+
slackBlocks?: unknown[]
|
|
480
|
+
/** Email HTML template */
|
|
481
|
+
emailHtml?: string
|
|
482
|
+
/** Web form component */
|
|
483
|
+
webComponent?: string
|
|
484
|
+
/** SMS message text */
|
|
485
|
+
smsText?: string
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Union of all function definition types
|
|
491
|
+
*/
|
|
492
|
+
export type FunctionDefinition<TArgs = unknown, TReturn = unknown> =
|
|
493
|
+
| CodeFunctionDefinition<TArgs, TReturn>
|
|
494
|
+
| GenerativeFunctionDefinition<TArgs, TReturn>
|
|
495
|
+
| AgenticFunctionDefinition<TArgs, TReturn>
|
|
496
|
+
| HumanFunctionDefinition<TArgs, TReturn>
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Result of defineFunction - a callable with metadata
|
|
500
|
+
*/
|
|
501
|
+
export interface DefinedFunction<TArgs = unknown, TReturn = unknown> {
|
|
502
|
+
/** The original definition */
|
|
503
|
+
definition: FunctionDefinition<TArgs, TReturn>
|
|
504
|
+
/** Call the function */
|
|
505
|
+
call: (args: TArgs) => Promise<TReturn>
|
|
506
|
+
/** Get the function as a tool definition for AI */
|
|
507
|
+
asTool: () => AIFunctionDefinition<TArgs, TReturn>
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Function registry for storing and retrieving defined functions
|
|
512
|
+
*
|
|
513
|
+
* Note: This is in-memory only. For persistence, use mdxai or mdxdb packages.
|
|
514
|
+
*/
|
|
515
|
+
export interface FunctionRegistry {
|
|
516
|
+
/** Get a function by name */
|
|
517
|
+
get(name: string): DefinedFunction | undefined
|
|
518
|
+
/** Set/store a function */
|
|
519
|
+
set(name: string, fn: DefinedFunction): void
|
|
520
|
+
/** Check if a function exists */
|
|
521
|
+
has(name: string): boolean
|
|
522
|
+
/** List all function names */
|
|
523
|
+
list(): string[]
|
|
524
|
+
/** Delete a function */
|
|
525
|
+
delete(name: string): boolean
|
|
526
|
+
/** Clear all functions */
|
|
527
|
+
clear(): void
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Result of auto-defining a function
|
|
532
|
+
*/
|
|
533
|
+
export interface AutoDefineResult {
|
|
534
|
+
/** The determined function type */
|
|
535
|
+
type: 'code' | 'generative' | 'agentic' | 'human'
|
|
536
|
+
/** Reasoning for why this type was chosen */
|
|
537
|
+
reasoning: string
|
|
538
|
+
/** The complete function definition */
|
|
539
|
+
definition: FunctionDefinition
|
|
540
|
+
}
|
package/test/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# ai-functions Tests
|
|
2
|
+
|
|
3
|
+
Integration tests for ai-functions using real AI models via Cloudflare AI Gateway.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
Set environment variables in `.env` at the project root:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
AI_GATEWAY_URL=https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_name}
|
|
11
|
+
AI_GATEWAY_TOKEN=your-gateway-token
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The AI Gateway should have secrets configured for:
|
|
15
|
+
- `anthropic` - Anthropic API key
|
|
16
|
+
- `openai` - OpenAI API key
|
|
17
|
+
- `openrouter` - OpenRouter API key
|
|
18
|
+
|
|
19
|
+
## Running Tests
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Run all tests
|
|
23
|
+
pnpm test
|
|
24
|
+
|
|
25
|
+
# Run specific test file
|
|
26
|
+
npx vitest run test/generate.test.ts
|
|
27
|
+
|
|
28
|
+
# Watch mode
|
|
29
|
+
npx vitest
|
|
30
|
+
|
|
31
|
+
# With verbose output
|
|
32
|
+
npx vitest run --reporter=verbose
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Test Files
|
|
36
|
+
|
|
37
|
+
| File | Description |
|
|
38
|
+
|------|-------------|
|
|
39
|
+
| `schema.test.ts` | Pure unit tests for schema conversion (no AI calls) |
|
|
40
|
+
| `embeddings.test.ts` | Embedding utility tests (mostly pure, 2 skipped API tests) |
|
|
41
|
+
| `generate.test.ts` | generateObject/generateText with real AI calls |
|
|
42
|
+
| `ai-proxy.test.ts` | AI() proxy and schema functions |
|
|
43
|
+
| `define.test.ts` | Function registry and defineFunction |
|
|
44
|
+
|
|
45
|
+
## Test Configuration
|
|
46
|
+
|
|
47
|
+
Tests use:
|
|
48
|
+
- **vitest** for test runner
|
|
49
|
+
- **dotenv** for loading env vars from parent directories
|
|
50
|
+
- **Sequential execution** to avoid rate limiting (`singleFork: true`)
|
|
51
|
+
- **60s timeout** for AI calls
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
### No Mocking
|
|
56
|
+
|
|
57
|
+
Tests call real AI models through Cloudflare AI Gateway. This ensures:
|
|
58
|
+
- Actual API compatibility
|
|
59
|
+
- Real response validation
|
|
60
|
+
- Gateway caching for efficiency
|
|
61
|
+
|
|
62
|
+
### Gateway Caching
|
|
63
|
+
|
|
64
|
+
Cloudflare AI Gateway caches responses, so:
|
|
65
|
+
- First run may be slower
|
|
66
|
+
- Subsequent runs use cached responses
|
|
67
|
+
- Tests are idempotent with same inputs
|
|
68
|
+
|
|
69
|
+
### Model Routing
|
|
70
|
+
|
|
71
|
+
All models route through OpenRouter:
|
|
72
|
+
- `'sonnet'` → `openrouter:anthropic/claude-sonnet-4.5`
|
|
73
|
+
- `'gpt-4o'` → `openrouter:openai/gpt-4o`
|
|
74
|
+
- OpenRouter handles model ID translation
|
|
75
|
+
|
|
76
|
+
## Writing Tests
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { describe, it, expect } from 'vitest'
|
|
80
|
+
import { generateObject } from '../src/generate.js'
|
|
81
|
+
|
|
82
|
+
const hasGateway = !!process.env.AI_GATEWAY_URL
|
|
83
|
+
|
|
84
|
+
describe.skipIf(!hasGateway)('my tests', () => {
|
|
85
|
+
it('generates output', async () => {
|
|
86
|
+
const { object } = await generateObject({
|
|
87
|
+
model: 'sonnet',
|
|
88
|
+
schema: { message: 'A greeting' },
|
|
89
|
+
prompt: 'Say hello',
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
expect(object.message).toBeDefined()
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Debugging
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Check env loading
|
|
101
|
+
node -e "require('dotenv').config({ path: '../../../.env' }); console.log(process.env.AI_GATEWAY_URL)"
|
|
102
|
+
|
|
103
|
+
# Run single test with logs
|
|
104
|
+
npx vitest run test/generate.test.ts -t "generates simple"
|
|
105
|
+
```
|