diff --git a/examples/example-evals-flags/.env.example b/examples/example-evals-flags/.env.example new file mode 100644 index 00000000..f09aa689 --- /dev/null +++ b/examples/example-evals-flags/.env.example @@ -0,0 +1,6 @@ +AXIOM_URL="https://api.axiom.co" +AXIOM_TOKEN="xaat-******" +AXIOM_DATASET="my_dataset" +AXIOM_EVAL_DATASET="my_eval_dataset" + +OPENAI_API_KEY="sk-proj-******" diff --git a/examples/example-evals-flags/.gitignore b/examples/example-evals-flags/.gitignore new file mode 100644 index 00000000..c5ea7670 --- /dev/null +++ b/examples/example-evals-flags/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/example-evals-flags/README.md b/examples/example-evals-flags/README.md new file mode 100644 index 00000000..232e8409 --- /dev/null +++ b/examples/example-evals-flags/README.md @@ -0,0 +1,40 @@ +# Example: Evals - Writing Agent + +A headless example demonstrating trace capture with Axiom's AI SDK for a marketplace listing writer. + +## What This Shows + +- **Trace capture** with `withSpan` and `wrapAISDKModel` +- **Tool calling** with `wrapTools` for content moderation +- **Headless architecture** - runs via CLI, no web framework + +## The Use Case + +A writing agent for "Acme" marketplace that transforms raw seller descriptions into polished product listings. Includes a `checkProhibitedItems` tool to demonstrate tool tracing. + +**Example:** +- **Input**: `"Used flip flops. Blue color. Size 9. Decent condition."` +- **Output**: `"Comfortable blue flip flops in size 9, perfect for casual summer wear..."` + +## Quick Start + +```bash +# Install dependencies (from repo root) +pnpm install + +# Set environment variables +export AXIOM_URL="your-axiom-url" +export AXIOM_TOKEN="your-axiom-token" +export AXIOM_DATASET="your-dataset" +export OPENAI_API_KEY="your-openai-key" + +# Generate a single listing (with trace) +npm run generate +``` + +## Key Files + +- `src/lib/service.ts` - Writing agent with tool calling +- `src/lib/tools/check-prohibited-items.ts` - Content moderation tool +- `src/lib/scripts/generate.ts` - CLI script for generations + diff --git a/examples/example-evals-flags/axiom.config.ts b/examples/example-evals-flags/axiom.config.ts new file mode 100644 index 00000000..b7e9df42 --- /dev/null +++ b/examples/example-evals-flags/axiom.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'axiom/ai/config'; +import { setupAppInstrumentation } from './src/instrumentation.node'; + +export default defineConfig({ + eval: { + url: process.env.AXIOM_URL, + token: process.env.AXIOM_TOKEN, + dataset: process.env.AXIOM_EVAL_DATASET, + + include: ['**/*.eval.{ts,js}'], + exclude: [], + + instrumentation: ({ url, token, dataset }) => setupAppInstrumentation({ url, token, dataset }), + + timeoutMs: 60_000, + }, +}); diff --git a/examples/example-evals-flags/env.ts b/examples/example-evals-flags/env.ts new file mode 100644 index 00000000..df36dd19 --- /dev/null +++ b/examples/example-evals-flags/env.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; + +const envSchema = z.object({ + AXIOM_URL: z.string(), + AXIOM_TOKEN: z.string(), + AXIOM_DATASET: z.string(), + AXIOM_EVAL_DATASET: z.string(), + OPENAI_API_KEY: z.string(), +}); + +try { + envSchema.parse(process.env); +} catch (error) { + console.error(error); +} + +declare global { + namespace NodeJS { + interface ProcessEnv extends z.infer {} + } +} diff --git a/examples/example-evals-flags/package.json b/examples/example-evals-flags/package.json new file mode 100644 index 00000000..54efb7fb --- /dev/null +++ b/examples/example-evals-flags/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-evals-flags", + "private": true, + "type": "module", + "scripts": { + "eval": "node ../../packages/ai/dist/bin.js eval .", + "generate": "tsx src/lib/scripts/generate.ts", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@ai-sdk/openai": "2.0.0-beta.11", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.202.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.0.1", + "@opentelemetry/semantic-conventions": "^1.34.0", + "ai": "5.0.0-beta.24", + "axiom": "workspace:*", + "zod": "catalog:" + }, + "devDependencies": { + "@types/node": "^22.17.2", + "autoevals": "^0.0.130", + "chalk": "^5.3.0", + "dotenv": "^16.4.5", + "tsx": "^4.19.2", + "typescript": "catalog:" + } +} diff --git a/examples/example-evals-flags/src/instrumentation.node.ts b/examples/example-evals-flags/src/instrumentation.node.ts new file mode 100644 index 00000000..4a0f81b9 --- /dev/null +++ b/examples/example-evals-flags/src/instrumentation.node.ts @@ -0,0 +1,51 @@ +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; +import { resourceFromAttributes } from '@opentelemetry/resources'; +import { BatchSpanProcessor, NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; +import { initAxiomAI, RedactionPolicy } from 'axiom/ai'; +import type { AxiomEvalInstrumentationHook } from 'axiom/ai/config'; +import { tracer } from './tracer'; + +let provider: NodeTracerProvider | undefined; + +export const setupAppInstrumentation: AxiomEvalInstrumentationHook = async (options) => { + if (provider) { + return { provider }; + } + + const dataset = options.dataset; + const url = options.url; + const token = options.token; + + if (!dataset) { + throw new Error('Dataset is required to initialize tracing'); + } + + if (!url) { + throw new Error('URL is required to initialize tracing'); + } + + if (!token) { + throw new Error('Token is required to initialize tracing'); + } + + const exporter = new OTLPTraceExporter({ + url: `${url}/v1/traces`, + headers: { + Authorization: `Bearer ${token}`, + 'X-Axiom-Dataset': dataset, + }, + }); + + provider = new NodeTracerProvider({ + resource: resourceFromAttributes({ + [ATTR_SERVICE_NAME]: 'example-evals-flags', + }), + spanProcessors: [new BatchSpanProcessor(exporter)], + }); + + provider.register(); + initAxiomAI({ tracer, redactionPolicy: RedactionPolicy.AxiomDefault }); + + return { provider }; +}; diff --git a/examples/example-evals-flags/src/instrumentation.ts b/examples/example-evals-flags/src/instrumentation.ts new file mode 100644 index 00000000..63549db5 --- /dev/null +++ b/examples/example-evals-flags/src/instrumentation.ts @@ -0,0 +1,10 @@ +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') { + const { setupAppInstrumentation } = await import('./instrumentation.node'); + await setupAppInstrumentation({ + url: process.env.AXIOM_URL, + token: process.env.AXIOM_TOKEN, + dataset: process.env.AXIOM_DATASET, + }); + } +} diff --git a/examples/example-evals-flags/src/lib/collections/records.ts b/examples/example-evals-flags/src/lib/collections/records.ts new file mode 100644 index 00000000..1dffc32d --- /dev/null +++ b/examples/example-evals-flags/src/lib/collections/records.ts @@ -0,0 +1,265 @@ +import type { ListingCollection } from '../schemas'; + +export const listingRecords: ListingCollection = [ + { + input: { + seller_brief: 'Used flip flops. Blue color. Size 9. Decent condition.', + }, + expected: { + product_description: + 'Comfortable blue flip flops in size 9, perfect for casual summer wear. These pre-loved sandals are in decent condition and ready for beach days or poolside relaxation.', + }, + metadata: { + category: 'fashion', + seller_username: '@coastalliving#54186', + }, + }, + { + input: { + seller_brief: 'A high-quality mug for everyday use.', + }, + expected: { + product_description: + 'Durable, high-quality mug designed for daily use. Whether you are enjoying your morning coffee or afternoon tea, this reliable mug is built to last.', + }, + metadata: { + category: 'home', + seller_username: '@kitchenware_pro#82041', + }, + }, + { + input: { + seller_brief: + 'Vintage leather jacket from the 80s. Some wear but still stylish. Size medium.', + }, + expected: { + product_description: + 'Authentic 80s vintage leather jacket in size medium. This classic piece shows character with some wear, adding to its retro charm. A timeless addition to any wardrobe.', + }, + metadata: { + category: 'fashion', + seller_username: '@vintage_finds#29384', + }, + }, + { + input: { + seller_brief: 'used iphone 12, works fine, some scratches on back', + }, + expected: { + product_description: + 'Fully functional iPhone 12 in good working condition. Features minor cosmetic scratches on the back, but performs perfectly. A great value for a reliable smartphone.', + }, + metadata: { + category: 'electronics', + seller_username: '@tech_seller#67293', + }, + }, + { + input: { + seller_brief: 'Harry Potter complete book set. All 7 books. Good condition.', + }, + expected: { + product_description: + 'Complete Harry Potter series featuring all 7 books in good condition. Perfect for fans or first-time readers looking to experience the entire magical journey.', + }, + metadata: { + category: 'books', + seller_username: '@bookworm_alice#91247', + }, + }, + { + input: { + seller_brief: 'Yoga mat, purple, barely used, comes with carrying strap', + }, + expected: { + product_description: + 'Purple yoga mat in excellent condition with minimal use. Includes a convenient carrying strap for easy transport to classes or outdoor sessions.', + }, + metadata: { + category: 'sports', + seller_username: '@fitness_enthusiast#45829', + }, + }, + { + input: { + seller_brief: 'Lego Star Wars set. Missing a few pieces but mostly complete.', + }, + expected: { + product_description: + 'Lego Star Wars building set, mostly complete with only a few minor pieces missing. Great for collectors or young builders looking for an affordable entry into the Star Wars universe.', + }, + metadata: { + category: 'toys', + seller_username: '@toy_collector#38475', + }, + }, + { + input: { + seller_brief: 'Wooden coffee table, scratches on surface, sturdy', + }, + expected: { + product_description: + 'Solid wooden coffee table with a sturdy build. Features surface scratches that add rustic character. A dependable piece for any living room.', + }, + metadata: { + category: 'home', + seller_username: '@furniture_deals#72156', + }, + }, + { + input: { + seller_brief: 'Car phone mount. Universal fit. Works great.', + }, + expected: { + product_description: + 'Universal car phone mount in excellent working condition. Compatible with most smartphone models, providing secure and convenient hands-free access while driving.', + }, + metadata: { + category: 'automotive', + seller_username: '@car_accessories#53921', + }, + }, + { + input: { + seller_brief: 'Gaming headset with mic, black, some wear on ear pads', + }, + expected: { + product_description: + 'Black gaming headset with built-in microphone. Ear pads show some wear from use, but audio quality remains excellent. Perfect for gaming sessions or video calls.', + }, + metadata: { + category: 'electronics', + seller_username: '@gamer_hub#64738', + }, + }, + { + input: { + seller_brief: 'Samsung Galaxy Tab, 64GB, minor screen scratches, charger included', + }, + expected: { + product_description: + 'Samsung Galaxy Tab with 64GB storage capacity. Features minor screen scratches but functions flawlessly. Includes original charger for immediate use.', + }, + metadata: { + category: 'electronics', + seller_username: '@TechRefurb', + }, + }, + { + input: { + seller_brief: 'Stainless steel water bottle, 32oz, insulated, keeps drinks cold for 24 hours', + }, + expected: { + product_description: + 'Premium 32oz insulated stainless steel water bottle with 24-hour cold retention technology. Perfect for staying hydrated throughout your day, whether at work, gym, or outdoor adventures.', + }, + metadata: { + category: 'sports', + seller_username: '@HydroGear', + }, + }, + { + input: { + seller_brief: 'Nike running shoes, size 10, gently used, good tread', + }, + expected: { + product_description: + 'Nike running shoes in size 10 with excellent tread remaining. Gently used with plenty of life left. Ideal for runners seeking quality footwear at a great price.', + }, + metadata: { + category: 'fashion', + seller_username: '@sneaker_resale#19283', + }, + }, + { + input: { + seller_brief: 'Electric kettle, 1.7L, fast boil, stainless steel finish', + }, + expected: { + product_description: + '1.7L electric kettle with rapid boil technology and sleek stainless steel finish. Efficient and stylish addition to any kitchen for quick hot beverages.', + }, + metadata: { + category: 'home', + seller_username: '@HomeEssentials', + }, + }, + { + input: { + seller_brief: 'Board game collection: Monopoly, Scrabble, and Risk. All complete.', + }, + expected: { + product_description: + 'Classic board game bundle featuring Monopoly, Scrabble, and Risk. All games are complete with original pieces and instructions. Perfect for family game nights.', + }, + metadata: { + category: 'toys', + seller_username: '@game_night_guru#84562', + }, + }, + { + input: { + seller_brief: 'Wireless mouse, ergonomic design, USB receiver included', + }, + expected: { + product_description: + 'Ergonomic wireless mouse designed for comfortable extended use. Includes USB receiver for easy plug-and-play connectivity. Compatible with Windows and Mac systems.', + }, + metadata: { + category: 'electronics', + seller_username: '@OfficeProSupply', + }, + }, + { + input: { + seller_brief: 'Cookbook collection, 5 books, various cuisines, some recipe notes in margins', + }, + expected: { + product_description: + 'Diverse cookbook collection featuring 5 books covering various international cuisines. Includes helpful recipe notes in margins from previous owner. Great for expanding your culinary repertoire.', + }, + metadata: { + category: 'books', + seller_username: '@chef_at_home#37194', + }, + }, + { + input: { + seller_brief: 'Car floor mats, all-weather rubber, fits most sedans', + }, + expected: { + product_description: + 'Durable all-weather rubber floor mats designed to fit most sedan models. Provides excellent protection against dirt, mud, and spills year-round.', + }, + metadata: { + category: 'automotive', + seller_username: '@AutoAccessories', + }, + }, + { + input: { + seller_brief: 'Desk lamp with adjustable arm, LED bulb, works perfectly', + }, + expected: { + product_description: + 'Functional desk lamp featuring an adjustable arm for optimal positioning. Equipped with energy-efficient LED bulb. Perfect for home office or study space.', + }, + metadata: { + category: 'home', + seller_username: '@office_surplus#62847', + }, + }, + { + input: { + seller_brief: 'Tennis racket, Wilson brand, intermediate level, new strings', + }, + expected: { + product_description: + 'Wilson tennis racket suited for intermediate players. Recently restrung and ready for the court. Excellent condition with minimal wear.', + }, + metadata: { + category: 'sports', + seller_username: '@tennis_player#23956', + }, + }, +]; diff --git a/examples/example-evals-flags/src/lib/evaluations/listing-writer.eval.ts b/examples/example-evals-flags/src/lib/evaluations/listing-writer.eval.ts new file mode 100644 index 00000000..9447214a --- /dev/null +++ b/examples/example-evals-flags/src/lib/evaluations/listing-writer.eval.ts @@ -0,0 +1,17 @@ +import { experimental_Eval as Eval } from 'axiom/ai/evals'; +import { Factuality, Moderation } from 'autoevals'; +import { generateListing } from '../service'; +import { listingRecords } from '../collections/records'; +import type { ListingInput, ListingOutput } from '../schemas'; + +Eval('listing-writer', { + data: () => listingRecords, + task: async ({ input }: { input: ListingInput }) => { + const result = await generateListing(input); + return result.output.product_description; + }, + scorers: [Moderation, Factuality], + metadata: { + description: 'Evaluates the Acme listing writer agent for product descriptions', + }, +}); diff --git a/examples/example-evals-flags/src/lib/schemas.ts b/examples/example-evals-flags/src/lib/schemas.ts new file mode 100644 index 00000000..4d0cd699 --- /dev/null +++ b/examples/example-evals-flags/src/lib/schemas.ts @@ -0,0 +1,45 @@ +import z from 'zod'; + +// Input from the seller +export const ListingInputSchema = z.object({ + seller_brief: z.string(), +}); + +// Expected output - the polished listing +export const ListingOutputSchema = z.object({ + product_description: z.string(), +}); + +// Product categories +export const ProductCategorySchema = z.enum([ + 'electronics', + 'fashion', + 'home', + 'sports', + 'books', + 'toys', + 'automotive', + 'other', +]); + +// Metadata for tracking +export const ListingMetadataSchema = z.object({ + category: ProductCategorySchema, + seller_username: z.string(), +}); + +// Collection record schema +export const ListingRecordSchema = z.object({ + input: ListingInputSchema, + expected: ListingOutputSchema, + metadata: ListingMetadataSchema, +}); + +export const ListingCollectionSchema = z.array(ListingRecordSchema); + +// Type exports +export type ListingInput = z.infer; +export type ListingOutput = z.infer; +export type ProductCategory = z.infer; +export type ListingRecord = z.infer; +export type ListingCollection = z.infer; diff --git a/examples/example-evals-flags/src/lib/scripts/generate.ts b/examples/example-evals-flags/src/lib/scripts/generate.ts new file mode 100644 index 00000000..b7790162 --- /dev/null +++ b/examples/example-evals-flags/src/lib/scripts/generate.ts @@ -0,0 +1,77 @@ +import 'dotenv/config'; +import chalk from 'chalk'; +import type { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { generateListing } from '../service'; +import { setupAppInstrumentation } from '../../instrumentation.node'; + +const sampleBriefs = [ + { + seller_brief: 'Retro Nintendo Game Boy, works perfectly, minor scratches', + seller_username: '@vintage_shop#82947', + }, + { + seller_brief: 'Bluetooth speaker, waterproof, great sound quality', + seller_username: '@tech_deals#45821', + }, + { + seller_brief: 'Ceramic plant pot set, 3 pieces, hand-painted design', + seller_username: '@home_decor#91234', + }, + { + seller_brief: 'Mountain bike helmet, size L, barely used, all safety standards met', + seller_username: '@cycling_gear#67453', + }, + { + seller_brief: 'Espresso machine, compact design, includes milk frother', + seller_username: '@CoffeePro', + }, +]; + +async function main() { + console.log(chalk.dim('─'.repeat(60))); + console.log(chalk.bold('Acme Listing Generator')); + console.log(chalk.dim('─'.repeat(60))); + + // Initialize instrumentation + console.log(chalk.dim('\n→ Initializing...')); + const { provider } = (await setupAppInstrumentation({ + url: process.env.AXIOM_URL, + token: process.env.AXIOM_TOKEN, + dataset: process.env.AXIOM_DATASET, + })) as { provider: NodeTracerProvider }; + + // Pick random sample + const sample = sampleBriefs[Math.floor(Math.random() * sampleBriefs.length)]; + console.log(chalk.dim(`→ Selected seller: ${chalk.cyan(sample.seller_username)}\n`)); + + // Show input + console.log(chalk.bold('Input:')); + console.log(chalk.gray(` "${sample.seller_brief}"`)); + + // Generate listing + console.log(chalk.dim('\n→ Generating listing...')); + const { output, traceId } = await generateListing({ seller_brief: sample.seller_brief }); + + // Show output + console.log(chalk.green('✓ Listing generated\n')); + console.log(chalk.bold('Output:')); + console.log(chalk.white(` ${output.product_description}`)); + + if (traceId) { + console.log(chalk.dim(`\n→ Trace ID: ${chalk.cyan(traceId)}`)); + } + + // Flush spans to Axiom + if (provider) { + await provider.forceFlush(); + } + + console.log(chalk.dim('→ Trace sent to Axiom')); + console.log(chalk.dim('─'.repeat(60) + '\n')); +} + +main().catch((error) => { + console.error(chalk.red('\n✗ Error:'), error.message); + console.error(error); + process.exit(1); +}); diff --git a/examples/example-evals-flags/src/lib/service.ts b/examples/example-evals-flags/src/lib/service.ts new file mode 100644 index 00000000..cadf4a27 --- /dev/null +++ b/examples/example-evals-flags/src/lib/service.ts @@ -0,0 +1,49 @@ +import { generateText, tool, stepCountIs } from 'ai'; +import { openai } from '@ai-sdk/openai'; +import { z } from 'zod'; +import { wrapAISDKModel, wrapTools, withSpan } from 'axiom/ai'; +import type { ListingInput, ListingOutput } from './schemas'; +import { checkProhibitedItems } from './tools/check-prohibited-items'; + +const SYSTEM_PROMPT = `You are a writer for Acme, an online marketplace where users buy and sell products. Your job is to create a listing for the product described by the seller in a style consistent with the Acme brand voice. Before writing, check if the item is prohibited using the checkProhibitedItems tool.`; + +export async function generateListing( + input: ListingInput, +): Promise<{ output: ListingOutput; traceId: string }> { + let traceId = ''; + + const result = await withSpan( + { capability: 'listing-writer', step: 'generate' }, + async (span) => { + traceId = span.spanContext().traceId; + + const response = await generateText({ + model: wrapAISDKModel(openai('gpt-4o-mini')), + messages: [ + { + role: 'system', + content: SYSTEM_PROMPT, + }, + { + role: 'user', + content: input.seller_brief, + }, + ], + stopWhen: stepCountIs(3), + tools: wrapTools({ + checkProhibitedItems: tool({ + description: 'Check if a product is on the prohibited items list', + inputSchema: z.object({ + productDescription: z.string().describe('The product description to check'), + }), + execute: checkProhibitedItems, + }), + }), + }); + + return { product_description: response.text }; + }, + ); + + return { output: result, traceId }; +} diff --git a/examples/example-evals-flags/src/lib/tools/check-prohibited-items.ts b/examples/example-evals-flags/src/lib/tools/check-prohibited-items.ts new file mode 100644 index 00000000..eb3793f3 --- /dev/null +++ b/examples/example-evals-flags/src/lib/tools/check-prohibited-items.ts @@ -0,0 +1,10 @@ +const PROHIBITED_KEYWORDS = ['tobacco', 'cigarette', 'vape', 'alcohol', 'prescription', 'rx']; + +export async function checkProhibitedItems(params: { productDescription: string }) { + const lowerDesc = params.productDescription.toLowerCase(); + const isProhibited = PROHIBITED_KEYWORDS.some((keyword) => lowerDesc.includes(keyword)); + return { + prohibited: isProhibited, + reason: isProhibited ? 'Item contains prohibited keywords' : null, + }; +} diff --git a/examples/example-evals-flags/src/tracer.ts b/examples/example-evals-flags/src/tracer.ts new file mode 100644 index 00000000..07b3ae87 --- /dev/null +++ b/examples/example-evals-flags/src/tracer.ts @@ -0,0 +1,3 @@ +import { trace } from '@opentelemetry/api'; + +export const tracer = trace.getTracer('acme-evals-flags'); diff --git a/examples/example-evals-flags/tsconfig.json b/examples/example-evals-flags/tsconfig.json new file mode 100644 index 00000000..8070856a --- /dev/null +++ b/examples/example-evals-flags/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "lib": ["ES2022"], + "moduleResolution": "bundler", + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "include": ["**/*.ts"], + "exclude": ["node_modules"] +} + diff --git a/examples/example-evals-nextjs/src/lib/capabilities/classify-ticket/evaluations/ticket-classification.eval.ts b/examples/example-evals-nextjs/src/lib/capabilities/classify-ticket/evaluations/ticket-classification.eval.ts index 0b807f20..93d37de8 100644 --- a/examples/example-evals-nextjs/src/lib/capabilities/classify-ticket/evaluations/ticket-classification.eval.ts +++ b/examples/example-evals-nextjs/src/lib/capabilities/classify-ticket/evaluations/ticket-classification.eval.ts @@ -3,7 +3,7 @@ import { jaccardResponseScorer, spamClassificationScorer } from '../../../scorer import { classifyTicketStep } from '../../../capabilities/classify-ticket/prompts'; import { pickFlags } from '@/lib/app-scope'; -Eval('Spam classification', { +Eval('spam-classification', { configFlags: pickFlags('ticketClassification'), data: () => [ { diff --git a/examples/example-evals-nextjs/test/feature.eval.ts b/examples/example-evals-nextjs/test/feature.eval.ts index 624de95a..e46c1d40 100644 --- a/examples/example-evals-nextjs/test/feature.eval.ts +++ b/examples/example-evals-nextjs/test/feature.eval.ts @@ -20,7 +20,7 @@ const exactMatchScorer = ({ output, expected }: { output: string; expected?: str }; }; -Eval('Basic demo', { +Eval('Basic-demo', { configFlags: pickFlags('behavior'), data: () => [ { diff --git a/packages/ai/src/config/index.ts b/packages/ai/src/config/index.ts index f36bac94..4efefe05 100644 --- a/packages/ai/src/config/index.ts +++ b/packages/ai/src/config/index.ts @@ -48,6 +48,9 @@ export interface AxiomConnectionConfig { */ export interface AxiomEvalInstrumentationOptions { url: string; + /** + * Axiom URL for resources like evaluations, prompts, etc. + */ token: string; dataset: string; } diff --git a/packages/ai/src/config/resolver.ts b/packages/ai/src/config/resolver.ts index c56f278e..87a0ecb5 100644 --- a/packages/ai/src/config/resolver.ts +++ b/packages/ai/src/config/resolver.ts @@ -1,5 +1,16 @@ import type { AxiomEvalInstrumentationOptions, ResolvedAxiomConfig } from './index'; +/** + * Builds a resources URL under the assumption that the API URL is in the format of https://api.axiom.co by replacing the subdomain with app. + * @param urlString - The API URL + * @returns The resources URL + */ +const buildConsoleUrl = (urlString: string) => { + const url = new URL(urlString); + + return `${url.protocol}//app.${url.host.split('api.').at(-1)}`; +}; + /** * Resolve Axiom connection settings from resolved config. * @@ -11,9 +22,16 @@ import type { AxiomEvalInstrumentationOptions, ResolvedAxiomConfig } from './ind */ export function resolveAxiomConnection( config: ResolvedAxiomConfig, -): AxiomEvalInstrumentationOptions { +): AxiomEvalInstrumentationOptions & { consoleEndpointUrl: string } { + let consoleEndpointUrl = buildConsoleUrl(config.eval.url); + + if ('__overrideEndpointUrl' in config.eval) { + consoleEndpointUrl = config.eval.__overrideEndpointUrl as string; + } + return { url: config.eval.url, + consoleEndpointUrl: consoleEndpointUrl, token: config.eval.token, dataset: config.eval.dataset, }; diff --git a/packages/ai/src/evals/eval.service.ts b/packages/ai/src/evals/eval.service.ts index 60be54ea..9f8680e9 100644 --- a/packages/ai/src/evals/eval.service.ts +++ b/packages/ai/src/evals/eval.service.ts @@ -1,7 +1,62 @@ import type { Case, Chat, Evaluation, Task } from './eval.types'; +import { createFetcher, type Fetcher } from '../utils/fetcher'; import type { ResolvedAxiomConfig } from '../config/index'; import { resolveAxiomConnection } from '../config/resolver'; +export interface EvaluationApiConfig { + dataset?: string; + region?: string; + baseUrl?: string; + apiUrl?: string; + token?: string; +} + +export type EvaluationStatus = 'running' | 'completed' | 'errored' | 'cancelled'; + +export interface EvaluationApiPayloadBase { + id: string; + name: string; + dataset: string; + region: string; + baselineId?: string; + totalCases?: number; + scorers?: string[]; + config?: Record; + status: EvaluationStatus; + successCases?: number; + erroredCases?: number; + durationMs?: number; + scorerAvgs?: number[]; + version: string; +} + +export class EvaluationApiClient { + private readonly fetcher: Fetcher; + constructor(config: ResolvedAxiomConfig) { + const { consoleEndpointUrl, token } = resolveAxiomConnection(config); + + this.fetcher = createFetcher(consoleEndpointUrl, token ?? ''); + } + + async createEvaluation(evaluation: EvaluationApiPayloadBase) { + const resp = await this.fetcher(`/api/evaluations/v3`, { + method: 'POST', + body: JSON.stringify(evaluation), + }); + + return resp.json(); + } + + async updateEvaluation(evaluation: Partial) { + const resp = await this.fetcher(`/api/evaluations/v3/${evaluation.id}`, { + method: 'PATCH', + body: JSON.stringify(evaluation), + }); + + return resp.json(); + } +} + /** Query axiom to find a baseline for an Eval */ export const findBaseline = async (evalName: string, config: ResolvedAxiomConfig) => { const { dataset, url, token } = resolveAxiomConnection(config); diff --git a/packages/ai/src/evals/eval.ts b/packages/ai/src/evals/eval.ts index c5f7945d..19fa58c9 100644 --- a/packages/ai/src/evals/eval.ts +++ b/packages/ai/src/evals/eval.ts @@ -19,7 +19,7 @@ import type { OutOfScopeFlag, } from './eval.types'; import type { Score, Scorer } from './scorers'; -import { findBaseline, findEvaluationCases } from './eval.service'; +import { EvaluationApiClient, findBaseline, findEvaluationCases } from './eval.service'; import { getGlobalFlagOverrides, setGlobalFlagOverrides } from './context/global-flags'; import { deepEqual } from '../util/deep-equal'; import { dotNotationToNested } from '../util/dot-path'; @@ -41,7 +41,7 @@ declare module 'vitest' { } } -const nanoid = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 10); +const createVersionId = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', 10); /** * Creates and registers an evaluation suite with the given name and parameters. @@ -171,9 +171,12 @@ async function registerEval< ? await findEvaluationCases(baselineId, axiomConfig) : await findBaseline(evalName, axiomConfig); + const evaluationApiClient = new EvaluationApiClient(axiomConfig); + // create a version code - const evalVersion = nanoid(); + const evalVersion = createVersionId(); let evalId = ''; // get traceId + let suiteStart: number; let suiteSpan: ReturnType | undefined; let suiteContext: Context | undefined; @@ -189,6 +192,14 @@ async function registerEval< | undefined; beforeAll(async (suite) => { + suite.meta.evaluation = { + id: evalId, + name: evalName, + version: evalVersion, + baseline: baseline ?? undefined, + configFlags: opts.configFlags, + }; + try { await instrumentationReady; } catch (error) { @@ -217,9 +228,25 @@ async function registerEval< }, }); evalId = suiteSpan.spanContext().traceId; + suite.meta.evaluation.id = evalId; suiteSpan.setAttribute(Attr.Eval.ID, evalId); suiteContext = trace.setSpan(context.active(), suiteSpan); + await evaluationApiClient.createEvaluation({ + id: evalId, + name: evalName, + dataset: axiomConfig.eval.dataset, + version: evalVersion, + region: 'US', + baselineId: baseline?.id ?? undefined, + totalCases: dataset.length, + scorers: opts.scorers?.map((s) => s.name) ?? [], + config: { + flags: opts.configFlags ?? [], + }, + status: 'running', + }); + // Ensure worker process knows CLI overrides if (injectedOverrides && Object.keys(injectedOverrides).length > 0) { try { @@ -239,6 +266,7 @@ async function registerEval< suite.meta.evaluation.flagConfig = flagConfig; const flagConfigJson = JSON.stringify(flagConfig); suiteSpan.setAttribute('eval.config.flags', flagConfigJson); + suiteStart = performance.now(); }); afterAll(async (suite) => { @@ -287,6 +315,24 @@ async function registerEval< }; } + const durationMs = Math.round(performance.now() - suiteStart); + + const successCases = suite.tasks.filter( + (task) => task.meta.case.status === 'success', + ).length; + const erroredCases = suite.tasks.filter( + (task) => task.meta.case.status === 'fail' || task.meta.case.status === 'pending', + ).length; + + await evaluationApiClient.updateEvaluation({ + id: evalId, + status: 'completed', + totalCases: dataset.length, + successCases, + erroredCases, + durationMs, + }); + // end root span suiteSpan?.setStatus({ code: SpanStatusCode.OK }); suiteSpan?.end(); diff --git a/packages/ai/src/utils/fetcher.ts b/packages/ai/src/utils/fetcher.ts new file mode 100644 index 00000000..ea31c20a --- /dev/null +++ b/packages/ai/src/utils/fetcher.ts @@ -0,0 +1,16 @@ +export interface Fetcher { + (path: string, options: RequestInit): Promise; +} + +export const createFetcher = (baseUrl: string, token: string): Fetcher => { + return (path: string, options: RequestInit) => + fetch(new URL(path, baseUrl).toString(), { + ...options, + headers: { + ...options.headers, + 'content-type': 'application/json', + authorization: `Bearer ${token}`, + 'x-axiom-check': 'good', + }, + }); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a345c75..1ecf25c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,55 @@ importers: specifier: ^2.5.4 version: 2.5.6 + examples/example-evals-flags: + dependencies: + '@ai-sdk/openai': + specifier: 2.0.0-beta.11 + version: 2.0.0-beta.11(zod@4.1.5) + '@opentelemetry/api': + specifier: ^1.9.0 + version: 1.9.0 + '@opentelemetry/exporter-trace-otlp-http': + specifier: ^0.202.0 + version: 0.202.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': + specifier: ^2.1.0 + version: 2.1.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': + specifier: ^2.0.1 + version: 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': + specifier: ^1.34.0 + version: 1.37.0 + ai: + specifier: 5.0.0-beta.24 + version: 5.0.0-beta.24(zod@4.1.5) + axiom: + specifier: workspace:* + version: link:../../packages/ai + zod: + specifier: 'catalog:' + version: 4.1.5 + devDependencies: + '@types/node': + specifier: ^22.17.2 + version: 22.17.2 + autoevals: + specifier: ^0.0.130 + version: 0.0.130 + chalk: + specifier: ^5.3.0 + version: 5.5.0 + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + tsx: + specifier: ^4.19.2 + version: 4.20.4 + typescript: + specifier: 'catalog:' + version: 5.9.2 + examples/example-evals-nextjs: dependencies: '@ai-sdk/openai': @@ -73,7 +122,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.5.4(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 @@ -204,7 +253,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.5.4(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 @@ -268,7 +317,7 @@ importers: version: link:../../packages/ai next: specifier: latest - version: 15.5.4(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 @@ -747,8 +796,8 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@emnapi/runtime@1.4.5': - resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/runtime@1.6.0': + resolution: {integrity: sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==} '@esbuild/aix-ppc64@0.25.9': resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} @@ -982,138 +1031,142 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.4': + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.4': + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.3': + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.3': + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.3': + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} + '@img/sharp-libvips-linux-arm@1.2.3': + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} + '@img/sharp-libvips-linux-ppc64@1.2.3': + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-s390x@1.2.3': + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.3': + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.3': + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.4': + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.4': + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} + '@img/sharp-linux-ppc64@0.34.4': + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-s390x@0.34.4': + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.4': + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.4': + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.4': + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.4': + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} + '@img/sharp-win32-arm64@0.34.4': + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.4': + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.4': + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1151,57 +1204,57 @@ packages: '@next/env@15.4.6': resolution: {integrity: sha512-yHDKVTcHrZy/8TWhj0B23ylKv5ypocuCwey9ZqPyv4rPdUdRzpGCkSi03t04KBPyU96kxVtUqx6O3nE1kpxASQ==} - '@next/env@15.5.4': - resolution: {integrity: sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==} + '@next/env@16.0.1': + resolution: {integrity: sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==} - '@next/swc-darwin-arm64@15.5.4': - resolution: {integrity: sha512-nopqz+Ov6uvorej8ndRX6HlxCYWCO3AHLfKK2TYvxoSB2scETOcfm/HSS3piPqc3A+MUgyHoqE6je4wnkjfrOA==} + '@next/swc-darwin-arm64@16.0.1': + resolution: {integrity: sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.4': - resolution: {integrity: sha512-QOTCFq8b09ghfjRJKfb68kU9k2K+2wsC4A67psOiMn849K9ZXgCSRQr0oVHfmKnoqCbEmQWG1f2h1T2vtJJ9mA==} + '@next/swc-darwin-x64@16.0.1': + resolution: {integrity: sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.4': - resolution: {integrity: sha512-eRD5zkts6jS3VfE/J0Kt1VxdFqTnMc3QgO5lFE5GKN3KDI/uUpSyK3CjQHmfEkYR4wCOl0R0XrsjpxfWEA++XA==} + '@next/swc-linux-arm64-gnu@16.0.1': + resolution: {integrity: sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@15.5.4': - resolution: {integrity: sha512-TOK7iTxmXFc45UrtKqWdZ1shfxuL4tnVAOuuJK4S88rX3oyVV4ZkLjtMT85wQkfBrOOvU55aLty+MV8xmcJR8A==} + '@next/swc-linux-arm64-musl@16.0.1': + resolution: {integrity: sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@15.5.4': - resolution: {integrity: sha512-7HKolaj+481FSW/5lL0BcTkA4Ueam9SPYWyN/ib/WGAFZf0DGAN8frNpNZYFHtM4ZstrHZS3LY3vrwlIQfsiMA==} + '@next/swc-linux-x64-gnu@16.0.1': + resolution: {integrity: sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@15.5.4': - resolution: {integrity: sha512-nlQQ6nfgN0nCO/KuyEUwwOdwQIGjOs4WNMjEUtpIQJPR2NUfmGpW2wkJln1d4nJ7oUzd1g4GivH5GoEPBgfsdw==} + '@next/swc-linux-x64-musl@16.0.1': + resolution: {integrity: sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@15.5.4': - resolution: {integrity: sha512-PcR2bN7FlM32XM6eumklmyWLLbu2vs+D7nJX8OAIoWy69Kef8mfiN4e8TUv2KohprwifdpFKPzIP1njuCjD0YA==} + '@next/swc-win32-arm64-msvc@16.0.1': + resolution: {integrity: sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.4': - resolution: {integrity: sha512-1ur2tSHZj8Px/KMAthmuI9FMp/YFusMMGoRNJaRZMOlSkgvLjzosSdQI0cJAKogdHl3qXUQKL9MGaYvKwA7DXg==} + '@next/swc-win32-x64-msvc@16.0.1': + resolution: {integrity: sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2433,13 +2486,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2528,8 +2574,8 @@ packages: destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} diff-match-patch@1.0.5: @@ -2922,9 +2968,6 @@ packages: is-any-array@2.0.1: resolution: {integrity: sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -3208,9 +3251,9 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@15.5.4: - resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + next@16.0.1: + resolution: {integrity: sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -3539,8 +3582,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} + sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -3574,9 +3617,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -4238,7 +4278,7 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@emnapi/runtime@1.4.5': + '@emnapi/runtime@1.6.0': dependencies: tslib: 2.8.1 optional: true @@ -4394,90 +4434,93 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/sharp-darwin-arm64@0.34.3': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 + '@img/sharp-libvips-darwin-arm64': 1.2.3 optional: true - '@img/sharp-darwin-x64@0.34.3': + '@img/sharp-darwin-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 + '@img/sharp-libvips-darwin-x64': 1.2.3 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': + '@img/sharp-libvips-darwin-arm64@1.2.3': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': + '@img/sharp-libvips-darwin-x64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': + '@img/sharp-libvips-linux-arm64@1.2.3': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': + '@img/sharp-libvips-linux-arm@1.2.3': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': + '@img/sharp-libvips-linux-ppc64@1.2.3': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': + '@img/sharp-libvips-linux-s390x@1.2.3': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': + '@img/sharp-libvips-linux-x64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': + '@img/sharp-libvips-linuxmusl-x64@1.2.3': optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-linux-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.3 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-arm': 1.2.3 optional: true - '@img/sharp-linux-ppc64@0.34.3': + '@img/sharp-linux-ppc64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 + '@img/sharp-libvips-linux-ppc64': 1.2.3 optional: true - '@img/sharp-linux-s390x@0.34.3': + '@img/sharp-linux-s390x@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 + '@img/sharp-libvips-linux-s390x': 1.2.3 optional: true - '@img/sharp-linux-x64@0.34.3': + '@img/sharp-linux-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 + '@img/sharp-libvips-linux-x64': 1.2.3 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': + '@img/sharp-linuxmusl-arm64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': + '@img/sharp-linuxmusl-x64@0.34.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-wasm32@0.34.4': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.6.0 optional: true - '@img/sharp-win32-arm64@0.34.3': + '@img/sharp-win32-arm64@0.34.4': optional: true - '@img/sharp-win32-ia32@0.34.3': + '@img/sharp-win32-ia32@0.34.4': optional: true - '@img/sharp-win32-x64@0.34.3': + '@img/sharp-win32-x64@0.34.4': optional: true '@isaacs/cliui@8.0.2': @@ -4518,30 +4561,30 @@ snapshots: '@next/env@15.4.6': {} - '@next/env@15.5.4': {} + '@next/env@16.0.1': {} - '@next/swc-darwin-arm64@15.5.4': + '@next/swc-darwin-arm64@16.0.1': optional: true - '@next/swc-darwin-x64@15.5.4': + '@next/swc-darwin-x64@16.0.1': optional: true - '@next/swc-linux-arm64-gnu@15.5.4': + '@next/swc-linux-arm64-gnu@16.0.1': optional: true - '@next/swc-linux-arm64-musl@15.5.4': + '@next/swc-linux-arm64-musl@16.0.1': optional: true - '@next/swc-linux-x64-gnu@15.5.4': + '@next/swc-linux-x64-gnu@16.0.1': optional: true - '@next/swc-linux-x64-musl@15.5.4': + '@next/swc-linux-x64-musl@16.0.1': optional: true - '@next/swc-win32-arm64-msvc@15.5.4': + '@next/swc-win32-arm64-msvc@16.0.1': optional: true - '@next/swc-win32-x64-msvc@15.5.4': + '@next/swc-win32-x64-msvc@16.0.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4621,7 +4664,7 @@ snapshots: '@opentelemetry/resource-detector-azure': 0.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/resource-detector-container': 0.7.3(@opentelemetry/api@1.9.0) '@opentelemetry/resource-detector-gcp': 0.36.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.202.0(@opentelemetry/api@1.9.0) transitivePeerDependencies: - encoding @@ -4653,14 +4696,14 @@ snapshots: '@opentelemetry/core@2.1.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.36.0 + '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/exporter-jaeger@2.0.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.36.0 + '@opentelemetry/semantic-conventions': 1.37.0 jaeger-client: 3.19.0 '@opentelemetry/exporter-logs-otlp-grpc@0.202.0(@opentelemetry/api@1.9.0)': @@ -4878,7 +4921,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.36.0 + '@opentelemetry/semantic-conventions': 1.37.0 transitivePeerDependencies: - supports-color @@ -4945,7 +4988,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.203.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.36.0 + '@opentelemetry/semantic-conventions': 1.37.0 forwarded-parse: 2.1.2 transitivePeerDependencies: - supports-color @@ -5270,35 +5313,35 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/resource-detector-aws@2.3.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/resource-detector-azure@0.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/resource-detector-container@0.7.3(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/resource-detector-gcp@0.36.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.0.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.1.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.37.0 gcp-metadata: 6.1.1 transitivePeerDependencies: @@ -5327,7 +5370,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.36.0 + '@opentelemetry/semantic-conventions': 1.37.0 '@opentelemetry/sdk-logs@0.202.0(@opentelemetry/api@1.9.0)': dependencies: @@ -6076,18 +6119,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -6155,7 +6186,7 @@ snapshots: destr@2.0.5: {} - detect-libc@2.0.4: + detect-libc@2.1.2: optional: true diff-match-patch@1.0.5: {} @@ -6629,9 +6660,6 @@ snapshots: is-any-array@2.0.1: {} - is-arrayish@0.3.2: - optional: true - is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -6890,9 +6918,9 @@ snapshots: neo-async@2.6.2: {} - next@15.5.4(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@16.0.1(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 15.5.4 + '@next/env': 16.0.1 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001735 postcss: 8.4.31 @@ -6900,16 +6928,16 @@ snapshots: react-dom: 18.3.1(react@18.3.1) styled-jsx: 5.1.6(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.4 - '@next/swc-darwin-x64': 15.5.4 - '@next/swc-linux-arm64-gnu': 15.5.4 - '@next/swc-linux-arm64-musl': 15.5.4 - '@next/swc-linux-x64-gnu': 15.5.4 - '@next/swc-linux-x64-musl': 15.5.4 - '@next/swc-win32-arm64-msvc': 15.5.4 - '@next/swc-win32-x64-msvc': 15.5.4 + '@next/swc-darwin-arm64': 16.0.1 + '@next/swc-darwin-x64': 16.0.1 + '@next/swc-linux-arm64-gnu': 16.0.1 + '@next/swc-linux-arm64-musl': 16.0.1 + '@next/swc-linux-x64-gnu': 16.0.1 + '@next/swc-linux-x64-musl': 16.0.1 + '@next/swc-win32-arm64-msvc': 16.0.1 + '@next/swc-win32-x64-msvc': 16.0.1 '@opentelemetry/api': 1.9.0 - sharp: 0.34.3 + sharp: 0.34.4 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -7228,34 +7256,34 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.34.3: + sharp@0.34.4: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 semver: 7.7.2 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 optional: true shebang-command@2.0.0: @@ -7296,11 +7324,6 @@ snapshots: signal-exit@4.1.0: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - source-map-js@1.2.1: {} source-map@0.6.1: {}