ai-functions 2.1.1 → 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 -4
- package/CHANGELOG.md +68 -1
- package/README.md +397 -157
- package/dist/ai-promise.d.ts +50 -3
- package/dist/ai-promise.d.ts.map +1 -1
- package/dist/ai-promise.js +410 -51
- 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 +54 -837
- 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 +272 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +513 -0
- package/dist/budget.js.map +1 -0
- package/dist/cache.d.ts +295 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +433 -0
- package/dist/cache.js.map +1 -0
- package/dist/context.d.ts +42 -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 +10 -1
- 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 -22
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +35 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +89 -42
- 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 +368 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +646 -0
- package/dist/retry.js.map +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -10
- 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 +453 -0
- package/dist/tool-orchestration.d.ts.map +1 -0
- package/dist/tool-orchestration.js +763 -0
- package/dist/tool-orchestration.js.map +1 -0
- 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 +10 -6
- package/src/ai-promise.ts +528 -99
- package/src/ai-schemas.ts +122 -0
- package/src/ai.ts +69 -1153
- 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 +740 -0
- package/src/cache.ts +681 -0
- package/src/context.ts +122 -76
- package/src/digital-objects-registry.ts +750 -0
- package/src/errors.ts +37 -0
- package/src/eval/runner.ts +63 -38
- 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 -33
- package/src/index.ts +325 -49
- 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 +902 -0
- package/src/schema.ts +8 -17
- package/src/telemetry.ts +403 -0
- package/src/template.ts +8 -4
- package/src/tool-orchestration.ts +1173 -0
- 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/backward-compat.test.ts +147 -0
- package/test/batch-autosubmit-errors.test.ts +610 -0
- package/test/batch-blog-posts.test.ts +87 -129
- package/test/budget-tracking.test.ts +800 -0
- package/test/cache.test.ts +712 -0
- package/test/context-isolation.test.ts +687 -0
- 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/evals/deterministic.eval.test.ts +376 -0
- package/test/generate-core.test.ts +140 -229
- package/test/implicit-batch.test.ts +22 -65
- package/test/json-parse-error-handling.test.ts +463 -0
- package/test/retry-policy-integration.test.ts +117 -0
- package/test/retry.test.ts +1016 -0
- package/test/schema.test.ts +55 -19
- package/test/streaming.test.ts +316 -0
- package/test/template.test.ts +1164 -0
- package/test/tool-orchestration.test.ts +1040 -0
- package/test/wrap-for-v3.test.ts +612 -0
- package/vitest.config.js +6 -0
- package/vitest.config.ts +20 -0
- 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/src/schema.ts
CHANGED
|
@@ -15,27 +15,18 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { z, type ZodTypeAny } from 'zod'
|
|
18
|
+
import { isZodSchema } from './type-guards.js'
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Simplified schema types
|
|
21
22
|
*/
|
|
22
23
|
export type SimpleSchema =
|
|
23
|
-
| string
|
|
24
|
-
| [string]
|
|
25
|
-
| [number]
|
|
26
|
-
| [SimpleSchema]
|
|
27
|
-
| { [key: string]: SimpleSchema }
|
|
28
|
-
| ZodTypeAny
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Check if value is a Zod schema
|
|
32
|
-
*/
|
|
33
|
-
function isZodSchema(value: unknown): value is ZodTypeAny {
|
|
34
|
-
return value !== null &&
|
|
35
|
-
typeof value === 'object' &&
|
|
36
|
-
'_def' in value &&
|
|
37
|
-
'parse' in value
|
|
38
|
-
}
|
|
24
|
+
| string // z.string().describe(value)
|
|
25
|
+
| [string] // z.array(z.string()).describe(value)
|
|
26
|
+
| [number] // z.array(z.number()).describe(value)
|
|
27
|
+
| [SimpleSchema] // z.array(converted).describe(value)
|
|
28
|
+
| { [key: string]: SimpleSchema } // z.object() recursively
|
|
29
|
+
| ZodTypeAny // Pass-through for actual Zod schemas
|
|
39
30
|
|
|
40
31
|
/**
|
|
41
32
|
* Convert a simplified schema to a Zod schema
|
|
@@ -73,7 +64,7 @@ function convertToZod(input: SimpleSchema): ZodTypeAny {
|
|
|
73
64
|
if (typeof input === 'string') {
|
|
74
65
|
// Enum syntax: 'option1 | option2 | option3'
|
|
75
66
|
if (input.includes(' | ')) {
|
|
76
|
-
const options = input.split(' | ').map(s => s.trim())
|
|
67
|
+
const options = input.split(' | ').map((s) => s.trim())
|
|
77
68
|
return z.enum(options as [string, ...string[]])
|
|
78
69
|
}
|
|
79
70
|
|
package/src/telemetry.ts
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry Integration for ai-functions
|
|
3
|
+
*
|
|
4
|
+
* Provides instrumented wrappers and telemetry utilities for AI function calls.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { withTelemetry, instrumentGenerate } from 'ai-functions/telemetry'
|
|
9
|
+
*
|
|
10
|
+
* // Enable telemetry globally
|
|
11
|
+
* withTelemetry({ provider: createConsoleTelemetryProvider() }, async () => {
|
|
12
|
+
* const text = await generate('Explain quantum computing')
|
|
13
|
+
* })
|
|
14
|
+
*
|
|
15
|
+
* // Or instrument individual functions
|
|
16
|
+
* const traced = instrumentGenerate(generate)
|
|
17
|
+
* const text = await traced('Explain quantum computing')
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
getTracer,
|
|
25
|
+
getMeter,
|
|
26
|
+
getLogger,
|
|
27
|
+
setTelemetryProvider,
|
|
28
|
+
getTelemetryProvider,
|
|
29
|
+
createAIMetrics,
|
|
30
|
+
SemanticAttributes,
|
|
31
|
+
MetricNames,
|
|
32
|
+
type Tracer,
|
|
33
|
+
type Meter,
|
|
34
|
+
type Logger,
|
|
35
|
+
type Span,
|
|
36
|
+
type SpanAttributes,
|
|
37
|
+
type TelemetryProvider,
|
|
38
|
+
type Counter,
|
|
39
|
+
type Histogram,
|
|
40
|
+
} from '@org.ai/types'
|
|
41
|
+
|
|
42
|
+
// Package info
|
|
43
|
+
const PACKAGE_NAME = 'ai-functions'
|
|
44
|
+
const PACKAGE_VERSION = '2.1.4'
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// Package-level Telemetry
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
let packageTracer: Tracer | undefined
|
|
51
|
+
let packageMeter: Meter | undefined
|
|
52
|
+
let packageLogger: Logger | undefined
|
|
53
|
+
let aiMetrics: ReturnType<typeof createAIMetrics> | undefined
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the tracer for ai-functions
|
|
57
|
+
*/
|
|
58
|
+
export function getFunctionsTracer(): Tracer {
|
|
59
|
+
if (!packageTracer) {
|
|
60
|
+
packageTracer = getTracer(PACKAGE_NAME, PACKAGE_VERSION)
|
|
61
|
+
}
|
|
62
|
+
return packageTracer
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the meter for ai-functions
|
|
67
|
+
*/
|
|
68
|
+
export function getFunctionsMeter(): Meter {
|
|
69
|
+
if (!packageMeter) {
|
|
70
|
+
packageMeter = getMeter(PACKAGE_NAME, PACKAGE_VERSION)
|
|
71
|
+
}
|
|
72
|
+
return packageMeter
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get the logger for ai-functions
|
|
77
|
+
*/
|
|
78
|
+
export function getFunctionsLogger(): Logger {
|
|
79
|
+
if (!packageLogger) {
|
|
80
|
+
packageLogger = getLogger(PACKAGE_NAME)
|
|
81
|
+
}
|
|
82
|
+
return packageLogger
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get AI metrics for the package
|
|
87
|
+
*/
|
|
88
|
+
export function getAIMetrics() {
|
|
89
|
+
if (!aiMetrics) {
|
|
90
|
+
aiMetrics = createAIMetrics(getFunctionsMeter())
|
|
91
|
+
}
|
|
92
|
+
return aiMetrics
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Reset cached telemetry instances (useful after changing provider)
|
|
97
|
+
*/
|
|
98
|
+
export function resetTelemetry(): void {
|
|
99
|
+
packageTracer = undefined
|
|
100
|
+
packageMeter = undefined
|
|
101
|
+
packageLogger = undefined
|
|
102
|
+
aiMetrics = undefined
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ============================================================================
|
|
106
|
+
// Telemetry Context
|
|
107
|
+
// ============================================================================
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Options for withTelemetry
|
|
111
|
+
*/
|
|
112
|
+
export interface WithTelemetryOptions {
|
|
113
|
+
/** Telemetry provider to use */
|
|
114
|
+
provider?: TelemetryProvider
|
|
115
|
+
/** Service name for telemetry */
|
|
116
|
+
serviceName?: string
|
|
117
|
+
/** Service version */
|
|
118
|
+
serviceVersion?: string
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Execute a function with telemetry enabled
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { createConsoleTelemetryProvider } from '@org.ai/types'
|
|
127
|
+
*
|
|
128
|
+
* await withTelemetry({
|
|
129
|
+
* provider: createConsoleTelemetryProvider()
|
|
130
|
+
* }, async () => {
|
|
131
|
+
* const text = await generate('Hello')
|
|
132
|
+
* })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export async function withTelemetry<T>(
|
|
136
|
+
options: WithTelemetryOptions,
|
|
137
|
+
fn: () => Promise<T>
|
|
138
|
+
): Promise<T> {
|
|
139
|
+
const previousProvider = getTelemetryProvider()
|
|
140
|
+
|
|
141
|
+
if (options.provider) {
|
|
142
|
+
setTelemetryProvider(options.provider)
|
|
143
|
+
resetTelemetry()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
return await fn()
|
|
148
|
+
} finally {
|
|
149
|
+
if (options.provider) {
|
|
150
|
+
setTelemetryProvider(previousProvider)
|
|
151
|
+
resetTelemetry()
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// Instrumentation Wrappers
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Record AI request metrics
|
|
162
|
+
*/
|
|
163
|
+
export function recordAIRequest(params: {
|
|
164
|
+
model: string
|
|
165
|
+
provider: string
|
|
166
|
+
inputTokens: number
|
|
167
|
+
outputTokens: number
|
|
168
|
+
durationMs: number
|
|
169
|
+
success: boolean
|
|
170
|
+
costUsd?: number | undefined
|
|
171
|
+
}): void {
|
|
172
|
+
const metrics = getAIMetrics()
|
|
173
|
+
const labels = {
|
|
174
|
+
model: params.model,
|
|
175
|
+
provider: params.provider,
|
|
176
|
+
status: params.success ? 'success' : 'error',
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
metrics.requestTotal.add(1, labels)
|
|
180
|
+
metrics.requestDuration.record(params.durationMs, labels)
|
|
181
|
+
metrics.tokensUsed.add(params.inputTokens + params.outputTokens, {
|
|
182
|
+
...labels,
|
|
183
|
+
type: 'total',
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
if (!params.success) {
|
|
187
|
+
metrics.requestErrors.add(1, labels)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (params.costUsd !== undefined) {
|
|
191
|
+
metrics.costTotal.add(params.costUsd, labels)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create a traced version of any async function
|
|
197
|
+
*/
|
|
198
|
+
export function traced<TArgs extends unknown[], TResult>(
|
|
199
|
+
name: string,
|
|
200
|
+
fn: (...args: TArgs) => Promise<TResult>,
|
|
201
|
+
options: {
|
|
202
|
+
kind?: 'internal' | 'client' | 'server'
|
|
203
|
+
getAttributes?: (...args: TArgs) => SpanAttributes
|
|
204
|
+
} = {}
|
|
205
|
+
): (...args: TArgs) => Promise<TResult> {
|
|
206
|
+
return async (...args: TArgs): Promise<TResult> => {
|
|
207
|
+
const tracer = getFunctionsTracer()
|
|
208
|
+
const logger = getFunctionsLogger()
|
|
209
|
+
|
|
210
|
+
const attributes: SpanAttributes = {
|
|
211
|
+
[SemanticAttributes.AI_FUNCTION_NAME]: name,
|
|
212
|
+
...(options.getAttributes ? options.getAttributes(...args) : {}),
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return tracer.withSpan(name, { kind: options.kind || 'internal', attributes }, async (span) => {
|
|
216
|
+
logger.debug(`Executing ${name}`, { attributes })
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const result = await fn(...args)
|
|
220
|
+
span.setStatus('ok')
|
|
221
|
+
return result
|
|
222
|
+
} catch (error) {
|
|
223
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
224
|
+
span.setStatus('error', message)
|
|
225
|
+
span.setAttribute(SemanticAttributes.EXCEPTION_MESSAGE, message)
|
|
226
|
+
if (error instanceof Error && error.stack) {
|
|
227
|
+
span.setAttribute(SemanticAttributes.EXCEPTION_STACKTRACE, error.stack)
|
|
228
|
+
}
|
|
229
|
+
logger.error(`Error in ${name}`, error instanceof Error ? error : undefined, {
|
|
230
|
+
attributes,
|
|
231
|
+
})
|
|
232
|
+
throw error
|
|
233
|
+
}
|
|
234
|
+
}) as Promise<TResult>
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Create instrumented generate function
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* import { generate } from 'ai-functions'
|
|
244
|
+
* import { instrumentGenerate } from 'ai-functions/telemetry'
|
|
245
|
+
*
|
|
246
|
+
* const tracedGenerate = instrumentGenerate(generate)
|
|
247
|
+
* const result = await tracedGenerate('text', 'Hello world')
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export function instrumentGenerate<T extends (...args: any[]) => Promise<any>>(generateFn: T): T {
|
|
251
|
+
return traced('ai.generate', generateFn as any, {
|
|
252
|
+
kind: 'client',
|
|
253
|
+
getAttributes: (type?: string) => ({
|
|
254
|
+
[SemanticAttributes.AI_FUNCTION_TYPE]: type || 'text',
|
|
255
|
+
}),
|
|
256
|
+
}) as T
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Create instrumented AI function with full metrics
|
|
261
|
+
*/
|
|
262
|
+
export function instrumentAIFunction<TInput, TOutput>(
|
|
263
|
+
name: string,
|
|
264
|
+
fn: (input: TInput) => Promise<TOutput>,
|
|
265
|
+
options: {
|
|
266
|
+
model?: string
|
|
267
|
+
provider?: string
|
|
268
|
+
getTokens?: (input: TInput, output: TOutput) => { input: number; output: number }
|
|
269
|
+
getCost?: (input: TInput, output: TOutput) => number
|
|
270
|
+
} = {}
|
|
271
|
+
): (input: TInput) => Promise<TOutput> {
|
|
272
|
+
return async (input: TInput): Promise<TOutput> => {
|
|
273
|
+
const tracer = getFunctionsTracer()
|
|
274
|
+
const logger = getFunctionsLogger()
|
|
275
|
+
const startTime = Date.now()
|
|
276
|
+
|
|
277
|
+
const attributes: SpanAttributes = {
|
|
278
|
+
[SemanticAttributes.AI_FUNCTION_NAME]: name,
|
|
279
|
+
...(options.model && { [SemanticAttributes.AI_MODEL]: options.model }),
|
|
280
|
+
...(options.provider && { [SemanticAttributes.AI_PROVIDER]: options.provider }),
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return tracer.withSpan(`ai.function.${name}`, { kind: 'client', attributes }, async (span) => {
|
|
284
|
+
logger.info(`AI function ${name} started`, { model: options.model })
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
const output = await fn(input)
|
|
288
|
+
const durationMs = Date.now() - startTime
|
|
289
|
+
|
|
290
|
+
// Record metrics
|
|
291
|
+
const tokens = options.getTokens?.(input, output)
|
|
292
|
+
const cost = options.getCost?.(input, output)
|
|
293
|
+
|
|
294
|
+
if (tokens) {
|
|
295
|
+
span.setAttribute(SemanticAttributes.AI_INPUT_TOKENS, tokens.input)
|
|
296
|
+
span.setAttribute(SemanticAttributes.AI_OUTPUT_TOKENS, tokens.output)
|
|
297
|
+
span.setAttribute(SemanticAttributes.AI_TOTAL_TOKENS, tokens.input + tokens.output)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (cost !== undefined) {
|
|
301
|
+
span.setAttribute(SemanticAttributes.AI_COST_USD, cost)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
recordAIRequest({
|
|
305
|
+
model: options.model || 'unknown',
|
|
306
|
+
provider: options.provider || 'unknown',
|
|
307
|
+
inputTokens: tokens?.input || 0,
|
|
308
|
+
outputTokens: tokens?.output || 0,
|
|
309
|
+
durationMs,
|
|
310
|
+
success: true,
|
|
311
|
+
costUsd: cost,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
span.setStatus('ok')
|
|
315
|
+
logger.info(`AI function ${name} completed`, {
|
|
316
|
+
durationMs,
|
|
317
|
+
tokens: tokens?.input !== undefined ? tokens.input + (tokens.output || 0) : undefined,
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
return output
|
|
321
|
+
} catch (error) {
|
|
322
|
+
const durationMs = Date.now() - startTime
|
|
323
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
324
|
+
|
|
325
|
+
recordAIRequest({
|
|
326
|
+
model: options.model || 'unknown',
|
|
327
|
+
provider: options.provider || 'unknown',
|
|
328
|
+
inputTokens: 0,
|
|
329
|
+
outputTokens: 0,
|
|
330
|
+
durationMs,
|
|
331
|
+
success: false,
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
span.setStatus('error', message)
|
|
335
|
+
logger.error(`AI function ${name} failed`, error instanceof Error ? error : undefined, {
|
|
336
|
+
durationMs,
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
throw error
|
|
340
|
+
}
|
|
341
|
+
}) as Promise<TOutput>
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// ============================================================================
|
|
346
|
+
// Span Helpers
|
|
347
|
+
// ============================================================================
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Start a span for an AI operation
|
|
351
|
+
*/
|
|
352
|
+
export function startAISpan(name: string, attributes?: SpanAttributes): Span {
|
|
353
|
+
const tracer = getFunctionsTracer()
|
|
354
|
+
return tracer.startSpan(name, {
|
|
355
|
+
kind: 'client',
|
|
356
|
+
attributes: {
|
|
357
|
+
[SemanticAttributes.SERVICE_NAME]: PACKAGE_NAME,
|
|
358
|
+
...attributes,
|
|
359
|
+
},
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Execute code within a span
|
|
365
|
+
*/
|
|
366
|
+
export async function withAISpan<T>(
|
|
367
|
+
name: string,
|
|
368
|
+
fn: (span: Span) => Promise<T>,
|
|
369
|
+
attributes?: SpanAttributes
|
|
370
|
+
): Promise<T> {
|
|
371
|
+
const tracer = getFunctionsTracer()
|
|
372
|
+
return tracer.withSpan(name, { kind: 'client', attributes }, fn) as Promise<T>
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// ============================================================================
|
|
376
|
+
// Re-exports from @org.ai/types
|
|
377
|
+
// ============================================================================
|
|
378
|
+
|
|
379
|
+
export {
|
|
380
|
+
// Core types
|
|
381
|
+
type Tracer,
|
|
382
|
+
type Meter,
|
|
383
|
+
type Logger,
|
|
384
|
+
type Span,
|
|
385
|
+
type SpanAttributes,
|
|
386
|
+
type TelemetryProvider,
|
|
387
|
+
type Counter,
|
|
388
|
+
type Histogram,
|
|
389
|
+
|
|
390
|
+
// Global functions
|
|
391
|
+
getTracer,
|
|
392
|
+
getMeter,
|
|
393
|
+
getLogger,
|
|
394
|
+
setTelemetryProvider,
|
|
395
|
+
getTelemetryProvider,
|
|
396
|
+
|
|
397
|
+
// Constants
|
|
398
|
+
SemanticAttributes,
|
|
399
|
+
MetricNames,
|
|
400
|
+
|
|
401
|
+
// Utilities
|
|
402
|
+
createAIMetrics,
|
|
403
|
+
} from '@org.ai/types'
|
package/src/template.ts
CHANGED
|
@@ -65,9 +65,15 @@ export function createChainablePromise<T>(
|
|
|
65
65
|
executor: (options?: FunctionOptions) => Promise<T>,
|
|
66
66
|
defaultOptions?: FunctionOptions
|
|
67
67
|
): ChainablePromise<T> {
|
|
68
|
-
// Create the base promise
|
|
68
|
+
// Create the base promise with a no-op catch to prevent unhandled rejection
|
|
69
|
+
// The actual error will still be thrown when .then() or await is called
|
|
69
70
|
const basePromise = executor(defaultOptions)
|
|
70
71
|
|
|
72
|
+
// Prevent unhandled rejection warning by attaching a no-op catch
|
|
73
|
+
// This doesn't swallow the error - it just prevents the warning when the
|
|
74
|
+
// promise is not immediately awaited (e.g., when chaining options)
|
|
75
|
+
basePromise.catch(() => {})
|
|
76
|
+
|
|
71
77
|
// Create a function that accepts options
|
|
72
78
|
const chainable = ((options?: FunctionOptions) => {
|
|
73
79
|
return executor({ ...defaultOptions, ...options })
|
|
@@ -134,9 +140,7 @@ export function withBatch<T, TInput = string>(
|
|
|
134
140
|
/**
|
|
135
141
|
* Create an async iterable from a streaming generator
|
|
136
142
|
*/
|
|
137
|
-
export function createAsyncIterable<T>(
|
|
138
|
-
items: T[] | (() => AsyncGenerator<T>)
|
|
139
|
-
): AsyncIterable<T> {
|
|
143
|
+
export function createAsyncIterable<T>(items: T[] | (() => AsyncGenerator<T>)): AsyncIterable<T> {
|
|
140
144
|
if (Array.isArray(items)) {
|
|
141
145
|
return {
|
|
142
146
|
async *[Symbol.asyncIterator]() {
|