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,694 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for core AI functions
|
|
3
|
+
*
|
|
4
|
+
* These tests verify the API contracts for each function.
|
|
5
|
+
* Tests marked with .skipIf(!hasGateway) require actual AI calls.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
9
|
+
import { stringify as yamlStringify } from 'yaml'
|
|
10
|
+
|
|
11
|
+
// Skip tests if no gateway configured
|
|
12
|
+
const hasGateway = !!process.env.AI_GATEWAY_URL || !!process.env.ANTHROPIC_API_KEY
|
|
13
|
+
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Mock implementations for unit tests
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
// Mock generate function that all others should call
|
|
19
|
+
const mockGenerate = vi.fn()
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// ai() - Direct text generation
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
describe('ai()', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
mockGenerate.mockReset()
|
|
28
|
+
mockGenerate.mockResolvedValue('Generated text')
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should accept a string prompt', async () => {
|
|
32
|
+
const ai = createMockAi()
|
|
33
|
+
const result = await ai('Write a haiku')
|
|
34
|
+
|
|
35
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
36
|
+
'text',
|
|
37
|
+
'Write a haiku',
|
|
38
|
+
expect.any(Object)
|
|
39
|
+
)
|
|
40
|
+
expect(result).toBe('Generated text')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should accept tagged template literal', async () => {
|
|
44
|
+
const ai = createMockAi()
|
|
45
|
+
const topic = 'TypeScript'
|
|
46
|
+
const result = await ai`Write about ${topic}`
|
|
47
|
+
|
|
48
|
+
expect(mockGenerate).toHaveBeenCalled()
|
|
49
|
+
const [, prompt] = mockGenerate.mock.calls[0]
|
|
50
|
+
expect(prompt).toContain('TypeScript')
|
|
51
|
+
expect(result).toBe('Generated text')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should accept options parameter', async () => {
|
|
55
|
+
const ai = createMockAi()
|
|
56
|
+
await ai`test`({ model: 'claude-opus-4-5' })
|
|
57
|
+
|
|
58
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
59
|
+
'text',
|
|
60
|
+
'test',
|
|
61
|
+
expect.objectContaining({ model: 'claude-opus-4-5' })
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should return string type', async () => {
|
|
66
|
+
const ai = createMockAi()
|
|
67
|
+
const result = await ai('test')
|
|
68
|
+
expect(typeof result).toBe('string')
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// summarize() - Condense text
|
|
74
|
+
// ============================================================================
|
|
75
|
+
|
|
76
|
+
describe('summarize()', () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
mockGenerate.mockReset()
|
|
79
|
+
mockGenerate.mockResolvedValue('Summary of content')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should accept text to summarize', async () => {
|
|
83
|
+
const summarize = createMockSummarize()
|
|
84
|
+
const result = await summarize`${longArticle}`
|
|
85
|
+
|
|
86
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
87
|
+
'summary',
|
|
88
|
+
expect.stringContaining('article'),
|
|
89
|
+
expect.any(Object)
|
|
90
|
+
)
|
|
91
|
+
expect(result).toBe('Summary of content')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('should support length option', async () => {
|
|
95
|
+
const summarize = createMockSummarize()
|
|
96
|
+
await summarize`${longArticle}`({ length: 'short' })
|
|
97
|
+
|
|
98
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
99
|
+
'summary',
|
|
100
|
+
expect.any(String),
|
|
101
|
+
expect.objectContaining({ length: 'short' })
|
|
102
|
+
)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should support audience option', async () => {
|
|
106
|
+
const summarize = createMockSummarize()
|
|
107
|
+
await summarize`${technicalReport}${{ audience: 'executives', focus: 'business impact' }}`
|
|
108
|
+
|
|
109
|
+
const [, prompt] = mockGenerate.mock.calls[0]
|
|
110
|
+
expect(prompt).toContain('executives')
|
|
111
|
+
expect(prompt).toContain('business impact')
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// is() - Boolean classification
|
|
117
|
+
// ============================================================================
|
|
118
|
+
|
|
119
|
+
describe('is()', () => {
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
mockGenerate.mockReset()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('should return boolean true', async () => {
|
|
125
|
+
mockGenerate.mockResolvedValue(true)
|
|
126
|
+
const is = createMockIs()
|
|
127
|
+
|
|
128
|
+
const result = await is`${'hello@example.com'} a valid email?`
|
|
129
|
+
expect(result).toBe(true)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('should return boolean false', async () => {
|
|
133
|
+
mockGenerate.mockResolvedValue(false)
|
|
134
|
+
const is = createMockIs()
|
|
135
|
+
|
|
136
|
+
const result = await is`${'not-an-email'} a valid email?`
|
|
137
|
+
expect(result).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('should accept natural question format', async () => {
|
|
141
|
+
mockGenerate.mockResolvedValue(true)
|
|
142
|
+
const is = createMockIs()
|
|
143
|
+
|
|
144
|
+
await is`${'The product is amazing!'} positive sentiment?`
|
|
145
|
+
|
|
146
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
147
|
+
'boolean',
|
|
148
|
+
expect.stringContaining('positive sentiment'),
|
|
149
|
+
expect.any(Object)
|
|
150
|
+
)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('should support model option for complex classifications', async () => {
|
|
154
|
+
mockGenerate.mockResolvedValue(true)
|
|
155
|
+
const is = createMockIs()
|
|
156
|
+
|
|
157
|
+
await is`${claim} factually accurate?`({ model: 'claude-opus-4-5' })
|
|
158
|
+
|
|
159
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
160
|
+
'boolean',
|
|
161
|
+
expect.any(String),
|
|
162
|
+
expect.objectContaining({ model: 'claude-opus-4-5' })
|
|
163
|
+
)
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// list() - Generate a list
|
|
169
|
+
// ============================================================================
|
|
170
|
+
|
|
171
|
+
describe('list()', () => {
|
|
172
|
+
beforeEach(() => {
|
|
173
|
+
mockGenerate.mockReset()
|
|
174
|
+
mockGenerate.mockResolvedValue(['Item 1', 'Item 2', 'Item 3'])
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('should return an array of strings', async () => {
|
|
178
|
+
const list = createMockList()
|
|
179
|
+
const result = await list`startup ideas for ${industry}`
|
|
180
|
+
|
|
181
|
+
expect(Array.isArray(result)).toBe(true)
|
|
182
|
+
expect(result).toHaveLength(3)
|
|
183
|
+
expect(result.every((item: unknown) => typeof item === 'string')).toBe(true)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('should respect count in prompt', async () => {
|
|
187
|
+
const list = createMockList()
|
|
188
|
+
await list`10 blog post titles for ${topic}`
|
|
189
|
+
|
|
190
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
191
|
+
'list',
|
|
192
|
+
expect.stringContaining('10'),
|
|
193
|
+
expect.any(Object)
|
|
194
|
+
)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('should support count option', async () => {
|
|
198
|
+
const list = createMockList()
|
|
199
|
+
await list('startup ideas', { count: 10 })
|
|
200
|
+
|
|
201
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
202
|
+
'list',
|
|
203
|
+
'startup ideas',
|
|
204
|
+
expect.objectContaining({ count: 10 })
|
|
205
|
+
)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// lists() - Generate multiple named lists
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
describe('lists()', () => {
|
|
214
|
+
beforeEach(() => {
|
|
215
|
+
mockGenerate.mockReset()
|
|
216
|
+
mockGenerate.mockResolvedValue({
|
|
217
|
+
pros: ['Pro 1', 'Pro 2'],
|
|
218
|
+
cons: ['Con 1', 'Con 2'],
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('should return named lists object', async () => {
|
|
223
|
+
const lists = createMockLists()
|
|
224
|
+
const result = await lists`pros and cons of ${topic}`
|
|
225
|
+
|
|
226
|
+
expect(result).toHaveProperty('pros')
|
|
227
|
+
expect(result).toHaveProperty('cons')
|
|
228
|
+
expect(Array.isArray(result.pros)).toBe(true)
|
|
229
|
+
expect(Array.isArray(result.cons)).toBe(true)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('should support SWOT analysis format', async () => {
|
|
233
|
+
mockGenerate.mockResolvedValue({
|
|
234
|
+
strengths: ['S1'],
|
|
235
|
+
weaknesses: ['W1'],
|
|
236
|
+
opportunities: ['O1'],
|
|
237
|
+
threats: ['T1'],
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
const lists = createMockLists()
|
|
241
|
+
const result = await lists`SWOT analysis for ${{ company, market }}`
|
|
242
|
+
|
|
243
|
+
expect(result).toHaveProperty('strengths')
|
|
244
|
+
expect(result).toHaveProperty('weaknesses')
|
|
245
|
+
expect(result).toHaveProperty('opportunities')
|
|
246
|
+
expect(result).toHaveProperty('threats')
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// extract() - Extract from text
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
describe('extract()', () => {
|
|
255
|
+
beforeEach(() => {
|
|
256
|
+
mockGenerate.mockReset()
|
|
257
|
+
mockGenerate.mockResolvedValue(['John Smith', 'Jane Doe'])
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it('should extract items from text', async () => {
|
|
261
|
+
const extract = createMockExtract()
|
|
262
|
+
const result = await extract`person names from ${article}`
|
|
263
|
+
|
|
264
|
+
expect(Array.isArray(result)).toBe(true)
|
|
265
|
+
expect(result).toContain('John Smith')
|
|
266
|
+
expect(result).toContain('Jane Doe')
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('should support schema for structured extraction', async () => {
|
|
270
|
+
mockGenerate.mockResolvedValue([
|
|
271
|
+
{ name: 'Acme Corp', role: 'competitor' },
|
|
272
|
+
{ name: 'Beta Inc', role: 'partner' },
|
|
273
|
+
])
|
|
274
|
+
|
|
275
|
+
const extract = createMockExtract()
|
|
276
|
+
const result = await extract`companies from ${text}${{
|
|
277
|
+
schema: {
|
|
278
|
+
name: 'Company name',
|
|
279
|
+
role: 'mentioned as: competitor | partner | customer',
|
|
280
|
+
},
|
|
281
|
+
}}`
|
|
282
|
+
|
|
283
|
+
expect(result[0]).toHaveProperty('name')
|
|
284
|
+
expect(result[0]).toHaveProperty('role')
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
// ============================================================================
|
|
289
|
+
// write() - Generate text content
|
|
290
|
+
// ============================================================================
|
|
291
|
+
|
|
292
|
+
describe('write()', () => {
|
|
293
|
+
beforeEach(() => {
|
|
294
|
+
mockGenerate.mockReset()
|
|
295
|
+
mockGenerate.mockResolvedValue('Generated content here...')
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
it('should generate text content', async () => {
|
|
299
|
+
const write = createMockWrite()
|
|
300
|
+
const result = await write`professional email to ${recipient} about ${subject}`
|
|
301
|
+
|
|
302
|
+
expect(typeof result).toBe('string')
|
|
303
|
+
expect(result.length).toBeGreaterThan(0)
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should support tone option', async () => {
|
|
307
|
+
const write = createMockWrite()
|
|
308
|
+
await write('blog post', { tone: 'casual', topic: 'TypeScript' })
|
|
309
|
+
|
|
310
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
311
|
+
'text',
|
|
312
|
+
'blog post',
|
|
313
|
+
expect.objectContaining({ tone: 'casual' })
|
|
314
|
+
)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('should support length option', async () => {
|
|
318
|
+
const write = createMockWrite()
|
|
319
|
+
await write('article', { length: 'long' })
|
|
320
|
+
|
|
321
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
322
|
+
'text',
|
|
323
|
+
'article',
|
|
324
|
+
expect.objectContaining({ length: 'long' })
|
|
325
|
+
)
|
|
326
|
+
})
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// ============================================================================
|
|
330
|
+
// code() - Generate code
|
|
331
|
+
// ============================================================================
|
|
332
|
+
|
|
333
|
+
describe('code()', () => {
|
|
334
|
+
beforeEach(() => {
|
|
335
|
+
mockGenerate.mockReset()
|
|
336
|
+
mockGenerate.mockResolvedValue('function validate(email) { return email.includes("@"); }')
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('should generate code', async () => {
|
|
340
|
+
const code = createMockCode()
|
|
341
|
+
const result = await code`email validation function`
|
|
342
|
+
|
|
343
|
+
expect(typeof result).toBe('string')
|
|
344
|
+
expect(result).toContain('function')
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
it('should support language option', async () => {
|
|
348
|
+
const code = createMockCode()
|
|
349
|
+
await code('REST API endpoints', { language: 'typescript' })
|
|
350
|
+
|
|
351
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
352
|
+
'code',
|
|
353
|
+
'REST API endpoints',
|
|
354
|
+
expect.objectContaining({ language: 'typescript' })
|
|
355
|
+
)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
it('should handle complex requirements via object interpolation', async () => {
|
|
359
|
+
const code = createMockCode()
|
|
360
|
+
const requirements = {
|
|
361
|
+
pages: ['home', 'about', 'pricing'],
|
|
362
|
+
features: ['dark mode', 'animations'],
|
|
363
|
+
stack: 'Next.js + Tailwind',
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await code`marketing website${{ requirements }}`
|
|
367
|
+
|
|
368
|
+
const [, prompt] = mockGenerate.mock.calls[0]
|
|
369
|
+
expect(prompt).toContain('pages:')
|
|
370
|
+
expect(prompt).toContain('- home')
|
|
371
|
+
expect(prompt).toContain('features:')
|
|
372
|
+
})
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
// ============================================================================
|
|
376
|
+
// diagram() - Generate diagrams
|
|
377
|
+
// ============================================================================
|
|
378
|
+
|
|
379
|
+
describe('diagram()', () => {
|
|
380
|
+
beforeEach(() => {
|
|
381
|
+
mockGenerate.mockReset()
|
|
382
|
+
mockGenerate.mockResolvedValue('graph TD\n A --> B\n B --> C')
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('should generate mermaid diagrams', async () => {
|
|
386
|
+
const diagram = createMockDiagram()
|
|
387
|
+
const result = await diagram`user authentication flow`
|
|
388
|
+
|
|
389
|
+
expect(typeof result).toBe('string')
|
|
390
|
+
expect(result).toContain('graph')
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('should support format option', async () => {
|
|
394
|
+
const diagram = createMockDiagram()
|
|
395
|
+
await diagram('database schema', { format: 'mermaid', type: 'erd' })
|
|
396
|
+
|
|
397
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
398
|
+
'diagram',
|
|
399
|
+
'database schema',
|
|
400
|
+
expect.objectContaining({ format: 'mermaid', type: 'erd' })
|
|
401
|
+
)
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
// ============================================================================
|
|
406
|
+
// slides() - Generate presentations
|
|
407
|
+
// ============================================================================
|
|
408
|
+
|
|
409
|
+
describe('slides()', () => {
|
|
410
|
+
beforeEach(() => {
|
|
411
|
+
mockGenerate.mockReset()
|
|
412
|
+
mockGenerate.mockResolvedValue('---\ntheme: default\n---\n\n# Slide 1\n\nContent here')
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
it('should generate slidev-format markdown', async () => {
|
|
416
|
+
const slides = createMockSlides()
|
|
417
|
+
const result = await slides`${topic}`
|
|
418
|
+
|
|
419
|
+
expect(typeof result).toBe('string')
|
|
420
|
+
expect(result).toContain('---')
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
it('should support format option', async () => {
|
|
424
|
+
const slides = createMockSlides()
|
|
425
|
+
await slides('quarterly review', { format: 'marp', slides: 12 })
|
|
426
|
+
|
|
427
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
428
|
+
'slides',
|
|
429
|
+
'quarterly review',
|
|
430
|
+
expect.objectContaining({ format: 'marp', slides: 12 })
|
|
431
|
+
)
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
it('should support speaker notes', async () => {
|
|
435
|
+
const slides = createMockSlides()
|
|
436
|
+
await slides('workshop', { includeNotes: true, duration: '2 hours' })
|
|
437
|
+
|
|
438
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
439
|
+
'slides',
|
|
440
|
+
'workshop',
|
|
441
|
+
expect.objectContaining({ includeNotes: true })
|
|
442
|
+
)
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
// ============================================================================
|
|
447
|
+
// image() - Generate images
|
|
448
|
+
// ============================================================================
|
|
449
|
+
|
|
450
|
+
describe('image()', () => {
|
|
451
|
+
beforeEach(() => {
|
|
452
|
+
mockGenerate.mockReset()
|
|
453
|
+
mockGenerate.mockResolvedValue(Buffer.from('fake-image-data'))
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
it('should generate image buffer', async () => {
|
|
457
|
+
const image = createMockImage()
|
|
458
|
+
const result = await image`minimalist logo for ${companyName}`
|
|
459
|
+
|
|
460
|
+
expect(Buffer.isBuffer(result)).toBe(true)
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
it('should support size option', async () => {
|
|
464
|
+
const image = createMockImage()
|
|
465
|
+
await image('robot reading a book', { size: '1024x1024', style: 'cartoon' })
|
|
466
|
+
|
|
467
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
468
|
+
'image',
|
|
469
|
+
'robot reading a book',
|
|
470
|
+
expect.objectContaining({ size: '1024x1024', style: 'cartoon' })
|
|
471
|
+
)
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
// ============================================================================
|
|
476
|
+
// video() - Generate videos
|
|
477
|
+
// ============================================================================
|
|
478
|
+
|
|
479
|
+
describe('video()', () => {
|
|
480
|
+
beforeEach(() => {
|
|
481
|
+
mockGenerate.mockReset()
|
|
482
|
+
mockGenerate.mockResolvedValue(Buffer.from('fake-video-data'))
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('should generate video buffer', async () => {
|
|
486
|
+
const video = createMockVideo()
|
|
487
|
+
const result = await video`product demo for ${productName}`
|
|
488
|
+
|
|
489
|
+
expect(Buffer.isBuffer(result)).toBe(true)
|
|
490
|
+
})
|
|
491
|
+
|
|
492
|
+
it('should support duration and aspect options', async () => {
|
|
493
|
+
const video = createMockVideo()
|
|
494
|
+
await video('promotional video', { duration: 30, aspect: '16:9', style: 'motion graphics' })
|
|
495
|
+
|
|
496
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
497
|
+
'video',
|
|
498
|
+
'promotional video',
|
|
499
|
+
expect.objectContaining({ duration: 30, aspect: '16:9' })
|
|
500
|
+
)
|
|
501
|
+
})
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
// ============================================================================
|
|
505
|
+
// research() - Agentic research
|
|
506
|
+
// ============================================================================
|
|
507
|
+
|
|
508
|
+
describe('research()', () => {
|
|
509
|
+
beforeEach(() => {
|
|
510
|
+
mockGenerate.mockReset()
|
|
511
|
+
mockGenerate.mockResolvedValue({
|
|
512
|
+
summary: 'Key findings...',
|
|
513
|
+
sources: [{ url: 'https://example.com', title: 'Source 1' }],
|
|
514
|
+
findings: ['Finding 1', 'Finding 2'],
|
|
515
|
+
confidence: 0.85,
|
|
516
|
+
})
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
it('should return structured research results', async () => {
|
|
520
|
+
const research = createMockResearch()
|
|
521
|
+
const result = await research`${topic}`
|
|
522
|
+
|
|
523
|
+
expect(result).toHaveProperty('summary')
|
|
524
|
+
expect(result).toHaveProperty('sources')
|
|
525
|
+
expect(result).toHaveProperty('findings')
|
|
526
|
+
expect(result).toHaveProperty('confidence')
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
it('should support depth option', async () => {
|
|
530
|
+
const research = createMockResearch()
|
|
531
|
+
await research`market size for AI tools`({ depth: 'thorough' })
|
|
532
|
+
|
|
533
|
+
expect(mockGenerate).toHaveBeenCalledWith(
|
|
534
|
+
'research',
|
|
535
|
+
expect.any(String),
|
|
536
|
+
expect.objectContaining({ depth: 'thorough' })
|
|
537
|
+
)
|
|
538
|
+
})
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
// ============================================================================
|
|
542
|
+
// do() - Single-pass task with tools
|
|
543
|
+
// ============================================================================
|
|
544
|
+
|
|
545
|
+
describe('do()', () => {
|
|
546
|
+
beforeEach(() => {
|
|
547
|
+
mockGenerate.mockReset()
|
|
548
|
+
mockGenerate.mockResolvedValue({ summary: 'Done', result: 'Task completed' })
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
it('should execute a task', async () => {
|
|
552
|
+
const doFn = createMockDo()
|
|
553
|
+
const result = await doFn`translate ${text} to Spanish`
|
|
554
|
+
|
|
555
|
+
expect(result).toBeDefined()
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
it('should handle complex multi-function tasks', async () => {
|
|
559
|
+
mockGenerate.mockResolvedValue({
|
|
560
|
+
summary: 'Article summary',
|
|
561
|
+
people: ['John', 'Jane'],
|
|
562
|
+
actionItems: ['Review', 'Follow up'],
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
const doFn = createMockDo()
|
|
566
|
+
const result = await doFn`
|
|
567
|
+
analyze this article and give me a summary,
|
|
568
|
+
key people mentioned, and action items
|
|
569
|
+
${article}
|
|
570
|
+
`
|
|
571
|
+
|
|
572
|
+
expect(result).toHaveProperty('summary')
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
it('is single-pass, not agentic loop', async () => {
|
|
576
|
+
const doFn = createMockDo()
|
|
577
|
+
await doFn`analyze ${data}`
|
|
578
|
+
|
|
579
|
+
// Should only call generate once (single pass)
|
|
580
|
+
expect(mockGenerate).toHaveBeenCalledTimes(1)
|
|
581
|
+
})
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
// ============================================================================
|
|
585
|
+
// Helper functions to create mock implementations
|
|
586
|
+
// ============================================================================
|
|
587
|
+
|
|
588
|
+
function createMockAi() {
|
|
589
|
+
return createMockFunction('text')
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function createMockSummarize() {
|
|
593
|
+
return createMockFunction('summary')
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function createMockIs() {
|
|
597
|
+
return createMockFunction('boolean')
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function createMockList() {
|
|
601
|
+
return createMockFunction('list')
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function createMockLists() {
|
|
605
|
+
return createMockFunction('lists')
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function createMockExtract() {
|
|
609
|
+
return createMockFunction('extract')
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
function createMockWrite() {
|
|
613
|
+
return createMockFunction('text')
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function createMockCode() {
|
|
617
|
+
return createMockFunction('code')
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function createMockDiagram() {
|
|
621
|
+
return createMockFunction('diagram')
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function createMockSlides() {
|
|
625
|
+
return createMockFunction('slides')
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function createMockImage() {
|
|
629
|
+
return createMockFunction('image')
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function createMockVideo() {
|
|
633
|
+
return createMockFunction('video')
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function createMockResearch() {
|
|
637
|
+
return createMockFunction('research')
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function createMockDo() {
|
|
641
|
+
return createMockFunction('do')
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function createMockFunction(type: string) {
|
|
645
|
+
return function (promptOrStrings: string | TemplateStringsArray, ...args: unknown[]) {
|
|
646
|
+
let prompt: string
|
|
647
|
+
|
|
648
|
+
if (Array.isArray(promptOrStrings) && 'raw' in promptOrStrings) {
|
|
649
|
+
// Tagged template
|
|
650
|
+
prompt = (promptOrStrings as TemplateStringsArray).reduce((acc, str, i) => {
|
|
651
|
+
const value = args[i]
|
|
652
|
+
if (value === undefined) return acc + str
|
|
653
|
+
if (typeof value === 'object' && value !== null) {
|
|
654
|
+
// Convert objects to YAML for readability (matches real implementation)
|
|
655
|
+
return acc + str + '\n' + yamlStringify(value).trim()
|
|
656
|
+
}
|
|
657
|
+
return acc + str + String(value)
|
|
658
|
+
}, '')
|
|
659
|
+
|
|
660
|
+
// Return chainable for options - properly make it thenable
|
|
661
|
+
const basePromise = mockGenerate(type, prompt, {})
|
|
662
|
+
const chainable = (options?: Record<string, unknown>) => mockGenerate(type, prompt, options || {})
|
|
663
|
+
|
|
664
|
+
// Add then/catch to make it awaitable
|
|
665
|
+
;(chainable as unknown as Promise<unknown>).then = basePromise.then.bind(basePromise)
|
|
666
|
+
;(chainable as unknown as Promise<unknown>).catch = basePromise.catch.bind(basePromise)
|
|
667
|
+
|
|
668
|
+
return chainable
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Regular call
|
|
672
|
+
prompt = promptOrStrings as string
|
|
673
|
+
return mockGenerate(type, prompt, args[0] || {})
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// ============================================================================
|
|
678
|
+
// Test fixtures
|
|
679
|
+
// ============================================================================
|
|
680
|
+
|
|
681
|
+
const longArticle = 'This is a long article about technology and innovation...'
|
|
682
|
+
const technicalReport = 'Technical analysis of system performance metrics...'
|
|
683
|
+
const industry = 'fintech'
|
|
684
|
+
const topic = 'TypeScript'
|
|
685
|
+
const claim = 'The Earth is round'
|
|
686
|
+
const article = 'Article mentioning John Smith and Jane Doe...'
|
|
687
|
+
const text = 'Some text content'
|
|
688
|
+
const company = 'Acme Corp'
|
|
689
|
+
const market = 'SaaS'
|
|
690
|
+
const recipient = 'John'
|
|
691
|
+
const subject = 'Project Update'
|
|
692
|
+
const companyName = 'TechCorp'
|
|
693
|
+
const productName = 'ProductX'
|
|
694
|
+
const data = { key: 'value' }
|