Skip to content

basalt-ai/basalt-js

Repository files navigation

Basalt SDK

Basalt is a powerful tool for managing AI prompts and their release workflows. This SDK is the official NodeJS package for interacting with your Basalt prompts.

Installation

Install the Basalt SDK via npm:

npm install @basalt-ai/sdk

Usage

Importing and Initializing the SDK

To get started, import the BasaltSDK class and initialize it with your API key:

// Using module syntax
import { Basalt } from '@basalt-ai/sdk'

// Using CommonJS syntax
const { Basalt } = require('@basalt-ai/sdk');

const basalt = new Basalt({
    apiKey: 'your-api-key-here',
});

// Don't forget to put your apiKey into an env variable
const basalt = new Basalt({
    apiKey: process.env.BASALT_API_KEY
})

OpenTelemetry (Tracing)

Tracing is enabled by default for all Basalt SDK routes. To export spans, configure the built-in OTLP gRPC exporter:

import { Basalt } from '@basalt-ai/sdk'

const basalt = new Basalt({
  apiKey: process.env.BASALT_API_KEY!,
  telemetry: {
    // For a local collector without TLS
    insecure: true,
    serviceName: 'my-app',
    // Optionally override the collector endpoint
    // endpoint: 'localhost:4317',
  },
})

All spans include Basalt metadata attributes (e.g. basalt.sdk, basalt.version, basalt.span_type, and basalt.meta.*) and propagate trace context headers (traceparent, etc.) on outgoing Basalt API requests.

Integration Modes

  • Recommended: consume the published package (npm install @basalt-ai/sdk).
  • Advanced (source/submodule): if you bundle SDK source in your own build pipeline, make sure SDK compile-time constants are provided (__PUBLIC_API_URL__, __SDK_VERSION__, __SDK_TARGET__) or keep runtime fallbacks enabled.

Troubleshooting: No Traces in UI

  1. Check BASALT_API_KEY is set and valid.
  2. Check exporter endpoint (BASALT_OTEL_EXPORTER_OTLP_ENDPOINT) points to your collector.
  3. Ensure telemetry is enabled (telemetry.enabled !== false).
  4. If using OpenAI auto-instrumentation, install @opentelemetry/instrumentation-openai and call basalt.instrument({ openai: true }) before loading OpenAI.
  5. For local debugging in Node, set BASALT_DEBUG_STDOUT_SPANS=1 to print exported spans.

Add Custom Attributes

To add custom attributes to the current active span:

import { setCurrentSpanAttributes } from '@basalt-ai/sdk'

setCurrentSpanAttributes({
  'basalt.meta.customer_id': 'cust_123',
})

Share / Mutate Basalt Context

To attach context that will be added to all Basalt spans created within a scope:

import { BasaltContextManager } from '@basalt-ai/sdk'

await BasaltContextManager.withMergedContext(
  {
    user: { id: 'user_1' },
    metadata: { env: 'prod' },
  },
  async () => {
    // Calls inside this function will automatically include these attributes
    // in Basalt spans.
  },
)

API Spec

Basalt

  • Constructors

    The Basalt constructor accepts following options:

    • apiKey: string: The API Key you generated from your Basalt workspace.

    • logLevel?: "all" | "warning" | "none"

      Configure what Basalt logs to the console. Recommended: warning at dev, none in production.

Basalt.Prompt

The prompt attribute provides methods to interact with your Basalt prompts:

  • Get a Prompt

    Retrieve a specific prompt using a slug, and optional filters tag and version. Without tag or version would, the production version of your prompt is selected by default.

    Example Usage:

    // With a single object. Tag and filters are still optional,
    // use this if you need more control over the specific version of
    // the prompt to select
    const result = await basalt.prompt.get({ slug: 'prompt-slug', tag: 'custom-tag' });
    const result = await basalt.prompt.get({ slug: 'prompt-slug', version: '1.0.0' });
    
    // With the slug, leaving the rest optional
    // this is useful for easily fetching the prod version of prompts
    const result = await basalt.prompt.get('prompt-slug');
    
    // This is also valid
    const result = await basalt.prompt.get('prompt-slug', { tag: 'latest' });
    const result = await basalt.prompt.get('prompt-slug', { version: '1.0.0' });
    
    // If your prompt has variables,they need to be provided
    // in the options.
    // Example prompt: "Hello {{name}}"
    const result = await basalt.prompt.get({
      	slug: 'prompt-slug',
      	variables: {
      		name: "John Doe"
      	}
    })
    
    // Handle the result by unwrapping the error / value
    if (result.error) {
      console.log('Could not fetch prompt', result.error.message);
      return;
    }
    
    // Use the prompt with your AI provider of choice
    // Example: OpenAI
    openaiClient.chat.completion.create({
      	model: 'gpt-4o'
      	messages: [{ role: 'User', content: result.value.text }]
      })

In-Memory Cache

The Basalt SDK includes an in-memory caching mechanism to improve performance by reducing redundant API calls. When you request a prompt multiple times with the same parameters, the SDK can serve it from the cache instead of making additional network requests.

How the Cache Works

The SDK implements a simple but effective in-memory cache through the MemoryCache class that:

  • Stores key-value pairs in memory
  • Supports configurable time-to-live (TTL) for each cached entry
  • Automatically invalidates expired entries
// Example of how caching works internally
// (You don't need to implement this yourself)

// First request fetches from API and caches the result
const result1 = await basalt.prompt.get('my-prompt');

// Subsequent identical requests within the TTL period 
// will be served from cache
const result2 = await basalt.prompt.get('my-prompt');

Cache Configuration

By default, the cache is enabled with reasonable defaults. You can configure the cache behavior when initializing the SDK:

const basalt = new Basalt({
    apiKey: process.env.BASALT_API_KEY,
    cache: {
        enabled: true,     // Enable/disable caching (default: true)
        ttl: 60000,        // Default TTL in milliseconds (default: 60000 - 1 minute)
    }
});

Cache Benefits

  • Improved Performance: Reduces latency for frequently accessed prompts
  • Reduced API Usage: Minimizes the number of API calls to the Basalt service
  • Offline Resilience: Previously cached prompts remain available even during temporary network issues

The cache is particularly useful in high-throughput applications where the same prompts are requested multiple times in a short period.

Migration from Legacy Monitoring

If you were using the legacy manual monitoring system (removed in v2.x), migrate to OpenTelemetry:

Before (Legacy):

const result = await basalt.prompt.get('my-prompt');
const generation = result.generation; // No longer available

await basalt.monitor.createExperiment(...)
trace.end(); // No longer available

After (OpenTelemetry):

// Use startObserve() for root spans with experiment tracking
const span = basalt.startObserve({
  name: 'my-operation',
  featureSlug: 'my-feature',
  experiment: {
    id: 'exp-1',
    name: 'My Experiment',
    featureSlug: 'my-feature',
  },
});

// Wrap operations with the root span context
await BasaltContextManager.withRootSpan(span, async () => {
  // Your operations here - child spans will auto-connect
  const result = await basalt.prompt.get('my-prompt');
  // ...
});

// End the span
span.end();

Key changes:

  • basalt.prompt.get() no longer returns a generation object
  • basalt.monitor.* methods removed - use OpenTelemetry spans instead
  • Use basalt.startObserve() or basalt.observe() for tracing
  • See OpenTelemetry section above for full documentation

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors