ai-functions 2.1.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +55 -1
- package/README.md +38 -0
- package/dist/ai-promise.d.ts +3 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +135 -64
- package/dist/ai-promise.js.map +1 -1
- package/dist/ai-schemas.d.ts +56 -0
- package/dist/ai-schemas.d.ts.map +1 -0
- package/dist/ai-schemas.js +53 -0
- package/dist/ai-schemas.js.map +1 -0
- package/dist/ai.d.ts +16 -242
- package/dist/ai.d.ts.map +1 -1
- package/dist/ai.js +51 -858
- package/dist/ai.js.map +1 -1
- package/dist/batch/anthropic.d.ts +6 -4
- package/dist/batch/anthropic.d.ts.map +1 -1
- package/dist/batch/anthropic.js +83 -145
- package/dist/batch/anthropic.js.map +1 -1
- package/dist/batch/bedrock.d.ts +8 -30
- package/dist/batch/bedrock.d.ts.map +1 -1
- package/dist/batch/bedrock.js +155 -338
- package/dist/batch/bedrock.js.map +1 -1
- package/dist/batch/cloudflare.d.ts +8 -20
- package/dist/batch/cloudflare.d.ts.map +1 -1
- package/dist/batch/cloudflare.js +68 -189
- package/dist/batch/cloudflare.js.map +1 -1
- package/dist/batch/google.d.ts +6 -20
- package/dist/batch/google.d.ts.map +1 -1
- package/dist/batch/google.js +70 -238
- package/dist/batch/google.js.map +1 -1
- package/dist/batch/index.d.ts +4 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +4 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/memory.d.ts +1 -1
- package/dist/batch/memory.d.ts.map +1 -1
- package/dist/batch/memory.js +14 -10
- package/dist/batch/memory.js.map +1 -1
- package/dist/batch/openai.d.ts +11 -14
- package/dist/batch/openai.d.ts.map +1 -1
- package/dist/batch/openai.js +52 -156
- package/dist/batch/openai.js.map +1 -1
- package/dist/batch/provider.d.ts +111 -0
- package/dist/batch/provider.d.ts.map +1 -0
- package/dist/batch/provider.js +233 -0
- package/dist/batch/provider.js.map +1 -0
- package/dist/batch-map.d.ts.map +1 -1
- package/dist/batch-map.js +23 -17
- package/dist/batch-map.js.map +1 -1
- package/dist/batch-queue.d.ts +65 -0
- package/dist/batch-queue.d.ts.map +1 -1
- package/dist/batch-queue.js +169 -14
- package/dist/batch-queue.js.map +1 -1
- package/dist/budget.d.ts.map +1 -1
- package/dist/budget.js +27 -14
- package/dist/budget.js.map +1 -1
- package/dist/cache.d.ts +23 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +36 -15
- package/dist/cache.js.map +1 -1
- package/dist/context.d.ts +26 -8
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +64 -62
- package/dist/context.js.map +1 -1
- package/dist/digital-objects-registry.d.ts +229 -0
- package/dist/digital-objects-registry.d.ts.map +1 -0
- package/dist/digital-objects-registry.js +617 -0
- package/dist/digital-objects-registry.js.map +1 -0
- package/dist/embeddings.d.ts +2 -2
- package/dist/embeddings.d.ts.map +1 -1
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/eval/runner.d.ts +8 -0
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +41 -35
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval-log/in-memory.d.ts +34 -0
- package/dist/eval-log/in-memory.d.ts.map +1 -0
- package/dist/eval-log/in-memory.js +84 -0
- package/dist/eval-log/in-memory.js.map +1 -0
- package/dist/eval-log/index.d.ts +29 -0
- package/dist/eval-log/index.d.ts.map +1 -0
- package/dist/eval-log/index.js +39 -0
- package/dist/eval-log/index.js.map +1 -0
- package/dist/eval-log/types.d.ts +101 -0
- package/dist/eval-log/types.d.ts.map +1 -0
- package/dist/eval-log/types.js +16 -0
- package/dist/eval-log/types.js.map +1 -0
- package/dist/function-registry.d.ts +116 -0
- package/dist/function-registry.d.ts.map +1 -0
- package/dist/function-registry.js +546 -0
- package/dist/function-registry.js.map +1 -0
- package/dist/generate.d.ts +9 -3
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +18 -18
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +18 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -18
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +118 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +187 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware/budget.d.ts +84 -0
- package/dist/middleware/budget.d.ts.map +1 -0
- package/dist/middleware/budget.js +110 -0
- package/dist/middleware/budget.js.map +1 -0
- package/dist/middleware/cache.d.ts +103 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +228 -0
- package/dist/middleware/cache.js.map +1 -0
- package/dist/middleware/embed-cache.d.ts +99 -0
- package/dist/middleware/embed-cache.d.ts.map +1 -0
- package/dist/middleware/embed-cache.js +128 -0
- package/dist/middleware/embed-cache.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/trace.d.ts +103 -0
- package/dist/middleware/trace.d.ts.map +1 -0
- package/dist/middleware/trace.js +176 -0
- package/dist/middleware/trace.js.map +1 -0
- package/dist/primitives.d.ts +120 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +398 -26
- package/dist/primitives.js.map +1 -1
- package/dist/retry.d.ts +66 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +115 -8
- package/dist/retry.js.map +1 -1
- package/dist/schema.js +2 -2
- package/dist/schema.js.map +1 -1
- package/dist/telemetry.d.ts +128 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +285 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +6 -1
- package/dist/template.js.map +1 -1
- package/dist/tool-orchestration.d.ts +66 -4
- package/dist/tool-orchestration.d.ts.map +1 -1
- package/dist/tool-orchestration.js +123 -23
- package/dist/tool-orchestration.js.map +1 -1
- package/dist/type-guards.d.ts +28 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +29 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +135 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +36 -1
- package/dist/types.js.map +1 -1
- package/dist/wrap-for-v3.d.ts +80 -0
- package/dist/wrap-for-v3.d.ts.map +1 -0
- package/dist/wrap-for-v3.js +89 -0
- package/dist/wrap-for-v3.js.map +1 -0
- package/examples/00-quickstart.ts +232 -0
- package/examples/01-rag-chatbot.ts +212 -0
- package/examples/02-multi-agent-research.ts +290 -0
- package/examples/03-email-classification.ts +379 -0
- package/examples/04-content-moderation.ts +400 -0
- package/examples/05-document-extraction.ts +455 -0
- package/examples/06-streaming-chat-nextjs.ts +437 -0
- package/examples/07-cloudflare-worker.ts +483 -0
- package/examples/08-batch-processing.ts +491 -0
- package/examples/09-budget-constrained.ts +527 -0
- package/examples/10-tool-orchestration.ts +565 -0
- package/examples/11-retry-resilience.ts +403 -0
- package/examples/12-caching-strategies.ts +422 -0
- package/examples/README.md +145 -0
- package/package.json +28 -25
- package/src/ai-promise.ts +226 -140
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +69 -1176
- package/src/batch/anthropic.ts +96 -161
- package/src/batch/bedrock.ts +203 -454
- package/src/batch/cloudflare.ts +99 -282
- package/src/batch/google.ts +91 -297
- package/src/batch/index.ts +4 -1
- package/src/batch/memory.ts +15 -10
- package/src/batch/openai.ts +65 -193
- package/src/batch/provider.ts +336 -0
- package/src/batch-map.ts +29 -24
- package/src/batch-queue.ts +200 -11
- package/src/budget.ts +31 -18
- package/src/cache.ts +45 -17
- package/src/context.ts +106 -77
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +60 -36
- package/src/eval-log/in-memory.ts +90 -0
- package/src/eval-log/index.ts +46 -0
- package/src/eval-log/types.ts +110 -0
- package/src/function-registry.ts +671 -0
- package/src/generate.ts +33 -28
- package/src/index.ts +119 -21
- package/src/logger.ts +232 -0
- package/src/middleware/budget.ts +171 -0
- package/src/middleware/cache.ts +299 -0
- package/src/middleware/embed-cache.ts +195 -0
- package/src/middleware/index.ts +23 -0
- package/src/middleware/trace.ts +248 -0
- package/src/primitives.ts +589 -62
- package/src/retry.ts +144 -18
- package/src/schema.ts +8 -8
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +213 -48
- package/src/type-guards.ts +31 -0
- package/src/types.ts +164 -25
- package/src/wrap-for-v3.ts +105 -0
- package/test/ai-promise.test.ts +1080 -0
- package/test/ai-proxy.test.ts +1 -1
- package/test/batch-autosubmit-errors.test.ts +49 -37
- package/test/batch-blog-posts.test.ts +87 -129
- package/test/core-functions.test.ts +183 -579
- package/test/decide.test.ts +154 -322
- package/test/define.test.ts +211 -8
- package/test/digital-objects-registry.test.ts +760 -0
- package/test/embedding-cache-middleware.test.ts +140 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/schema.test.ts +55 -19
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +270 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- package/LICENSE +0 -21
- package/dist/rpc/auth.d.ts +0 -69
- package/dist/rpc/auth.d.ts.map +0 -1
- package/dist/rpc/auth.js +0 -136
- package/dist/rpc/auth.js.map +0 -1
- package/dist/rpc/client.d.ts +0 -62
- package/dist/rpc/client.d.ts.map +0 -1
- package/dist/rpc/client.js +0 -103
- package/dist/rpc/client.js.map +0 -1
- package/dist/rpc/deferred.d.ts +0 -60
- package/dist/rpc/deferred.d.ts.map +0 -1
- package/dist/rpc/deferred.js +0 -96
- package/dist/rpc/deferred.js.map +0 -1
- package/dist/rpc/index.d.ts +0 -22
- package/dist/rpc/index.d.ts.map +0 -1
- package/dist/rpc/index.js +0 -38
- package/dist/rpc/index.js.map +0 -1
- package/dist/rpc/local.d.ts +0 -42
- package/dist/rpc/local.d.ts.map +0 -1
- package/dist/rpc/local.js +0 -50
- package/dist/rpc/local.js.map +0 -1
- package/dist/rpc/server.d.ts +0 -165
- package/dist/rpc/server.d.ts.map +0 -1
- package/dist/rpc/server.js +0 -405
- package/dist/rpc/server.js.map +0 -1
- package/dist/rpc/session.d.ts +0 -32
- package/dist/rpc/session.d.ts.map +0 -1
- package/dist/rpc/session.js +0 -43
- package/dist/rpc/session.js.map +0 -1
- package/dist/rpc/transport.d.ts +0 -306
- package/dist/rpc/transport.d.ts.map +0 -1
- package/dist/rpc/transport.js +0 -731
- package/dist/rpc/transport.js.map +0 -1
- package/src/batch/anthropic.js +0 -256
- package/src/batch/bedrock.js +0 -584
- package/src/batch/cloudflare.js +0 -287
- package/src/batch/google.js +0 -359
- package/src/batch/index.js +0 -30
- package/src/batch/memory.js +0 -187
- package/src/batch/openai.js +0 -402
- package/src/eval/index.js +0 -7
- package/src/eval/models.js +0 -119
- package/src/eval/runner.js +0 -147
- package/test/schema.test.js +0 -96
package/test/define.test.ts
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { describe, it, expect, beforeEach } from 'vitest'
|
|
8
|
-
import { define, defineFunction, functions } from '../src/index.js'
|
|
8
|
+
import { define, defineFunction, functions, createFunctionRegistry, resetGlobalRegistry } from '../src/index.js'
|
|
9
9
|
|
|
10
10
|
// Skip tests if no gateway configured
|
|
11
11
|
const hasGateway = !!process.env.AI_GATEWAY_URL || !!process.env.ANTHROPIC_API_KEY
|
|
12
12
|
|
|
13
13
|
describe('functions registry', () => {
|
|
14
14
|
beforeEach(() => {
|
|
15
|
-
|
|
15
|
+
resetGlobalRegistry()
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
it('starts empty', () => {
|
|
@@ -75,14 +75,152 @@ describe('functions registry', () => {
|
|
|
75
75
|
functions.set('func1', fn1)
|
|
76
76
|
functions.set('func2', fn2)
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
resetGlobalRegistry()
|
|
79
|
+
expect(functions.list()).toEqual([])
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('createFunctionRegistry', () => {
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
resetGlobalRegistry()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('creates an isolated registry instance', () => {
|
|
89
|
+
const registry = createFunctionRegistry()
|
|
90
|
+
expect(registry.list()).toEqual([])
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('registry operations do not affect global registry', () => {
|
|
94
|
+
// Add function to global registry
|
|
95
|
+
const globalFn = defineFunction({
|
|
96
|
+
type: 'generative',
|
|
97
|
+
name: 'globalFunc',
|
|
98
|
+
args: { input: 'Test input' },
|
|
99
|
+
output: 'string',
|
|
100
|
+
})
|
|
101
|
+
functions.set('globalFunc', globalFn)
|
|
102
|
+
|
|
103
|
+
// Create isolated registry and add different function
|
|
104
|
+
const registry = createFunctionRegistry()
|
|
105
|
+
const isolatedFn = defineFunction({
|
|
106
|
+
type: 'generative',
|
|
107
|
+
name: 'isolatedFunc',
|
|
108
|
+
args: { data: 'Test data' },
|
|
109
|
+
output: 'string',
|
|
110
|
+
})
|
|
111
|
+
registry.set('isolatedFunc', isolatedFn)
|
|
112
|
+
|
|
113
|
+
// Verify isolation
|
|
114
|
+
expect(functions.has('globalFunc')).toBe(true)
|
|
115
|
+
expect(functions.has('isolatedFunc')).toBe(false)
|
|
116
|
+
expect(registry.has('isolatedFunc')).toBe(true)
|
|
117
|
+
expect(registry.has('globalFunc')).toBe(false)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('multiple registries are independent of each other', () => {
|
|
121
|
+
const registry1 = createFunctionRegistry()
|
|
122
|
+
const registry2 = createFunctionRegistry()
|
|
123
|
+
|
|
124
|
+
const fn1 = defineFunction({
|
|
125
|
+
type: 'generative',
|
|
126
|
+
name: 'func1',
|
|
127
|
+
args: {},
|
|
128
|
+
output: 'string',
|
|
129
|
+
})
|
|
130
|
+
const fn2 = defineFunction({
|
|
131
|
+
type: 'generative',
|
|
132
|
+
name: 'func2',
|
|
133
|
+
args: {},
|
|
134
|
+
output: 'string',
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
registry1.set('func1', fn1)
|
|
138
|
+
registry2.set('func2', fn2)
|
|
139
|
+
|
|
140
|
+
expect(registry1.has('func1')).toBe(true)
|
|
141
|
+
expect(registry1.has('func2')).toBe(false)
|
|
142
|
+
expect(registry2.has('func1')).toBe(false)
|
|
143
|
+
expect(registry2.has('func2')).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('isolated registry supports all operations', () => {
|
|
147
|
+
const registry = createFunctionRegistry()
|
|
148
|
+
|
|
149
|
+
const fn = defineFunction({
|
|
150
|
+
type: 'generative',
|
|
151
|
+
name: 'testFunc',
|
|
152
|
+
args: { x: 'number' },
|
|
153
|
+
output: 'string',
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// set and get
|
|
157
|
+
registry.set('testFunc', fn)
|
|
158
|
+
expect(registry.get('testFunc')).toBe(fn)
|
|
159
|
+
|
|
160
|
+
// has
|
|
161
|
+
expect(registry.has('testFunc')).toBe(true)
|
|
162
|
+
|
|
163
|
+
// list
|
|
164
|
+
expect(registry.list()).toEqual(['testFunc'])
|
|
165
|
+
|
|
166
|
+
// delete
|
|
167
|
+
expect(registry.delete('testFunc')).toBe(true)
|
|
168
|
+
expect(registry.has('testFunc')).toBe(false)
|
|
169
|
+
|
|
170
|
+
// clear
|
|
171
|
+
registry.set('a', fn)
|
|
172
|
+
registry.set('b', fn)
|
|
173
|
+
registry.clear()
|
|
174
|
+
expect(registry.list()).toEqual([])
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('resetGlobalRegistry', () => {
|
|
179
|
+
it('clears all functions from global registry', () => {
|
|
180
|
+
const fn = defineFunction({
|
|
181
|
+
type: 'generative',
|
|
182
|
+
name: 'testFunc',
|
|
183
|
+
args: {},
|
|
184
|
+
output: 'string',
|
|
185
|
+
})
|
|
186
|
+
functions.set('testFunc', fn)
|
|
187
|
+
expect(functions.has('testFunc')).toBe(true)
|
|
188
|
+
|
|
189
|
+
resetGlobalRegistry()
|
|
190
|
+
expect(functions.has('testFunc')).toBe(false)
|
|
191
|
+
expect(functions.list()).toEqual([])
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('does not affect isolated registries', () => {
|
|
195
|
+
const isolatedRegistry = createFunctionRegistry()
|
|
196
|
+
const fn = defineFunction({
|
|
197
|
+
type: 'generative',
|
|
198
|
+
name: 'isolatedFunc',
|
|
199
|
+
args: {},
|
|
200
|
+
output: 'string',
|
|
201
|
+
})
|
|
202
|
+
isolatedRegistry.set('isolatedFunc', fn)
|
|
203
|
+
|
|
204
|
+
// Add to global and reset
|
|
205
|
+
functions.set('globalFunc', fn)
|
|
206
|
+
resetGlobalRegistry()
|
|
207
|
+
|
|
208
|
+
// Global should be empty, isolated should still have function
|
|
209
|
+
expect(functions.list()).toEqual([])
|
|
210
|
+
expect(isolatedRegistry.has('isolatedFunc')).toBe(true)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('can be called multiple times safely', () => {
|
|
214
|
+
resetGlobalRegistry()
|
|
215
|
+
resetGlobalRegistry()
|
|
216
|
+
resetGlobalRegistry()
|
|
79
217
|
expect(functions.list()).toEqual([])
|
|
80
218
|
})
|
|
81
219
|
})
|
|
82
220
|
|
|
83
221
|
describe('defineFunction', () => {
|
|
84
222
|
beforeEach(() => {
|
|
85
|
-
|
|
223
|
+
resetGlobalRegistry()
|
|
86
224
|
})
|
|
87
225
|
|
|
88
226
|
it('creates a generative function definition', () => {
|
|
@@ -132,6 +270,7 @@ describe('defineFunction', () => {
|
|
|
132
270
|
name: 'implement',
|
|
133
271
|
args: { spec: 'Function specification' },
|
|
134
272
|
language: 'typescript',
|
|
273
|
+
handler: () => 'ok',
|
|
135
274
|
})
|
|
136
275
|
|
|
137
276
|
expect(fn.definition.type).toBe('code')
|
|
@@ -163,7 +302,7 @@ describe('defineFunction', () => {
|
|
|
163
302
|
|
|
164
303
|
describe('define helpers', () => {
|
|
165
304
|
beforeEach(() => {
|
|
166
|
-
|
|
305
|
+
resetGlobalRegistry()
|
|
167
306
|
})
|
|
168
307
|
|
|
169
308
|
it('define.generative registers function', () => {
|
|
@@ -204,7 +343,8 @@ describe('define helpers', () => {
|
|
|
204
343
|
const fn = define.code({
|
|
205
344
|
name: 'generate',
|
|
206
345
|
args: { prompt: 'Code generation prompt' },
|
|
207
|
-
language: '
|
|
346
|
+
language: 'typescript',
|
|
347
|
+
handler: () => 'ok',
|
|
208
348
|
})
|
|
209
349
|
|
|
210
350
|
expect(functions.has('generate')).toBe(true)
|
|
@@ -212,9 +352,72 @@ describe('define helpers', () => {
|
|
|
212
352
|
})
|
|
213
353
|
})
|
|
214
354
|
|
|
355
|
+
// Code is the DETERMINISTIC kind — no gateway required. These tests assert the
|
|
356
|
+
// post-split contract: `type: 'code'` runs a handler (or inline body), never a
|
|
357
|
+
// model, at call time. (Code-authoring moved to generateCode().)
|
|
358
|
+
describe('code function execution (deterministic)', () => {
|
|
359
|
+
beforeEach(() => {
|
|
360
|
+
resetGlobalRegistry()
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('runs the supplied handler with no LLM call', async () => {
|
|
364
|
+
const calculateTax = defineFunction<number, { amount: number; rate: number }>({
|
|
365
|
+
type: 'code',
|
|
366
|
+
name: 'calculateTax',
|
|
367
|
+
args: { amount: 'Amount (number)', rate: 'Rate (number)' },
|
|
368
|
+
handler: ({ amount, rate }) => amount * rate,
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
const result = await calculateTax.call({ amount: 100, rate: 0.2 })
|
|
372
|
+
expect(result).toBe(20)
|
|
373
|
+
// Determinism: same input → same output, every time
|
|
374
|
+
expect(await calculateTax.call({ amount: 100, rate: 0.2 })).toBe(20)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('awaits an async handler', async () => {
|
|
378
|
+
const fn = defineFunction<string, { name: string }>({
|
|
379
|
+
type: 'code',
|
|
380
|
+
name: 'greetAsync',
|
|
381
|
+
args: { name: 'Name' },
|
|
382
|
+
handler: async ({ name }) => `hi ${name}`,
|
|
383
|
+
})
|
|
384
|
+
expect(await fn.call({ name: 'world' })).toBe('hi world')
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
it('evaluates an inline code body deterministically', async () => {
|
|
388
|
+
const fn = defineFunction<number, { items: number[] }>({
|
|
389
|
+
type: 'code',
|
|
390
|
+
name: 'sum',
|
|
391
|
+
args: { items: ['Numbers'] },
|
|
392
|
+
language: 'typescript',
|
|
393
|
+
code: 'return args.items.reduce((a, b) => a + b, 0)',
|
|
394
|
+
})
|
|
395
|
+
expect(await fn.call({ items: [1, 2, 3, 4] })).toBe(10)
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('throws (does not call a model) when no handler or code is provided', async () => {
|
|
399
|
+
const fn = defineFunction({
|
|
400
|
+
type: 'code',
|
|
401
|
+
name: 'noImpl',
|
|
402
|
+
args: { spec: 'spec' },
|
|
403
|
+
language: 'typescript',
|
|
404
|
+
})
|
|
405
|
+
await expect(fn.call({ spec: 'x' })).rejects.toThrow(/no handler or inline code/i)
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it('define.code runs the handler', async () => {
|
|
409
|
+
const fn = define.code<number, { a: number; b: number }>({
|
|
410
|
+
name: 'add',
|
|
411
|
+
args: { a: 'a (number)', b: 'b (number)' },
|
|
412
|
+
handler: ({ a, b }) => a + b,
|
|
413
|
+
})
|
|
414
|
+
expect(await fn.call({ a: 2, b: 3 })).toBe(5)
|
|
415
|
+
})
|
|
416
|
+
})
|
|
417
|
+
|
|
215
418
|
describe.skipIf(!hasGateway)('generative function execution', () => {
|
|
216
419
|
beforeEach(() => {
|
|
217
|
-
|
|
420
|
+
resetGlobalRegistry()
|
|
218
421
|
})
|
|
219
422
|
|
|
220
423
|
it('executes a generative string function', async () => {
|
|
@@ -251,7 +454,7 @@ describe.skipIf(!hasGateway)('generative function execution', () => {
|
|
|
251
454
|
|
|
252
455
|
describe.skipIf(!hasGateway)('auto-define', () => {
|
|
253
456
|
beforeEach(() => {
|
|
254
|
-
|
|
457
|
+
resetGlobalRegistry()
|
|
255
458
|
})
|
|
256
459
|
|
|
257
460
|
it('auto-defines a function from name and args', async () => {
|