Skip to main content
Generate a chart’s title, subtitle, and caption with natural language. Send a GraphConfig and a prompt, receive a GraphConfig with narrative text written into config.content.

Methods

generateNarrative

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

generateNarrativeStream

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

Parameters

interface GenerateNarrativeParams {
  config: GraphConfig;
  userPrompt: string;
  metadata?: Metadata;
}
FieldTypeRequiredDescription
configGraphConfigYesThe chart configuration to narrate
userPromptstringYesNatural language instruction for the narrative — tone, focus, or refinements
metadataMetadataNoRequest tracking information

Response

interface GenerateNarrativeResponse {
  response: {
    message: string;
  };
  config: GraphConfig;
}
FieldTypeDescription
response.messagestringExplanation of the narrative produced
configGraphConfigUpdated chart configuration. Title, subtitle, and caption are written into config.content as TipTap JSON documents.
The response is validated with Zod. Invalid responses throw an error. Which fields are written — title only, title and caption, or all three — depends on the storytelling level. See Invocation effort and chart narrative for how metadata.effort controls this.

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: 'line',
  data: {
    columns: [
      { key: 'month', label: 'Month' },
      { key: 'users', label: 'Active Users' },
    ],
    rows: [
      { month: 'Jan', users: 1200 },
      { month: 'Feb', users: 1800 },
      { month: 'Mar', users: 3100 },
    ],
  },
};

const result = await ai.generateNarrative({
  config,
  userPrompt: 'Write a punchy title and a one-line caption',
});

// Narrative is embedded in the config content as TipTap JSON
console.log(result.config.content?.title);
console.log(result.config.content?.caption);

With Progress Callback

Use the onProgress callback to show real-time progress without full streaming:
const result = await ai.generateNarrative(
  {
    config,
    userPrompt: 'Make the title more specific and lead with the headline number',
  },
  (progress) => {
    console.log(progress.message);
  }
);

Streaming

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

const stream = await ai.generateNarrativeStream({
  config,
  userPrompt: 'Write a title, subtitle, and caption',
});

for await (const event of stream) {
  if (isProgressEvent(event)) {
    console.log(event.message);
  }

  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.generateNarrative({
    config,
    userPrompt: 'Write a title for this chart',
  });
} catch (error) {
  if (isGraphyApiError(error)) {
    console.error('API error:', error.message);
  }
}
See Error Handling for retry behavior and error types.