@graphysdk/agents-sdk 1.2.0-beta.1773268716508 → 1.2.0-beta.1773662483280

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("tslib"),e=require("zod");class r extends Error{constructor(t){super(t),this.name="GraphyApiError"}}class i{constructor(t){if(this.tag="[GRAPHY]",!t.apiKey||0===t.apiKey.trim().length)throw new Error("apiKey is required and must not be empty");const e=new URL(t.baseUrl);if(!["http:","https:"].includes(e.protocol))throw new Error(`Invalid baseUrl protocol: ${e.protocol}. Only http(s) is allowed.`);this.apiKey=t.apiKey,this.baseUrl=e.origin+e.pathname.replace(/\/$/,""),this.timeout=t.timeout||6e4,this.retryConfig=t.retryConfig||{attempts:3,delay:1e3,backoff:2},this.logger=t.logger||{log:console.log,warn:console.warn,error:console.error,debug:console.debug}}static isProgressEvent(t){return"progress"===t.type}static isCompleteEvent(t){return"complete"===t.type}static isErrorEvent(t){return"error"===t.type}stream(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.makeRequest(e,r,i);return this.parseSSE(t)})}fetch(e,n,o,s){return t.__awaiter(this,void 0,void 0,function*(){var a,l,c,h;const u=Date.now();this.logger.debug(`${this.tag} Fetch: ${e}`);try{const y=yield this.makeRequest(e,n,s),f=y.headers.get("content-type");if(null==f?void 0:f.includes("text/event-stream")){try{for(var g,p=!0,d=t.__asyncValues(this.parseSSE(y));!(a=(g=yield d.next()).done);p=!0){h=g.value,p=!1;const t=h;if(i.isProgressEvent(t)&&o&&o(t),i.isCompleteEvent(t))return t.data;if(i.isErrorEvent(t)){const i=Date.now()-u;throw this.logger.error(`${this.tag} Server error: ${e} ${i}ms`,t.error),new r(t.error)}}}catch(t){l={error:t}}finally{try{p||a||!(c=d.return)||(yield c.call(d))}finally{if(l)throw l.error}}const n=Date.now()-u;throw this.logger.error(`${this.tag} Stream incomplete: ${e} ${n}ms`),new r("Stream ended without completion")}return yield y.json()}catch(t){const i=Date.now()-u;if(this.logger.error(`${this.tag} Fetch failed: ${e} ${i}ms`,t),t instanceof r)throw t;throw t}finally{const t=Date.now()-u;this.logger.debug(`${this.tag} Fetch completed: ${e} ${t}ms`)}})}ping(){return t.__awaiter(this,void 0,void 0,function*(){const t=Date.now();try{return yield this.makeRequest("/health",void 0,void 0,this.retryConfig.attempts,"GET"),{ok:!0,latency:Date.now()-t}}catch(e){return{ok:!1,latency:Date.now()-t}}})}sleep(e){return t.__awaiter(this,void 0,void 0,function*(){return new Promise(t=>setTimeout(t,e))})}parseSSE(e){return t.__asyncGenerator(this,arguments,function*(){if(!e.body)throw new r("Response body is null");const i=e.body.getReader(),n=new TextDecoder;let o="",s="",a="";try{for(;;){const{done:e,value:r}=yield t.__await(i.read());if(e)break;o+=n.decode(r,{stream:!0});const l=o.split(/\r?\n/);o=l.pop()||"";for(const e of l)if(e.startsWith("event: "))s=e.slice(7).trim();else if(e.startsWith("data: "))a+=(a?"\n":"")+e.slice(6);else if(""===e.trim()&&a){try{const e=JSON.parse(a);let r;if("progress"===s){const t=e;r=Object.assign({type:"progress"},t)}else if("complete"===s)r={type:"complete",data:e};else{if("error"!==s){s="",a="";continue}{const t=e;r=Object.assign({type:"error"},t)}}if(yield yield t.__await(r),"complete"===s||"error"===s)return yield t.__await(void 0)}catch(t){this.logger.warn("Invalid SSE data format",a)}s="",a=""}}}finally{i.releaseLock()}})}makeRequest(e,i,n){return t.__awaiter(this,arguments,void 0,function*(t,e,i,n=1,o="POST"){if(!t.startsWith("/"))throw new r("Invalid endpoint: must start with /");const s=new URL(t,this.baseUrl);if(s.origin!==new URL(this.baseUrl).origin)throw new r("Endpoint resolved to unexpected origin");this.logger.debug(`${this.tag} Request ${n}/${this.retryConfig.attempts}: ${s}`);const a=new AbortController,l=setTimeout(()=>a.abort(),this.timeout),c=()=>a.abort();i&&i.addEventListener("abort",c);try{const l=yield fetch(s,Object.assign({method:o,headers:{"Content-Type":"application/json",Accept:"application/json, text/event-stream","Cache-Control":"no-cache",Authorization:`Bearer ${this.apiKey}`,"User-Agent":"Graphy-SDK/1.0"},signal:a.signal},"POST"===o&&{body:JSON.stringify(e)}));if(!l.ok){const s=l.status>=500||429===l.status;let a=`HTTP ${l.status}`;try{const t=yield l.json();if("object"==typeof t&&null!==t){const e=t;"string"==typeof e.message?a=e.message:"string"==typeof e.error&&(a=e.error)}}catch(t){}const c=new r(a);if(s&&n<this.retryConfig.attempts&&!(null==i?void 0:i.aborted)){const r=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,n-1);return this.logger.warn(`${this.tag} Retrying ${t} in ${r}ms (attempt ${n+1})`),yield this.sleep(r),this.makeRequest(t,e,i,n+1,o)}throw this.logger.error(`${this.tag} Request failed: ${t} (${l.status}) - ${a}`),c}return this.logger.debug(`${this.tag} Connected: ${t}`),l}catch(s){if(s instanceof r)throw s;if(s instanceof Error&&"AbortError"===s.name)throw this.logger.debug(`${this.tag} Aborted: ${t}`),s;if(n<this.retryConfig.attempts&&!(null==i?void 0:i.aborted)){const r=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,n-1);return this.logger.warn(`${this.tag} Network error, retrying ${t} in ${r}ms`),yield this.sleep(r),this.makeRequest(t,e,i,n+1,o)}throw this.logger.error(`${this.tag} Network error: ${t}`,s),new r("Network error")}finally{clearTimeout(l),i&&i.removeEventListener("abort",c)}})}}const n=e.z.enum(["EN_GB","EN_US"]),o=e.z.custom(t=>null!=t&&"object"==typeof t),s=e.z.enum(["none","low","medium","high"]);e.z.object({callId:e.z.string(),locale:n.optional(),storytellingEffort:s.optional().default("low")});const a=e.z.enum(["line","bar","groupedBar","stackedBar","100StackedBar","column","groupedColumn","stackedColumn","100StackedColumn","combo","pie","donut","funnel","heatmap","scatter","waterfall","table"]),l=e.z.object({dataPrepPrompt:e.z.string(),chartType:a,summary:e.z.string()}),c=e.z.object({title:e.z.string(),subtitle:e.z.string(),caption:e.z.string().nullable()}),h=e.z.object({config:o,suggestions:e.z.array(l),description:e.z.string().nullable()}),u=e.z.object({title:e.z.string().nullish(),subtitle:e.z.string().nullish(),caption:e.z.string().nullish()}),g=e.z.object({config:o,response:e.z.object({message:e.z.string(),steps:e.z.array(e.z.string()).optional()}),narrative:u.nullish()}),p="/api/v0";exports.AiChartTypeEnum=a,exports.ChartNarrativeSchema=u,exports.GenerateGraphNarrativeResponseSchema=c,exports.GenerateGraphResponseSchema=g,exports.GenerateGraphSuggestionsResponseSchema=h,exports.GraphyAiSdk=class{constructor(t){this.client=new i(t)}generateGraph(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const{narrativeOptions:n}=e,o=t.__rest(e,["narrativeOptions"]),s=yield this.client.fetch(`${p}/generate`,o,r,i),a=g.parse(s);return this.stripNarrative(a,n)})}generateGraphStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){const{narrativeOptions:i}=e,n=t.__rest(e,["narrativeOptions"]),o=yield this.client.stream(`${p}/generate`,n,r);return this.wrapStreamWithNarrativeStripping(o,i)})}generateNarrative(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${p}/narrative`,e,r,i);return c.parse(t)})}generateNarrativeStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){return this.client.stream(`${p}/narrative`,e,r)})}generateSuggestions(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${p}/suggestions`,e,r,i);return h.parse(t)})}generateSuggestionsStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){return this.client.stream(`${p}/suggestions`,e,r)})}stripNarrative(t,e){return e&&t.narrative?Object.assign(Object.assign({},t),{narrative:{title:e.excludeTitle?null:t.narrative.title,subtitle:e.excludeSubtitle?null:t.narrative.subtitle,caption:e.excludeCaption?null:t.narrative.caption}}):t}wrapStreamWithNarrativeStripping(e,r){return t.__asyncGenerator(this,arguments,function*(){var n,o,s,a;try{for(var l,c=!0,h=t.__asyncValues(e);!(n=(l=yield t.__await(h.next())).done);c=!0){a=l.value,c=!1;const e=a;if(i.isCompleteEvent(e)){const i=this.stripNarrative(e.data,r);yield yield t.__await(Object.assign(Object.assign({},e),{data:i}))}else yield yield t.__await(e)}}catch(t){o={error:t}}finally{try{c||n||!(s=h.return)||(yield t.__await(s.call(h)))}finally{if(o)throw o.error}}})}},exports.GraphyApiError=r,exports.StorytellingEffortSchema=s,exports.SuggestionSchema=l;
1
+ "use strict";var t=require("tslib"),e=require("zod");class r extends Error{constructor(t,e){var r;super(t),Object.setPrototypeOf(this,new.target.prototype),this.name="GraphyApiError",this.status=null==e?void 0:e.status,this.code=null==e?void 0:e.code,this.retryable=null!==(r=null==e?void 0:e.retryable)&&void 0!==r&&r}}const i=t=>"progress"===t.type,o=t=>"complete"===t.type,s=t=>"error"===t.type;class n{constructor(t){if(this.tag="[GRAPHY]",!t.apiKey||0===t.apiKey.trim().length)throw new Error("apiKey is required and must not be empty");const e=new URL(t.baseUrl);if(!["http:","https:"].includes(e.protocol))throw new Error(`Invalid baseUrl protocol: ${e.protocol}. Only http(s) is allowed.`);this.apiKey=t.apiKey,this.baseUrl=e.origin+e.pathname.replace(/\/$/,""),this.timeout=t.timeout||6e4,this.retryConfig=t.retryConfig||{attempts:3,delay:1e3,backoff:2},this.logger=t.logger||{log:console.log,warn:console.warn,error:console.error,debug:console.debug}}static isProgressEvent(t){return i(t)}static isCompleteEvent(t){return o(t)}static isErrorEvent(t){return s(t)}stream(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.makeRequest(e,r,i);return this.parseSSE(t)})}fetch(e,n,a,l){return t.__awaiter(this,void 0,void 0,function*(){var c,g,h,u,d;const p=Date.now();this.logger.debug(`${this.tag} Fetch: ${e}`);try{const w=yield this.makeRequest(e,n,l),b=w.headers.get("content-type");if(null==b?void 0:b.includes("text/event-stream")){try{for(var y,f=!0,m=t.__asyncValues(this.parseSSE(w));!(c=(y=yield m.next()).done);f=!0){u=y.value,f=!1;const t=u;if(i(t)&&a&&a(t),o(t))return t.data;if(s(t)){const i=Date.now()-p;throw this.logger.error(`${this.tag} Server error: ${e} ${i}ms`,t.error),new r(t.error,{code:t.code,retryable:null!==(d=t.retryable)&&void 0!==d&&d})}}}catch(t){g={error:t}}finally{try{f||c||!(h=m.return)||(yield h.call(m))}finally{if(g)throw g.error}}const n=Date.now()-p;throw this.logger.error(`${this.tag} Stream incomplete: ${e} ${n}ms`),new r("Stream ended without completion")}return yield w.json()}catch(t){const i=Date.now()-p;if(this.logger.error(`${this.tag} Fetch failed: ${e} ${i}ms`,t),t instanceof r)throw t;throw t}finally{const t=Date.now()-p;this.logger.debug(`${this.tag} Fetch completed: ${e} ${t}ms`)}})}ping(){return t.__awaiter(this,void 0,void 0,function*(){const t=Date.now();try{return yield this.makeRequest("/health",void 0,void 0,this.retryConfig.attempts,"GET"),{ok:!0,latency:Date.now()-t}}catch(e){return{ok:!1,latency:Date.now()-t}}})}sleep(e){return t.__awaiter(this,void 0,void 0,function*(){return new Promise(t=>setTimeout(t,e))})}parseSSE(e){return t.__asyncGenerator(this,arguments,function*(){if(!e.body)throw new r("Response body is null");const i=e.body.getReader(),o=new TextDecoder;let s="",n="",a="";try{for(;;){const{done:e,value:r}=yield t.__await(i.read());if(e)break;s+=o.decode(r,{stream:!0});const l=s.split(/\r?\n/);s=l.pop()||"";for(const e of l)if(e.startsWith("event: "))n=e.slice(7).trim();else if(e.startsWith("data: "))a+=(a?"\n":"")+e.slice(6);else if(""===e.trim()&&a){try{const e=JSON.parse(a);let r;if("progress"===n){const t=e;r=Object.assign({type:"progress"},t)}else if("complete"===n)r={type:"complete",data:e};else{if("error"!==n){n="",a="";continue}{const t=e;r=Object.assign({type:"error"},t)}}if(yield yield t.__await(r),"complete"===n||"error"===n)return yield t.__await(void 0)}catch(t){this.logger.warn("Invalid SSE data format",a)}n="",a=""}}}finally{i.releaseLock()}})}makeRequest(e,i,o){return t.__awaiter(this,arguments,void 0,function*(t,e,i,o=1,s="POST"){if(!t.startsWith("/"))throw new r("Invalid endpoint: must start with /");const n=new URL(t,this.baseUrl);if(n.origin!==new URL(this.baseUrl).origin)throw new r("Endpoint resolved to unexpected origin");this.logger.debug(`${this.tag} Request ${o}/${this.retryConfig.attempts}: ${n}`);const a=new AbortController,l=setTimeout(()=>a.abort(),this.timeout),c=()=>a.abort();i&&i.addEventListener("abort",c);try{const l=yield fetch(n,Object.assign({method:s,headers:{"Content-Type":"application/json",Accept:"application/json, text/event-stream","Cache-Control":"no-cache",Authorization:`Bearer ${this.apiKey}`,"User-Agent":"Graphy-SDK/1.0"},signal:a.signal},"POST"===s&&{body:JSON.stringify(e)}));if(!l.ok){const n=l.status>=500||429===l.status;let a,c=`HTTP ${l.status}`;try{const t=yield l.json();if("object"==typeof t&&null!==t){const e=t;"string"==typeof e.message?c=e.message:"string"==typeof e.error&&(c=e.error),"string"==typeof e.code&&(a=e.code)}}catch(t){}const g=new r(c,{status:l.status,code:a,retryable:n});if(n&&o<this.retryConfig.attempts&&!(null==i?void 0:i.aborted)){const r=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,o-1);return this.logger.warn(`${this.tag} Retrying ${t} in ${r}ms (attempt ${o+1})`),yield this.sleep(r),this.makeRequest(t,e,i,o+1,s)}throw this.logger.error(`${this.tag} Request failed: ${t} (${l.status}) - ${c}`),g}return this.logger.debug(`${this.tag} Connected: ${t}`),l}catch(n){if(n instanceof r)throw n;if(n instanceof Error&&"AbortError"===n.name)throw this.logger.debug(`${this.tag} Aborted: ${t}`),n;if(o<this.retryConfig.attempts&&!(null==i?void 0:i.aborted)){const r=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,o-1);return this.logger.warn(`${this.tag} Network error, retrying ${t} in ${r}ms`),yield this.sleep(r),this.makeRequest(t,e,i,o+1,s)}throw this.logger.error(`${this.tag} Network error: ${t}`,n),new r("Network error",{retryable:!0})}finally{clearTimeout(l),i&&i.removeEventListener("abort",c)}})}}const a=e.z.enum(["EN_GB","EN_US"]),l=e.z.custom(t=>null!=t&&"object"==typeof t),c=e.z.enum(["none","low","medium","high"]);e.z.object({callId:e.z.string(),locale:a.optional(),storytellingEffort:c.optional().default("low")});const g=e.z.enum(["line","bar","groupedBar","stackedBar","100StackedBar","column","groupedColumn","stackedColumn","100StackedColumn","combo","pie","donut","funnel","heatmap","scatter","waterfall","table"]),h=e.z.object({dataPrepPrompt:e.z.string(),chartType:g,summary:e.z.string()}),u=e.z.object({title:e.z.string(),subtitle:e.z.string(),caption:e.z.string().nullable()}),d=e.z.object({config:l,suggestions:e.z.array(h),description:e.z.string().nullable()}),p=e.z.object({config:l,response:e.z.object({message:e.z.string(),steps:e.z.array(e.z.string()).optional()})}),y="/api/v0";exports.AiChartTypeEnum=g,exports.GenerateGraphNarrativeResponseSchema=u,exports.GenerateGraphResponseSchema=p,exports.GenerateGraphSuggestionsResponseSchema=d,exports.GraphyAiSdk=class{constructor(t){this.client=new n(t)}generateGraph(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const{storytellingOptions:o}=e,s=t.__rest(e,["storytellingOptions"]),n=yield this.client.fetch(`${y}/generate`,s,r,i),a=p.parse(n);return this.stripStorytelling(a,o)})}generateGraphStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){const{storytellingOptions:i}=e,o=t.__rest(e,["storytellingOptions"]),s=yield this.client.stream(`${y}/generate`,o,r);return this.wrapStreamWithStorytellingStripping(s,i)})}generateNarrative(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${y}/narrative`,e,r,i);return u.parse(t)})}generateNarrativeStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){return this.client.stream(`${y}/narrative`,e,r)})}generateSuggestions(e,r,i){return t.__awaiter(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${y}/suggestions`,e,r,i);return d.parse(t)})}generateSuggestionsStream(e,r){return t.__awaiter(this,void 0,void 0,function*(){return this.client.stream(`${y}/suggestions`,e,r)})}stripStorytelling(t,e){return e&&t.config.content?Object.assign(Object.assign({},t),{config:Object.assign(Object.assign({},t.config),{content:Object.assign(Object.assign(Object.assign(Object.assign({},t.config.content),e.excludeTitle&&{title:void 0}),e.excludeSubtitle&&{subtitle:void 0}),e.excludeCaption&&{caption:void 0})})}):t}wrapStreamWithStorytellingStripping(e,r){return t.__asyncGenerator(this,arguments,function*(){var i,s,n,a;try{for(var l,c=!0,g=t.__asyncValues(e);!(i=(l=yield t.__await(g.next())).done);c=!0){a=l.value,c=!1;const e=a;if(o(e)){const i=this.stripStorytelling(e.data,r);yield yield t.__await(Object.assign(Object.assign({},e),{data:i}))}else yield yield t.__await(e)}}catch(t){s={error:t}}finally{try{c||i||!(n=g.return)||(yield t.__await(n.call(g)))}finally{if(s)throw s.error}}})}},exports.GraphyApiError=r,exports.StorytellingEffortSchema=c,exports.SuggestionSchema=h,exports.isCompleteEvent=o,exports.isErrorEvent=s,exports.isGraphyApiError=t=>t instanceof r,exports.isProgressEvent=i;
package/dist/index.d.ts CHANGED
@@ -2,41 +2,101 @@ import * as _graphysdk_core_node from '@graphysdk/core/node';
2
2
  import { GraphConfig } from '@graphysdk/core/node';
3
3
  import { z } from 'zod';
4
4
 
5
+ /**
6
+ * A progress update emitted during an SSE stream.
7
+ * Indicates how far along the server-side operation has progressed.
8
+ */
5
9
  interface ProgressEvent {
10
+ /** Discriminant literal identifying this as a progress event. */
6
11
  type: 'progress';
12
+ /** Completion percentage from 0 to 100. */
7
13
  percentage: number;
14
+ /** Optional human-readable progress message. */
8
15
  message?: string;
16
+ /** Optional arbitrary metadata attached by the server. */
9
17
  metadata?: Record<string, JsonValue>;
10
18
  }
19
+ /**
20
+ * The final event emitted when an SSE stream completes successfully.
21
+ * Contains the full response payload.
22
+ */
11
23
  interface CompleteEvent<T> {
24
+ /** Discriminant literal identifying this as a completion event. */
12
25
  type: 'complete';
26
+ /** The response data from the completed operation. */
13
27
  data: T;
14
28
  }
29
+ /**
30
+ * An error event emitted when the server encounters a failure during an SSE stream.
31
+ */
15
32
  interface ErrorEvent {
33
+ /** Discriminant literal identifying this as an error event. */
16
34
  type: 'error';
35
+ /** Human-readable error description. */
17
36
  error: string;
37
+ /** Machine-readable error code from the API (e.g. `"RATE_LIMIT_ERROR"`). */
18
38
  code?: string;
39
+ /** Whether the consumer should retry the request. */
19
40
  retryable?: boolean;
20
41
  }
42
+ /**
43
+ * Discriminated union of all SSE event types emitted during streaming operations.
44
+ * Use the type guards {@link isProgressEvent}, {@link isCompleteEvent}, and
45
+ * {@link isErrorEvent} to narrow the event type.
46
+ */
21
47
  type SSEEvent<T> = ProgressEvent | CompleteEvent<T> | ErrorEvent;
48
+ /**
49
+ * Logger interface for SDK diagnostic output.
50
+ * Falls back to `console` methods when not provided in {@link ClientConfig}.
51
+ */
22
52
  interface Logger {
23
53
  log: (...args: Array<JsonValue | unknown>) => void;
24
54
  warn: (...args: Array<JsonValue | unknown>) => void;
25
55
  error: (...args: Array<JsonValue | unknown>) => void;
26
56
  debug: (...args: Array<JsonValue | unknown>) => void;
27
57
  }
58
+ /**
59
+ * Configuration for the automatic retry behavior on failed requests.
60
+ * Retries use exponential backoff: `delay * backoff^(attempt - 1)`.
61
+ */
28
62
  interface RetryConfig {
63
+ /** Maximum number of attempts (including the initial request). */
29
64
  attempts: number;
65
+ /** Base delay in milliseconds before the first retry. */
30
66
  delay: number;
67
+ /** Multiplier applied to the delay for each subsequent retry. */
31
68
  backoff: number;
32
69
  }
70
+ /**
71
+ * Configuration for initializing the SDK client.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const sdk = new GraphyAiSdk({
76
+ * apiKey: process.env.GRAPHY_API_KEY,
77
+ * baseUrl: 'https://agents.graphy.dev',
78
+ * });
79
+ * ```
80
+ */
33
81
  interface ClientConfig {
82
+ /** API key for authenticating requests. */
34
83
  apiKey: string;
84
+ /** Base URL of the Graphy Agents API (e.g. `"https://agents.graphy.dev"`). */
35
85
  baseUrl: string;
86
+ /**
87
+ * Request timeout in milliseconds.
88
+ * @defaultValue 60000
89
+ */
36
90
  timeout?: number;
91
+ /** Custom logger implementation. Falls back to `console` methods if not provided. */
37
92
  logger?: Logger;
93
+ /**
94
+ * Retry configuration for transient failures (5xx, 429, network errors).
95
+ * @defaultValue `{ attempts: 3, delay: 1000, backoff: 2 }`
96
+ */
38
97
  retryConfig?: RetryConfig;
39
98
  }
99
+ /** A JSON-compatible value. */
40
100
  type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
41
101
  interface JsonObject {
42
102
  [key: string]: JsonValue;
@@ -45,6 +105,108 @@ type JsonArray = JsonValue[];
45
105
 
46
106
  type ProgressHandler = (progress: ProgressEvent) => void;
47
107
 
108
+ /**
109
+ * Options for constructing a {@link GraphyApiError}.
110
+ */
111
+ interface GraphyApiErrorOptions {
112
+ /** HTTP status code from the server response (e.g. 401, 429, 500). */
113
+ status?: number;
114
+ /** Machine-readable error code from the API (e.g. `"RATE_LIMIT_ERROR"`, `"VALIDATION_ERROR"`). */
115
+ code?: string;
116
+ /** Whether this request is safe to retry. Defaults to `false`. */
117
+ retryable?: boolean;
118
+ }
119
+ /**
120
+ * Error thrown by the Graphy SDK when an API request fails.
121
+ *
122
+ * Covers HTTP errors, SSE stream errors, and network failures. Inspect
123
+ * {@link status}, {@link code}, and {@link retryable} to decide how to
124
+ * handle the failure programmatically.
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * try {
129
+ * await sdk.generateGraph({ config, userPrompt });
130
+ * } catch (error) {
131
+ * if (isGraphyApiError(error)) {
132
+ * console.error(`[${error.code}] ${error.message} (HTTP ${error.status})`);
133
+ * if (error.retryable) {
134
+ * // schedule retry
135
+ * }
136
+ * }
137
+ * }
138
+ * ```
139
+ */
140
+ declare class GraphyApiError extends Error {
141
+ /** HTTP status code, if the error originated from an HTTP response. */
142
+ readonly status: number | undefined;
143
+ /** Machine-readable error code from the API, if provided. */
144
+ readonly code: string | undefined;
145
+ /** Whether the SDK considers this error retryable (5xx, 429, network errors). */
146
+ readonly retryable: boolean;
147
+ /**
148
+ * @param message - Human-readable error description.
149
+ * @param options - Optional structured metadata about the error.
150
+ */
151
+ constructor(message: string, options?: GraphyApiErrorOptions);
152
+ }
153
+ /**
154
+ * Type guard that narrows an unknown value to {@link GraphyApiError}.
155
+ *
156
+ * @param error - The value to check.
157
+ * @returns `true` if `error` is an instance of `GraphyApiError`.
158
+ */
159
+ declare const isGraphyApiError: (error: unknown) => error is GraphyApiError;
160
+
161
+ /**
162
+ * Narrows an SSE event to a {@link ProgressEvent}.
163
+ *
164
+ * @param event - The SSE event to check.
165
+ * @returns `true` if the event is a progress event containing percentage and optional message.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * for await (const event of stream) {
170
+ * if (isProgressEvent(event)) {
171
+ * updateProgressBar(event.percentage);
172
+ * }
173
+ * }
174
+ * ```
175
+ */
176
+ declare const isProgressEvent: <T>(event: SSEEvent<T>) => event is ProgressEvent;
177
+ /**
178
+ * Narrows an SSE event to a {@link CompleteEvent} containing the final response data.
179
+ *
180
+ * @param event - The SSE event to check.
181
+ * @returns `true` if the event is a complete event.
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * for await (const event of stream) {
186
+ * if (isCompleteEvent(event)) {
187
+ * applyConfig(event.data.config);
188
+ * }
189
+ * }
190
+ * ```
191
+ */
192
+ declare const isCompleteEvent: <T>(event: SSEEvent<T>) => event is CompleteEvent<T>;
193
+ /**
194
+ * Narrows an SSE event to an {@link ErrorEvent}.
195
+ *
196
+ * @param event - The SSE event to check.
197
+ * @returns `true` if the event is an error event containing error details.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * for await (const event of stream) {
202
+ * if (isErrorEvent(event)) {
203
+ * console.error(`[${event.code}] ${event.error}`);
204
+ * }
205
+ * }
206
+ * ```
207
+ */
208
+ declare const isErrorEvent: <T>(event: SSEEvent<T>) => event is ErrorEvent;
209
+
48
210
  declare const StorytellingEffortSchema: z.ZodEnum<{
49
211
  none: "none";
50
212
  low: "low";
@@ -153,7 +315,7 @@ declare const GenerateGraphSuggestionsResponseSchema: z.ZodObject<{
153
315
  description: z.ZodNullable<z.ZodString>;
154
316
  }, z.core.$strip>;
155
317
  type GenerateGraphSuggestionsResponse = z.infer<typeof GenerateGraphSuggestionsResponseSchema>;
156
- interface NarrativeOptions {
318
+ interface StorytellingOptions {
157
319
  excludeTitle?: boolean;
158
320
  excludeSubtitle?: boolean;
159
321
  excludeCaption?: boolean;
@@ -162,65 +324,111 @@ type GenerateGraphParams = {
162
324
  config: GraphConfig;
163
325
  userPrompt: string;
164
326
  metadata?: Metadata;
165
- narrativeOptions?: NarrativeOptions;
327
+ storytellingOptions?: StorytellingOptions;
166
328
  };
167
- declare const ChartNarrativeSchema: z.ZodObject<{
168
- title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
169
- subtitle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
170
- caption: z.ZodOptional<z.ZodNullable<z.ZodString>>;
171
- }, z.core.$strip>;
172
- type ChartNarrative = z.infer<typeof ChartNarrativeSchema>;
173
329
  declare const GenerateGraphResponseSchema: z.ZodObject<{
174
330
  config: z.ZodType<GraphConfig, unknown, z.core.$ZodTypeInternals<GraphConfig, unknown>>;
175
331
  response: z.ZodObject<{
176
332
  message: z.ZodString;
177
333
  steps: z.ZodOptional<z.ZodArray<z.ZodString>>;
178
334
  }, z.core.$strip>;
179
- narrative: z.ZodOptional<z.ZodNullable<z.ZodObject<{
180
- title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
181
- subtitle: z.ZodOptional<z.ZodNullable<z.ZodString>>;
182
- caption: z.ZodOptional<z.ZodNullable<z.ZodString>>;
183
- }, z.core.$strip>>>;
184
335
  }, z.core.$strip>;
185
336
  type GenerateGraphResponse = z.infer<typeof GenerateGraphResponseSchema>;
186
337
 
338
+ /**
339
+ * Client SDK for the Graphy AI Agents API.
340
+ *
341
+ * Provides methods for AI-powered chart generation, narrative text creation,
342
+ * and prompt suggestions. Each method has a request-response variant and a
343
+ * streaming variant returning an `AsyncIterableIterator` of SSE events.
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * const sdk = new GraphyAiSdk({
348
+ * apiKey: process.env.GRAPHY_API_KEY,
349
+ * baseUrl: 'https://agents.graphy.dev',
350
+ * });
351
+ *
352
+ * const result = await sdk.generateGraph({
353
+ * config: existingConfig,
354
+ * userPrompt: 'Add a trend line',
355
+ * });
356
+ * ```
357
+ */
187
358
  declare class GraphyAiSdk {
188
359
  private client;
360
+ /**
361
+ * @param config - SDK configuration including API key and base URL.
362
+ * @throws {Error} If `apiKey` is empty or `baseUrl` is invalid.
363
+ */
189
364
  constructor(config: ClientConfig);
365
+ /**
366
+ * Generates a chart configuration from a natural language prompt.
367
+ *
368
+ * @param data - Generation parameters including the current config and user prompt.
369
+ * @param onProgress - Optional callback invoked with progress updates during generation.
370
+ * @param signal - Optional `AbortSignal` to cancel the request.
371
+ * @returns The generated chart configuration and agent response message.
372
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
373
+ */
190
374
  generateGraph(data: GenerateGraphParams, onProgress?: ProgressHandler, signal?: AbortSignal): Promise<{
191
375
  config: _graphysdk_core_node.GraphConfig;
192
376
  response: {
193
377
  message: string;
194
378
  steps?: string[] | undefined;
195
379
  };
196
- narrative?: {
197
- title?: string | null | undefined;
198
- subtitle?: string | null | undefined;
199
- caption?: string | null | undefined;
200
- } | null | undefined;
201
380
  }>;
381
+ /**
382
+ * Streams chart generation events via SSE.
383
+ *
384
+ * @param data - Generation parameters including the current config and user prompt.
385
+ * @param signal - Optional `AbortSignal` to cancel the request.
386
+ * @returns An async iterator yielding {@link SSEEvent} objects.
387
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
388
+ */
202
389
  generateGraphStream(data: GenerateGraphParams, signal?: AbortSignal): Promise<AsyncIterableIterator<SSEEvent<{
203
390
  config: _graphysdk_core_node.GraphConfig;
204
391
  response: {
205
392
  message: string;
206
393
  steps?: string[] | undefined;
207
394
  };
208
- narrative?: {
209
- title?: string | null | undefined;
210
- subtitle?: string | null | undefined;
211
- caption?: string | null | undefined;
212
- } | null | undefined;
213
395
  }>>>;
396
+ /**
397
+ * Generates narrative text (title, subtitle, caption) for a chart.
398
+ *
399
+ * @param data - Parameters including the chart config and a descriptive prompt.
400
+ * @param onProgress - Optional callback invoked with progress updates.
401
+ * @param signal - Optional `AbortSignal` to cancel the request.
402
+ * @returns The generated narrative containing title, subtitle, and optional caption.
403
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
404
+ */
214
405
  generateNarrative(data: GenerateGraphNarrativeParams, onProgress?: ProgressHandler, signal?: AbortSignal): Promise<{
215
406
  title: string;
216
407
  subtitle: string;
217
408
  caption: string | null;
218
409
  }>;
410
+ /**
411
+ * Streams narrative generation events via SSE.
412
+ *
413
+ * @param data - Parameters including the chart config and a descriptive prompt.
414
+ * @param signal - Optional `AbortSignal` to cancel the request.
415
+ * @returns An async iterator yielding {@link SSEEvent} objects.
416
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
417
+ */
219
418
  generateNarrativeStream(data: GenerateGraphNarrativeParams, signal?: AbortSignal): Promise<AsyncIterableIterator<SSEEvent<{
220
419
  title: string;
221
420
  subtitle: string;
222
421
  caption: string | null;
223
422
  }>>>;
423
+ /**
424
+ * Generates chart type and configuration suggestions from raw data.
425
+ *
426
+ * @param data - Parameters including the raw data string.
427
+ * @param onProgress - Optional callback invoked with progress updates.
428
+ * @param signal - Optional `AbortSignal` to cancel the request.
429
+ * @returns Suggested chart configurations and descriptions.
430
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
431
+ */
224
432
  generateSuggestions(data: GenerateGraphSuggestionsParams, onProgress?: ProgressHandler, signal?: AbortSignal): Promise<{
225
433
  config: _graphysdk_core_node.GraphConfig;
226
434
  suggestions: {
@@ -230,6 +438,14 @@ declare class GraphyAiSdk {
230
438
  }[];
231
439
  description: string | null;
232
440
  }>;
441
+ /**
442
+ * Streams suggestion generation events via SSE.
443
+ *
444
+ * @param data - Parameters including the raw data string.
445
+ * @param signal - Optional `AbortSignal` to cancel the request.
446
+ * @returns An async iterator yielding {@link SSEEvent} objects.
447
+ * @throws {GraphyApiError} When the API returns an error or the network request fails.
448
+ */
233
449
  generateSuggestionsStream(data: GenerateGraphSuggestionsParams, signal?: AbortSignal): Promise<AsyncIterableIterator<SSEEvent<{
234
450
  config: _graphysdk_core_node.GraphConfig;
235
451
  suggestions: {
@@ -239,13 +455,9 @@ declare class GraphyAiSdk {
239
455
  }[];
240
456
  description: string | null;
241
457
  }>>>;
242
- private stripNarrative;
243
- private wrapStreamWithNarrativeStripping;
244
- }
245
-
246
- declare class GraphyApiError extends Error {
247
- constructor(message: string);
458
+ private stripStorytelling;
459
+ private wrapStreamWithStorytellingStripping;
248
460
  }
249
461
 
250
- export { AiChartTypeEnum, ChartNarrativeSchema, GenerateGraphNarrativeResponseSchema, GenerateGraphResponseSchema, GenerateGraphSuggestionsResponseSchema, GraphyAiSdk, GraphyApiError, StorytellingEffortSchema, SuggestionSchema };
251
- export type { AiChartType, ChartNarrative, ClientConfig, CompleteEvent, ErrorEvent, GenerateGraphNarrativeParams, GenerateGraphNarrativeResponse, GenerateGraphParams, GenerateGraphResponse, GenerateGraphSuggestionsParams, GenerateGraphSuggestionsResponse, Logger, NarrativeOptions, ProgressEvent, ProgressHandler, RetryConfig, SSEEvent, StorytellingEffort, Suggestion };
462
+ export { AiChartTypeEnum, GenerateGraphNarrativeResponseSchema, GenerateGraphResponseSchema, GenerateGraphSuggestionsResponseSchema, GraphyAiSdk, GraphyApiError, StorytellingEffortSchema, SuggestionSchema, isCompleteEvent, isErrorEvent, isGraphyApiError, isProgressEvent };
463
+ export type { AiChartType, ClientConfig, CompleteEvent, ErrorEvent, GenerateGraphNarrativeParams, GenerateGraphNarrativeResponse, GenerateGraphParams, GenerateGraphResponse, GenerateGraphSuggestionsParams, GenerateGraphSuggestionsResponse, GraphyApiErrorOptions, Logger, ProgressEvent, ProgressHandler, RetryConfig, SSEEvent, StorytellingEffort, StorytellingOptions, Suggestion };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{__awaiter as t,__asyncValues as e,__asyncGenerator as r,__await as i,__rest as o}from"tslib";import{z as n}from"zod";class s extends Error{constructor(t){super(t),this.name="GraphyApiError"}}class a{constructor(t){if(this.tag="[GRAPHY]",!t.apiKey||0===t.apiKey.trim().length)throw new Error("apiKey is required and must not be empty");const e=new URL(t.baseUrl);if(!["http:","https:"].includes(e.protocol))throw new Error(`Invalid baseUrl protocol: ${e.protocol}. Only http(s) is allowed.`);this.apiKey=t.apiKey,this.baseUrl=e.origin+e.pathname.replace(/\/$/,""),this.timeout=t.timeout||6e4,this.retryConfig=t.retryConfig||{attempts:3,delay:1e3,backoff:2},this.logger=t.logger||{log:console.log,warn:console.warn,error:console.error,debug:console.debug}}static isProgressEvent(t){return"progress"===t.type}static isCompleteEvent(t){return"complete"===t.type}static isErrorEvent(t){return"error"===t.type}stream(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.makeRequest(e,r,i);return this.parseSSE(t)})}fetch(r,i,o,n){return t(this,void 0,void 0,function*(){var t,l,c,h;const u=Date.now();this.logger.debug(`${this.tag} Fetch: ${r}`);try{const f=yield this.makeRequest(r,i,n),y=f.headers.get("content-type");if(null==y?void 0:y.includes("text/event-stream")){try{for(var g,d=!0,p=e(this.parseSSE(f));!(t=(g=yield p.next()).done);d=!0){h=g.value,d=!1;const t=h;if(a.isProgressEvent(t)&&o&&o(t),a.isCompleteEvent(t))return t.data;if(a.isErrorEvent(t)){const e=Date.now()-u;throw this.logger.error(`${this.tag} Server error: ${r} ${e}ms`,t.error),new s(t.error)}}}catch(t){l={error:t}}finally{try{d||t||!(c=p.return)||(yield c.call(p))}finally{if(l)throw l.error}}const i=Date.now()-u;throw this.logger.error(`${this.tag} Stream incomplete: ${r} ${i}ms`),new s("Stream ended without completion")}return yield f.json()}catch(t){const e=Date.now()-u;if(this.logger.error(`${this.tag} Fetch failed: ${r} ${e}ms`,t),t instanceof s)throw t;throw t}finally{const t=Date.now()-u;this.logger.debug(`${this.tag} Fetch completed: ${r} ${t}ms`)}})}ping(){return t(this,void 0,void 0,function*(){const t=Date.now();try{return yield this.makeRequest("/health",void 0,void 0,this.retryConfig.attempts,"GET"),{ok:!0,latency:Date.now()-t}}catch(e){return{ok:!1,latency:Date.now()-t}}})}sleep(e){return t(this,void 0,void 0,function*(){return new Promise(t=>setTimeout(t,e))})}parseSSE(t){return r(this,arguments,function*(){if(!t.body)throw new s("Response body is null");const e=t.body.getReader(),r=new TextDecoder;let o="",n="",a="";try{for(;;){const{done:t,value:s}=yield i(e.read());if(t)break;o+=r.decode(s,{stream:!0});const l=o.split(/\r?\n/);o=l.pop()||"";for(const t of l)if(t.startsWith("event: "))n=t.slice(7).trim();else if(t.startsWith("data: "))a+=(a?"\n":"")+t.slice(6);else if(""===t.trim()&&a){try{const t=JSON.parse(a);let e;if("progress"===n){const r=t;e=Object.assign({type:"progress"},r)}else if("complete"===n)e={type:"complete",data:t};else{if("error"!==n){n="",a="";continue}{const r=t;e=Object.assign({type:"error"},r)}}if(yield yield i(e),"complete"===n||"error"===n)return yield i(void 0)}catch(t){this.logger.warn("Invalid SSE data format",a)}n="",a=""}}}finally{e.releaseLock()}})}makeRequest(e,r,i){return t(this,arguments,void 0,function*(t,e,r,i=1,o="POST"){if(!t.startsWith("/"))throw new s("Invalid endpoint: must start with /");const n=new URL(t,this.baseUrl);if(n.origin!==new URL(this.baseUrl).origin)throw new s("Endpoint resolved to unexpected origin");this.logger.debug(`${this.tag} Request ${i}/${this.retryConfig.attempts}: ${n}`);const a=new AbortController,l=setTimeout(()=>a.abort(),this.timeout),c=()=>a.abort();r&&r.addEventListener("abort",c);try{const l=yield fetch(n,Object.assign({method:o,headers:{"Content-Type":"application/json",Accept:"application/json, text/event-stream","Cache-Control":"no-cache",Authorization:`Bearer ${this.apiKey}`,"User-Agent":"Graphy-SDK/1.0"},signal:a.signal},"POST"===o&&{body:JSON.stringify(e)}));if(!l.ok){const n=l.status>=500||429===l.status;let a=`HTTP ${l.status}`;try{const t=yield l.json();if("object"==typeof t&&null!==t){const e=t;"string"==typeof e.message?a=e.message:"string"==typeof e.error&&(a=e.error)}}catch(t){}const c=new s(a);if(n&&i<this.retryConfig.attempts&&!(null==r?void 0:r.aborted)){const n=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,i-1);return this.logger.warn(`${this.tag} Retrying ${t} in ${n}ms (attempt ${i+1})`),yield this.sleep(n),this.makeRequest(t,e,r,i+1,o)}throw this.logger.error(`${this.tag} Request failed: ${t} (${l.status}) - ${a}`),c}return this.logger.debug(`${this.tag} Connected: ${t}`),l}catch(n){if(n instanceof s)throw n;if(n instanceof Error&&"AbortError"===n.name)throw this.logger.debug(`${this.tag} Aborted: ${t}`),n;if(i<this.retryConfig.attempts&&!(null==r?void 0:r.aborted)){const n=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,i-1);return this.logger.warn(`${this.tag} Network error, retrying ${t} in ${n}ms`),yield this.sleep(n),this.makeRequest(t,e,r,i+1,o)}throw this.logger.error(`${this.tag} Network error: ${t}`,n),new s("Network error")}finally{clearTimeout(l),r&&r.removeEventListener("abort",c)}})}}const l=n.enum(["EN_GB","EN_US"]),c=n.custom(t=>null!=t&&"object"==typeof t),h=n.enum(["none","low","medium","high"]);n.object({callId:n.string(),locale:l.optional(),storytellingEffort:h.optional().default("low")});const u=n.enum(["line","bar","groupedBar","stackedBar","100StackedBar","column","groupedColumn","stackedColumn","100StackedColumn","combo","pie","donut","funnel","heatmap","scatter","waterfall","table"]),g=n.object({dataPrepPrompt:n.string(),chartType:u,summary:n.string()}),d=n.object({title:n.string(),subtitle:n.string(),caption:n.string().nullable()}),p=n.object({config:c,suggestions:n.array(g),description:n.string().nullable()}),f=n.object({title:n.string().nullish(),subtitle:n.string().nullish(),caption:n.string().nullish()}),y=n.object({config:c,response:n.object({message:n.string(),steps:n.array(n.string()).optional()}),narrative:f.nullish()}),m="/api/v0";class v{constructor(t){this.client=new a(t)}generateGraph(e,r,i){return t(this,void 0,void 0,function*(){const{narrativeOptions:t}=e,n=o(e,["narrativeOptions"]),s=yield this.client.fetch(`${m}/generate`,n,r,i),a=y.parse(s);return this.stripNarrative(a,t)})}generateGraphStream(e,r){return t(this,void 0,void 0,function*(){const{narrativeOptions:t}=e,i=o(e,["narrativeOptions"]),n=yield this.client.stream(`${m}/generate`,i,r);return this.wrapStreamWithNarrativeStripping(n,t)})}generateNarrative(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${m}/narrative`,e,r,i);return d.parse(t)})}generateNarrativeStream(e,r){return t(this,void 0,void 0,function*(){return this.client.stream(`${m}/narrative`,e,r)})}generateSuggestions(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${m}/suggestions`,e,r,i);return p.parse(t)})}generateSuggestionsStream(e,r){return t(this,void 0,void 0,function*(){return this.client.stream(`${m}/suggestions`,e,r)})}stripNarrative(t,e){return e&&t.narrative?Object.assign(Object.assign({},t),{narrative:{title:e.excludeTitle?null:t.narrative.title,subtitle:e.excludeSubtitle?null:t.narrative.subtitle,caption:e.excludeCaption?null:t.narrative.caption}}):t}wrapStreamWithNarrativeStripping(t,o){return r(this,arguments,function*(){var r,n,s,l;try{for(var c,h=!0,u=e(t);!(r=(c=yield i(u.next())).done);h=!0){l=c.value,h=!1;const t=l;if(a.isCompleteEvent(t)){const e=this.stripNarrative(t.data,o);yield yield i(Object.assign(Object.assign({},t),{data:e}))}else yield yield i(t)}}catch(t){n={error:t}}finally{try{h||r||!(s=u.return)||(yield i(s.call(u)))}finally{if(n)throw n.error}}})}}export{u as AiChartTypeEnum,f as ChartNarrativeSchema,d as GenerateGraphNarrativeResponseSchema,y as GenerateGraphResponseSchema,p as GenerateGraphSuggestionsResponseSchema,v as GraphyAiSdk,s as GraphyApiError,h as StorytellingEffortSchema,g as SuggestionSchema};
1
+ import{__awaiter as t,__asyncValues as e,__asyncGenerator as r,__await as i,__rest as o}from"tslib";import{z as n}from"zod";class s extends Error{constructor(t,e){var r;super(t),Object.setPrototypeOf(this,new.target.prototype),this.name="GraphyApiError",this.status=null==e?void 0:e.status,this.code=null==e?void 0:e.code,this.retryable=null!==(r=null==e?void 0:e.retryable)&&void 0!==r&&r}}const a=t=>t instanceof s,l=t=>"progress"===t.type,c=t=>"complete"===t.type,g=t=>"error"===t.type;class h{constructor(t){if(this.tag="[GRAPHY]",!t.apiKey||0===t.apiKey.trim().length)throw new Error("apiKey is required and must not be empty");const e=new URL(t.baseUrl);if(!["http:","https:"].includes(e.protocol))throw new Error(`Invalid baseUrl protocol: ${e.protocol}. Only http(s) is allowed.`);this.apiKey=t.apiKey,this.baseUrl=e.origin+e.pathname.replace(/\/$/,""),this.timeout=t.timeout||6e4,this.retryConfig=t.retryConfig||{attempts:3,delay:1e3,backoff:2},this.logger=t.logger||{log:console.log,warn:console.warn,error:console.error,debug:console.debug}}static isProgressEvent(t){return l(t)}static isCompleteEvent(t){return c(t)}static isErrorEvent(t){return g(t)}stream(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.makeRequest(e,r,i);return this.parseSSE(t)})}fetch(r,i,o,n){return t(this,void 0,void 0,function*(){var t,a,h,d,u;const p=Date.now();this.logger.debug(`${this.tag} Fetch: ${r}`);try{const b=yield this.makeRequest(r,i,n),v=b.headers.get("content-type");if(null==v?void 0:v.includes("text/event-stream")){try{for(var y,f=!0,m=e(this.parseSSE(b));!(t=(y=yield m.next()).done);f=!0){d=y.value,f=!1;const t=d;if(l(t)&&o&&o(t),c(t))return t.data;if(g(t)){const e=Date.now()-p;throw this.logger.error(`${this.tag} Server error: ${r} ${e}ms`,t.error),new s(t.error,{code:t.code,retryable:null!==(u=t.retryable)&&void 0!==u&&u})}}}catch(t){a={error:t}}finally{try{f||t||!(h=m.return)||(yield h.call(m))}finally{if(a)throw a.error}}const i=Date.now()-p;throw this.logger.error(`${this.tag} Stream incomplete: ${r} ${i}ms`),new s("Stream ended without completion")}return yield b.json()}catch(t){const e=Date.now()-p;if(this.logger.error(`${this.tag} Fetch failed: ${r} ${e}ms`,t),t instanceof s)throw t;throw t}finally{const t=Date.now()-p;this.logger.debug(`${this.tag} Fetch completed: ${r} ${t}ms`)}})}ping(){return t(this,void 0,void 0,function*(){const t=Date.now();try{return yield this.makeRequest("/health",void 0,void 0,this.retryConfig.attempts,"GET"),{ok:!0,latency:Date.now()-t}}catch(e){return{ok:!1,latency:Date.now()-t}}})}sleep(e){return t(this,void 0,void 0,function*(){return new Promise(t=>setTimeout(t,e))})}parseSSE(t){return r(this,arguments,function*(){if(!t.body)throw new s("Response body is null");const e=t.body.getReader(),r=new TextDecoder;let o="",n="",a="";try{for(;;){const{done:t,value:s}=yield i(e.read());if(t)break;o+=r.decode(s,{stream:!0});const l=o.split(/\r?\n/);o=l.pop()||"";for(const t of l)if(t.startsWith("event: "))n=t.slice(7).trim();else if(t.startsWith("data: "))a+=(a?"\n":"")+t.slice(6);else if(""===t.trim()&&a){try{const t=JSON.parse(a);let e;if("progress"===n){const r=t;e=Object.assign({type:"progress"},r)}else if("complete"===n)e={type:"complete",data:t};else{if("error"!==n){n="",a="";continue}{const r=t;e=Object.assign({type:"error"},r)}}if(yield yield i(e),"complete"===n||"error"===n)return yield i(void 0)}catch(t){this.logger.warn("Invalid SSE data format",a)}n="",a=""}}}finally{e.releaseLock()}})}makeRequest(e,r,i){return t(this,arguments,void 0,function*(t,e,r,i=1,o="POST"){if(!t.startsWith("/"))throw new s("Invalid endpoint: must start with /");const n=new URL(t,this.baseUrl);if(n.origin!==new URL(this.baseUrl).origin)throw new s("Endpoint resolved to unexpected origin");this.logger.debug(`${this.tag} Request ${i}/${this.retryConfig.attempts}: ${n}`);const a=new AbortController,l=setTimeout(()=>a.abort(),this.timeout),c=()=>a.abort();r&&r.addEventListener("abort",c);try{const l=yield fetch(n,Object.assign({method:o,headers:{"Content-Type":"application/json",Accept:"application/json, text/event-stream","Cache-Control":"no-cache",Authorization:`Bearer ${this.apiKey}`,"User-Agent":"Graphy-SDK/1.0"},signal:a.signal},"POST"===o&&{body:JSON.stringify(e)}));if(!l.ok){const n=l.status>=500||429===l.status;let a,c=`HTTP ${l.status}`;try{const t=yield l.json();if("object"==typeof t&&null!==t){const e=t;"string"==typeof e.message?c=e.message:"string"==typeof e.error&&(c=e.error),"string"==typeof e.code&&(a=e.code)}}catch(t){}const g=new s(c,{status:l.status,code:a,retryable:n});if(n&&i<this.retryConfig.attempts&&!(null==r?void 0:r.aborted)){const n=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,i-1);return this.logger.warn(`${this.tag} Retrying ${t} in ${n}ms (attempt ${i+1})`),yield this.sleep(n),this.makeRequest(t,e,r,i+1,o)}throw this.logger.error(`${this.tag} Request failed: ${t} (${l.status}) - ${c}`),g}return this.logger.debug(`${this.tag} Connected: ${t}`),l}catch(n){if(n instanceof s)throw n;if(n instanceof Error&&"AbortError"===n.name)throw this.logger.debug(`${this.tag} Aborted: ${t}`),n;if(i<this.retryConfig.attempts&&!(null==r?void 0:r.aborted)){const n=this.retryConfig.delay*Math.pow(this.retryConfig.backoff,i-1);return this.logger.warn(`${this.tag} Network error, retrying ${t} in ${n}ms`),yield this.sleep(n),this.makeRequest(t,e,r,i+1,o)}throw this.logger.error(`${this.tag} Network error: ${t}`,n),new s("Network error",{retryable:!0})}finally{clearTimeout(l),r&&r.removeEventListener("abort",c)}})}}const d=n.enum(["EN_GB","EN_US"]),u=n.custom(t=>null!=t&&"object"==typeof t),p=n.enum(["none","low","medium","high"]);n.object({callId:n.string(),locale:d.optional(),storytellingEffort:p.optional().default("low")});const y=n.enum(["line","bar","groupedBar","stackedBar","100StackedBar","column","groupedColumn","stackedColumn","100StackedColumn","combo","pie","donut","funnel","heatmap","scatter","waterfall","table"]),f=n.object({dataPrepPrompt:n.string(),chartType:y,summary:n.string()}),m=n.object({title:n.string(),subtitle:n.string(),caption:n.string().nullable()}),b=n.object({config:u,suggestions:n.array(f),description:n.string().nullable()}),v=n.object({config:u,response:n.object({message:n.string(),steps:n.array(n.string()).optional()})}),w="/api/v0";class ${constructor(t){this.client=new h(t)}generateGraph(e,r,i){return t(this,void 0,void 0,function*(){const{storytellingOptions:t}=e,n=o(e,["storytellingOptions"]),s=yield this.client.fetch(`${w}/generate`,n,r,i),a=v.parse(s);return this.stripStorytelling(a,t)})}generateGraphStream(e,r){return t(this,void 0,void 0,function*(){const{storytellingOptions:t}=e,i=o(e,["storytellingOptions"]),n=yield this.client.stream(`${w}/generate`,i,r);return this.wrapStreamWithStorytellingStripping(n,t)})}generateNarrative(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${w}/narrative`,e,r,i);return m.parse(t)})}generateNarrativeStream(e,r){return t(this,void 0,void 0,function*(){return this.client.stream(`${w}/narrative`,e,r)})}generateSuggestions(e,r,i){return t(this,void 0,void 0,function*(){const t=yield this.client.fetch(`${w}/suggestions`,e,r,i);return b.parse(t)})}generateSuggestionsStream(e,r){return t(this,void 0,void 0,function*(){return this.client.stream(`${w}/suggestions`,e,r)})}stripStorytelling(t,e){return e&&t.config.content?Object.assign(Object.assign({},t),{config:Object.assign(Object.assign({},t.config),{content:Object.assign(Object.assign(Object.assign(Object.assign({},t.config.content),e.excludeTitle&&{title:void 0}),e.excludeSubtitle&&{subtitle:void 0}),e.excludeCaption&&{caption:void 0})})}):t}wrapStreamWithStorytellingStripping(t,o){return r(this,arguments,function*(){var r,n,s,a;try{for(var l,g=!0,h=e(t);!(r=(l=yield i(h.next())).done);g=!0){a=l.value,g=!1;const t=a;if(c(t)){const e=this.stripStorytelling(t.data,o);yield yield i(Object.assign(Object.assign({},t),{data:e}))}else yield yield i(t)}}catch(t){n={error:t}}finally{try{g||r||!(s=h.return)||(yield i(s.call(h)))}finally{if(n)throw n.error}}})}}export{y as AiChartTypeEnum,m as GenerateGraphNarrativeResponseSchema,v as GenerateGraphResponseSchema,b as GenerateGraphSuggestionsResponseSchema,$ as GraphyAiSdk,s as GraphyApiError,p as StorytellingEffortSchema,f as SuggestionSchema,c as isCompleteEvent,g as isErrorEvent,a as isGraphyApiError,l as isProgressEvent};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@graphysdk/agents-sdk",
3
3
  "author": "Graphy",
4
- "version": "1.2.0-beta.1773268716508",
4
+ "version": "1.2.0-beta.1773662483280",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "files": [
@@ -18,14 +18,14 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "zod": "^4.3.6",
21
- "@graphysdk/core": "1.2.0-beta.1773268716508"
21
+ "@graphysdk/core": "1.2.0-beta.1773662483280"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@rollup/plugin-commonjs": "^28.0.6",
25
25
  "@rollup/plugin-node-resolve": "^16.0.1",
26
26
  "@rollup/plugin-terser": "^0.4.4",
27
27
  "@rollup/plugin-typescript": "^12.1.4",
28
- "lodash-es": "^4.17.21",
28
+ "lodash-es": "^4.17.23",
29
29
  "rollup": "^4.59.0",
30
30
  "rollup-plugin-clear": "^2.0.7",
31
31
  "rollup-plugin-copy": "^3.5.0",
@@ -37,12 +37,21 @@
37
37
  "@graphytools/typescript-config": "0.0.1",
38
38
  "@graphytools/vitest-config": "1.0.0"
39
39
  },
40
+ "lint-staged": {
41
+ "*.{ts,tsx,js,jsx,json,css,md}": [
42
+ "prettier --write"
43
+ ],
44
+ "*.{ts,tsx}": [
45
+ "eslint --max-warnings=0 --fix"
46
+ ]
47
+ },
40
48
  "scripts": {
41
49
  "build": "rollup -c --bundleConfigAsCjs",
42
50
  "build:dev": "rollup -c --bundleConfigAsCjs --watch",
43
51
  "test": "vitest run",
44
52
  "test:watch": "TZ=utc vitest",
45
53
  "lint": "eslint . --max-warnings 0",
54
+ "lint:fix": "eslint . --fix",
46
55
  "format": "prettier --write .",
47
56
  "format:check": "prettier --check .",
48
57
  "typecheck": "tsc --noEmit",