A version written into a manifest is written into every manifest that wants it, which is how eslint came to exist in a hundred and four forms across this estate and how a package came to resolve twice at run time. The catalog moves the number out of the manifest: a manifest names the package, the workspace names the version. Four are held below their latest because the newer release cannot be used, and the reason is recorded rather than the version alone: @noble/hashes 2 renamed every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels 3 points its types condition at the bundle.
Hanzo Insights AI
TypeScript SDK for LLM observability with Hanzo Insights.
Installation
npm install @hanzo/insights-ai
Direct Provider Usage
import { OpenAI } from '@hanzo/insights-ai'
import { Insights } from '@hanzo/insights-node'
const phClient = new Insights('<YOUR_PROJECT_API_KEY>', { host: 'https://us.i.insights.hanzo.ai' })
const client = new OpenAI({
apiKey: '<YOUR_OPENAI_API_KEY>',
insights: phClient,
})
const completion = await client.chat.completions.create({
model: 'gpt-5-mini',
messages: [{ role: 'user', content: 'Tell me a fun fact about hedgehogs' }],
insightsDistinctId: 'user_123', // optional
insightsTraceId: 'trace_123', // optional
insightsProperties: { conversation_id: 'abc123', paid: true }, //optional
insightsGroups: { company: 'company_id_in_your_db' }, // optional
insightsPrivacyMode: false, // optional
})
console.log(completion.choices[0].message.content)
// YOU HAVE TO HAVE THIS OR THE CLIENT MAY NOT SEND EVENTS
await phClient.shutdown()
Custom and unsupported providers
Use this when working with Vercel AI SDK telemetry. @hanzo/ai exposes an OTEL SpanProcessor that maps spans to Insights AI events and sends them through @hanzo/insights-node.
import { NodeSDK } from '@opentelemetry/sdk-node'
import { Insights } from '@hanzo/insights-node'
import { generateText } from 'ai'
import { openai } from '@ai-sdk/openai'
import { InsightsSpanProcessor } from '@hanzo/insights-ai/otel'
const phClient = new Insights('<YOUR_PROJECT_API_KEY>', { host: 'https://us.i.insights.hanzo.ai' })
const sdk = new NodeSDK({
spanProcessors: [
new InsightsSpanProcessor(phClient),
],
})
await captureAiGeneration(phClient, {
distinctId: 'user_123',
traceId: 'trace_abc',
provider: 'cloudflare-workers-ai',
model: '@cf/zai-org/glm-4.7-flash',
input: messages,
output: result.response,
modelParameters: { reasoning_effort: 'high' },
usage: { inputTokens: result.usage?.prompt_tokens, outputTokens: result.usage?.completion_tokens },
latency: (Date.now() - start) / 1000,
properties: { feature: 'transcript-toc' },
})
await phClient.shutdown()
captureAiGeneration is the same primitive that every other @insights/ai wrapper funnels through, so the resulting events are indistinguishable from those produced by withTracing, OpenAI, Anthropic, etc.
OpenTelemetry
aiSdkSpanMapperis the default mapper.- You can pass custom
mappersinInsightsSpanProcessoroptions to support additional span schemas.
npm install @insights/ai @opentelemetry/sdk-node @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http
For dynamic properties, pass values in experimental_telemetry.metadata on each AI SDK call.
These are captured from ai.telemetry.metadata.* and forwarded as Insights event properties.
Use processor options (insightsProperties) only for global defaults.
A self-contained SpanProcessor that handles batching and export internally. Use this when your setup accepts a span processor.
- The OTEL route currently maps supported spans into Insights AI events (manual capture path).
- Existing wrapper-based tracing (for example
withTracing) still works and is unchanged.
LLM Observability docs
Please see the main Insights docs.