mirror of
https://github.com/hanzoai/insights-js.git
synced 2026-10-30 18:34:19 +00:00
* style(convex): apply prettier formatting to example-convex * refactor(convex): replace @opentelemetry/sdk-node with runtime-agnostic sdk-trace-base Remove "use node" directive from all Convex example files by switching from @opentelemetry/sdk-node (Node.js-only) to @opentelemetry/sdk-trace-base with BasicTracerProvider + BatchSpanProcessor. Add a performance polyfill for Convex's V8 isolate which lacks the performance global that @opentelemetry/core expects. * fix(convex): use class-based performance polyfill with relative timing * fix(convex): move tracer provider to module scope to avoid silent no-op trace.setGlobalTracerProvider() only applies on the first call — subsequent calls are silently ignored. Since Convex V8 isolates are warm-reused, the provider must be initialized at module scope. Per-request distinctId is already passed via experimental_telemetry metadata. * refactor(convex): extract OTEL provider setup into shared otelSetup.ts Move provider creation and global registration out of action files into a shared setup file. PostHogTraceExporter is now clearly framed as a standard OTEL span processor that sits alongside other exporters in the user's OTEL config, rather than owning the entire provider. * refactor(convex): inline OTEL setup back into individual example files Keep the provider setup co-located with the action so each example is self-contained and easy to follow without jumping between files. * fix(convex): remove competitor names from comments * style(convex): format example-convex files * fix(convex): use SimpleSpanProcessor instead of BatchSpanProcessor Convex actions terminate immediately after returning, so BatchSpanProcessor never gets a chance to flush. SimpleSpanProcessor sends spans synchronously, ensuring they're exported before the action completes.
62 lines
2.0 KiB
TypeScript
62 lines
2.0 KiB
TypeScript
import { generateText } from 'ai'
|
|
import { openai } from '@ai-sdk/openai'
|
|
import { action } from '../_generated/server'
|
|
import { v } from 'convex/values'
|
|
import { posthog } from '../posthog.js'
|
|
|
|
// Demonstrates using the Vercel AI SDK (without @convex-dev/agent)
|
|
// to call an LLM and capture $ai_generation events to PostHog.
|
|
export const generate = action({
|
|
args: {
|
|
prompt: v.string(),
|
|
distinctId: v.optional(v.string()),
|
|
},
|
|
handler: async (ctx, args) => {
|
|
const traceId = crypto.randomUUID()
|
|
const startTime = Date.now()
|
|
|
|
const result = await generateText({
|
|
model: openai('gpt-5-mini'),
|
|
prompt: args.prompt,
|
|
})
|
|
|
|
const latency = (Date.now() - startTime) / 1000
|
|
|
|
await posthog.capture(ctx, {
|
|
distinctId: args.distinctId ?? 'anonymous',
|
|
event: '$ai_generation',
|
|
properties: {
|
|
// Trace ID groups multiple generations into a single trace
|
|
$ai_trace_id: traceId,
|
|
|
|
// Core identification
|
|
$ai_provider: 'openai',
|
|
$ai_model: 'gpt-5-mini',
|
|
|
|
// Token usage
|
|
$ai_input_tokens: result.usage.inputTokens,
|
|
$ai_output_tokens: result.usage.outputTokens,
|
|
|
|
// Cache tokens (if the provider reports them)
|
|
$ai_cache_read_input_tokens: result.usage.cachedInputTokens,
|
|
|
|
// Performance
|
|
$ai_latency: latency,
|
|
|
|
// Input/output content
|
|
$ai_input: [{ role: 'user', content: args.prompt }],
|
|
$ai_output_choices: [{ role: 'assistant', content: result.text }],
|
|
|
|
// Generation metadata — the AI SDK doesn't expose HTTP status directly,
|
|
// so we infer success/failure from the finish reason.
|
|
$ai_is_error: result.finishReason === 'error',
|
|
},
|
|
})
|
|
|
|
return {
|
|
text: result.text,
|
|
usage: result.usage,
|
|
}
|
|
},
|
|
})
|