Skip to main content
Modify charts using natural language. Send a GraphConfig and a prompt, receive an updated GraphConfig.

Methods

generateGraph

Processes the request and returns the final result. Internally handles streaming and collects the response.
async generateGraph(
  params: GenerateGraphParams,
  onProgress?: (event: ProgressEvent) => void,
  signal?: AbortSignal
): Promise<GenerateGraphResponse>

generateGraphStream

Returns an async iterator that yields events as they arrive.
async generateGraphStream(
  params: GenerateGraphParams,
  signal?: AbortSignal
): Promise<AsyncIterableIterator<SSEEvent<GenerateGraphResponse>>>

Parameters

interface GenerateGraphParams {
  config: GraphConfig;
  userPrompt: string;
  metadata?: Metadata;
  storytellingOptions?: StorytellingOptions;
}
FieldTypeRequiredDescription
configGraphConfigYesThe current chart configuration
userPromptstringYesNatural language instruction
metadataMetadataNoRequest tracking information
storytellingOptionsStorytellingOptionsNoPrune storytelling from config content client-side (SDK only).

Metadata

interface Metadata {
  callId?: string;
  locale?: string;
  storytellingEffort?: 'none' | 'low' | 'medium' | 'high';
}
FieldTypeDescription
callIdstringRequired when metadata is provided. Unique identifier for tracking and debugging.
localestringLocale for responses (e.g., en-US, fr-FR).
storytellingEffort'none' | 'low' | 'medium' | 'high'Which narrative fields the agent fills. See Storytelling and narrative. Default is 'low'.

Response

interface GenerateGraphResponse {
  config: GraphConfig;
  response: {
    message: string;
    steps?: string[];
  };
}
FieldTypeDescription
configGraphConfigUpdated chart configuration. Narrative (title, subtitle, caption) is embedded in config.content as TipTap JSON documents; see Storytelling and narrative.
response.messagestringExplanation of changes made
response.stepsstring[]Breakdown of individual modifications
The response is validated with Zod. Invalid responses throw an error.

Storytelling and narrative

metadata.storytellingEffort controls which of title, subtitle, and caption the agent fills. The agent is instructed as follows:
EffortTitleSubtitleCaption
'none'
'low'nullnull
'medium'null
'high'
  • 'none' — No narrative is generated; config.content title, subtitle, and caption remain empty.
  • 'low' — Only title is filled (a trend, pattern or conclusion from the data). Default.
  • 'medium'Title and caption are filled (caption describes trends, patterns or insights).
  • 'high'Title, subtitle, and caption are all filled (subtitle describes what is being visualised).
Narrative fields are embedded in config.content as TipTap JSON documents (config.content.title, config.content.subtitle, config.content.caption). With the SDK you can pass storytellingOptions to prune the content client-side: the SDK removes any excluded field from config.content before returning (see StorytellingOptions in the Type Reference).
const result = await ai.generateGraph({
  config,
  userPrompt: 'Show sales by region and add a clear title',
  metadata: { storytellingEffort: 'high' }, // title + subtitle + caption all filled
});

// Narrative is embedded in the config content as TipTap JSON
console.log(result.config.content?.title);    // TipTap JSON doc with title text
console.log(result.config.content?.subtitle); // TipTap JSON doc (undefined if effort is low or medium)
console.log(result.config.content?.caption);  // TipTap JSON doc (undefined if effort is low)

Basic Usage

import { GraphyAiSdk } from '@graphysdk/agents-sdk';
import type { GraphConfig } from '@graphysdk/core';

const ai = new GraphyAiSdk({
  apiKey: process.env.GRAPHY_API_KEY,
  baseUrl: 'https://agents.graphy.dev',
});

const config: GraphConfig = {
  type: 'column',
  data: {
    columns: [
      { key: 'month', label: 'Month' },
      { key: 'sales', label: 'Sales' },
    ],
    rows: [
      { month: 'Jan', sales: 100 },
      { month: 'Feb', sales: 120 },
      { month: 'Mar', sales: 115 },
    ],
  },
};

const result = await ai.generateGraph({
  config,
  userPrompt: 'Change this to a bar chart and sort by sales descending',
});

console.log(result.config); // Updated GraphConfig
console.log(result.response.message); // Explanation

With Progress Callback

Use the onProgress callback to show real-time progress without full streaming:
const result = await ai.generateGraph(
  {
    config,
    userPrompt: 'Add a trend line and change colors to blue',
  },
  (progress) => {
    console.log(`${progress.percentage}% - ${progress.message}`);
  }
);

ProgressEvent

interface ProgressEvent {
  type: 'progress';
  percentage: number;
  message?: string;
  metadata?: Record<string, unknown>;
}

With Abort Signal

Cancel a request mid-operation:
const controller = new AbortController();

// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);

try {
  const result = await ai.generateGraph(
    { config, userPrompt: 'Create a complex visualization' },
    undefined,
    controller.signal
  );
} catch (error) {
  if (error instanceof Error && error.name === 'AbortError') {
    console.log('Request cancelled');
  }
}

Streaming

For full control over the event stream:
import { isProgressEvent, isCompleteEvent, isErrorEvent } from '@graphysdk/agents-sdk';

const stream = await ai.generateGraphStream({
  config,
  userPrompt: 'Add annotations for peak values',
});

for await (const event of stream) {
  if (isProgressEvent(event)) {
    console.log(`${event.percentage}%`);
  }

  if (isCompleteEvent(event)) {
    console.log('Result:', event.data.config);
  }

  if (isErrorEvent(event)) {
    console.error('Error:', event.error);
  }
}
See Streaming for cancellation and React patterns.

Error Handling

import { isGraphyApiError } from '@graphysdk/agents-sdk';

try {
  const result = await ai.generateGraph({
    config,
    userPrompt: 'Change to a bar chart',
  });
} catch (error) {
  if (isGraphyApiError(error)) {
    console.error('API error:', error.message);
  } else if (error instanceof Error && error.name === 'AbortError') {
    console.log('Request cancelled');
  } else {
    console.error('Unexpected error:', error);
  }
}
See Error Handling for retry behavior and error types.