graphlit-client 1.0.20250610009 → 1.0.20250611001

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/client.d.ts CHANGED
@@ -1,41 +1,7 @@
1
- import { ApolloClient, NormalizedCacheObject } from "@apollo/client/core";
1
+ import { ApolloClient, NormalizedCacheObject } from "@apollo/client";
2
2
  import * as Types from "./generated/graphql-types.js";
3
3
  import { AgentOptions, AgentResult, StreamAgentOptions, ToolHandler } from "./types/agent.js";
4
4
  import { AgentStreamEvent } from "./types/ui-events.js";
5
- export type StreamEvent = {
6
- type: "start";
7
- conversationId: string;
8
- } | {
9
- type: "token";
10
- token: string;
11
- } | {
12
- type: "message";
13
- message: string;
14
- } | {
15
- type: "tool_call_start";
16
- toolCall: {
17
- id: string;
18
- name: string;
19
- };
20
- } | {
21
- type: "tool_call_delta";
22
- toolCallId: string;
23
- argumentDelta: string;
24
- } | {
25
- type: "tool_call_complete";
26
- toolCall: {
27
- id: string;
28
- name: string;
29
- arguments: string;
30
- };
31
- } | {
32
- type: "complete";
33
- messageId?: string;
34
- conversationId?: string;
35
- } | {
36
- type: "error";
37
- error: string;
38
- };
39
5
  export type { AgentOptions, AgentResult, StreamAgentOptions, ToolCallResult, UsageInfo, AgentError, } from "./types/agent.js";
40
6
  export type { AgentStreamEvent } from "./types/ui-events.js";
41
7
  declare class Graphlit {
@@ -376,7 +342,7 @@ declare class Graphlit {
376
342
  * @param options - Stream agent options
377
343
  * @throws Error if streaming is not supported
378
344
  */
379
- streamAgent(prompt: string, onEvent: (event: StreamEvent | AgentStreamEvent) => void, conversationId?: string, specification?: Types.EntityReferenceInput, tools?: Types.ToolDefinitionInput[], toolHandlers?: Record<string, ToolHandler>, options?: StreamAgentOptions, mimeType?: string, data?: string, // base64 encoded
345
+ streamAgent(prompt: string, onEvent: (event: AgentStreamEvent) => void, conversationId?: string, specification?: Types.EntityReferenceInput, tools?: Types.ToolDefinitionInput[], toolHandlers?: Record<string, ToolHandler>, options?: StreamAgentOptions, mimeType?: string, data?: string, // base64 encoded
380
346
  correlationId?: string): Promise<void>;
381
347
  /**
382
348
  * Execute the streaming agent workflow with tool calling loop
@@ -417,4 +383,3 @@ declare class Graphlit {
417
383
  }
418
384
  export { Graphlit };
419
385
  export * as Types from "./generated/graphql-types.js";
420
- export { StreamEventAggregator, AggregatedEvent, formatSSEEvent, createSSEStream, wrapToolHandlers, enhanceToolCalls, ConversationMetrics, ToolResultEmitter, ServerMapping, } from "./stream-helpers.js";
package/dist/client.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as jwt from "jsonwebtoken";
2
- import { ApolloClient, InMemoryCache, createHttpLink, ApolloLink, ApolloError, } from "@apollo/client/core";
2
+ import { ApolloClient, InMemoryCache, createHttpLink, ApolloLink, ApolloError, } from "@apollo/client";
3
3
  import * as Types from "./generated/graphql-types.js";
4
4
  import * as Documents from "./generated/graphql-documents.js";
5
5
  import * as dotenv from "dotenv";
6
- import { getServiceType, } from "./model-mapping.js";
6
+ import { getServiceType } from "./model-mapping.js";
7
7
  import { UIEventAdapter } from "./streaming/ui-event-adapter.js";
8
8
  import { formatMessagesForOpenAI, formatMessagesForAnthropic, formatMessagesForGoogle, } from "./streaming/llm-formatters.js";
9
9
  import { streamWithOpenAI, streamWithAnthropic, streamWithGoogle, } from "./streaming/providers.js";
@@ -1724,7 +1724,8 @@ class Graphlit {
1724
1724
  // Check for common truncation patterns
1725
1725
  const lastChars = toolCall.arguments.slice(-20);
1726
1726
  let isTruncated = false;
1727
- if (!toolCall.arguments.includes('}') || !lastChars.includes('}')) {
1727
+ if (!toolCall.arguments.includes("}") ||
1728
+ !lastChars.includes("}")) {
1728
1729
  console.error(`Possible truncation detected - arguments don't end with '}': ...${lastChars}`);
1729
1730
  isTruncated = true;
1730
1731
  }
@@ -1737,7 +1738,8 @@ class Graphlit {
1737
1738
  const missingBraces = openBraces - closeBraces;
1738
1739
  if (missingBraces > 0) {
1739
1740
  // Check if we're mid-value (ends with number or boolean)
1740
- if (fixedJson.match(/:\s*\d+$/) || fixedJson.match(/:\s*(true|false)$/)) {
1741
+ if (fixedJson.match(/:\s*\d+$/) ||
1742
+ fixedJson.match(/:\s*(true|false)$/)) {
1741
1743
  // Complete the current property and close
1742
1744
  fixedJson += ', "content": ""'; // Add empty content field
1743
1745
  }
@@ -1747,7 +1749,8 @@ class Graphlit {
1747
1749
  fixedJson += ', "content": ""';
1748
1750
  }
1749
1751
  // Add missing closing quote if the string ends with an unfinished string
1750
- else if (fixedJson.endsWith('"') === false && fixedJson.includes('"')) {
1752
+ else if (fixedJson.endsWith('"') === false &&
1753
+ fixedJson.includes('"')) {
1751
1754
  const lastQuoteIndex = fixedJson.lastIndexOf('"');
1752
1755
  const afterLastQuote = fixedJson.slice(lastQuoteIndex + 1);
1753
1756
  if (!afterLastQuote.includes('"')) {
@@ -1755,7 +1758,7 @@ class Graphlit {
1755
1758
  }
1756
1759
  }
1757
1760
  // Add missing closing braces
1758
- fixedJson += '}'.repeat(missingBraces);
1761
+ fixedJson += "}".repeat(missingBraces);
1759
1762
  console.log(`Attempting to fix truncated JSON by adding ${missingBraces} closing brace(s):`);
1760
1763
  console.log(fixedJson);
1761
1764
  try {
@@ -1771,7 +1774,7 @@ class Graphlit {
1771
1774
  // If we couldn't parse or fix the JSON, log details and continue
1772
1775
  if (!args) {
1773
1776
  // Log position mentioned in error if available
1774
- const errorMsg = parseError instanceof Error ? parseError.message : '';
1777
+ const errorMsg = parseError instanceof Error ? parseError.message : "";
1775
1778
  const posMatch = errorMsg.match(/position (\d+)/);
1776
1779
  if (posMatch) {
1777
1780
  const pos = parseInt(posMatch[1]);
@@ -1781,7 +1784,7 @@ class Graphlit {
1781
1784
  // Update UI with error - use StreamEvent error type
1782
1785
  uiAdapter.handleEvent({
1783
1786
  type: "error",
1784
- error: `Tool ${toolCall.name} failed: Invalid JSON arguments: ${parseError instanceof Error ? parseError.message : 'Unknown error'}`,
1787
+ error: `Tool ${toolCall.name} failed: Invalid JSON arguments: ${parseError instanceof Error ? parseError.message : "Unknown error"}`,
1785
1788
  });
1786
1789
  continue;
1787
1790
  }
@@ -2113,5 +2116,3 @@ class Graphlit {
2113
2116
  }
2114
2117
  export { Graphlit };
2115
2118
  export * as Types from "./generated/graphql-types.js";
2116
- // Export streaming helpers
2117
- export { StreamEventAggregator, formatSSEEvent, createSSEStream, wrapToolHandlers, enhanceToolCalls, ConversationMetrics, } from "./stream-helpers.js";
@@ -1,6 +1,6 @@
1
1
  import { ConversationToolCall, Specification, ToolDefinitionInput } from "../generated/graphql-types.js";
2
- import { StreamEvent } from "../client.js";
3
2
  import { OpenAIMessage, AnthropicMessage, GoogleMessage } from "./llm-formatters.js";
3
+ import { StreamEvent } from "../types/internal.js";
4
4
  /**
5
5
  * Stream with OpenAI SDK
6
6
  */
@@ -1,5 +1,5 @@
1
1
  import { AgentStreamEvent } from "../types/ui-events.js";
2
- import { StreamEvent } from "../client.js";
2
+ import { StreamEvent } from "../types/internal.js";
3
3
  import { ChunkingStrategy } from "./chunk-buffer.js";
4
4
  /**
5
5
  * Adapter that transforms low-level streaming events into high-level UI events
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Internal types used by the streaming implementation
3
+ * These are not exported to consumers of the library
4
+ */
5
+ /**
6
+ * Low-level streaming events used internally by providers
7
+ * These get transformed into AgentStreamEvent by UIEventAdapter
8
+ */
9
+ export type StreamEvent = {
10
+ type: "start";
11
+ conversationId: string;
12
+ } | {
13
+ type: "token";
14
+ token: string;
15
+ } | {
16
+ type: "message";
17
+ message: string;
18
+ } | {
19
+ type: "tool_call_start";
20
+ toolCall: {
21
+ id: string;
22
+ name: string;
23
+ };
24
+ } | {
25
+ type: "tool_call_delta";
26
+ toolCallId: string;
27
+ argumentDelta: string;
28
+ } | {
29
+ type: "tool_call_complete";
30
+ toolCall: {
31
+ id: string;
32
+ name: string;
33
+ arguments: string;
34
+ };
35
+ } | {
36
+ type: "complete";
37
+ messageId?: string;
38
+ conversationId?: string;
39
+ } | {
40
+ type: "error";
41
+ error: string;
42
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Internal types used by the streaming implementation
3
+ * These are not exported to consumers of the library
4
+ */
5
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20250610009",
3
+ "version": "1.0.20250611001",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "main": "dist/client.js",
6
6
  "types": "dist/client.d.ts",
@@ -1,106 +0,0 @@
1
- import { StreamEvent } from "./client.js";
2
- import { ConversationRoleTypes } from "./generated/graphql-types.js";
3
- export declare class StreamEventAggregator {
4
- private conversationId;
5
- private messageBuffer;
6
- private toolCallsBuffer;
7
- private isFirstAssistantMessage;
8
- private hasReceivedToolCalls;
9
- private tokenBuffer;
10
- /**
11
- * Process a stream event and return any complete messages ready for the UI
12
- */
13
- processEvent(event: StreamEvent): AggregatedEvent | null;
14
- /**
15
- * Reset the aggregator for a new conversation
16
- */
17
- reset(): void;
18
- /**
19
- * Get current state (useful for debugging)
20
- */
21
- getState(): {
22
- conversationId: string;
23
- messageBuffer: string;
24
- toolCallsCount: number;
25
- hasReceivedToolCalls: boolean;
26
- isFirstAssistantMessage: boolean;
27
- tokenCount: number;
28
- };
29
- }
30
- /**
31
- * Aggregated event types that are ready for UI consumption
32
- */
33
- export type AggregatedEvent = {
34
- type: "conversationStarted";
35
- conversationId: string;
36
- } | {
37
- type: "token";
38
- token: string;
39
- accumulated: string;
40
- } | {
41
- type: "assistantMessage";
42
- message: {
43
- message?: string | null;
44
- role?: ConversationRoleTypes | null;
45
- toolCalls?: any[];
46
- };
47
- isFinal: boolean;
48
- conversationId?: string;
49
- } | {
50
- type: "streamComplete";
51
- conversationId?: string;
52
- } | {
53
- type: "error";
54
- error: string;
55
- };
56
- /**
57
- * Helper to create an SSE response with proper formatting
58
- */
59
- export declare function formatSSEEvent(data: any, eventName?: string): string;
60
- /**
61
- * Helper to create a TransformStream for SSE with built-in ping support
62
- */
63
- export declare function createSSEStream(options?: {
64
- pingInterval?: number;
65
- }): {
66
- readable: ReadableStream<any>;
67
- sendEvent: (data: any, eventName?: string) => Promise<void>;
68
- close: () => Promise<void>;
69
- writer: WritableStreamDefaultWriter<any>;
70
- };
71
- /**
72
- * Helper to wrap tool handlers with result emission
73
- */
74
- export interface ToolResultEmitter {
75
- (toolCallId: string, result: any, status: "complete" | "error" | "blocked", duration: number): void;
76
- }
77
- export declare function wrapToolHandlers(handlers: Record<string, (args: any) => Promise<any>>, emitResult: ToolResultEmitter): Record<string, (args: any) => Promise<any>>;
78
- /**
79
- * Helper to enhance tool calls with server information
80
- */
81
- export interface ServerMapping {
82
- toolName: string;
83
- serverName: string;
84
- serverId: string;
85
- }
86
- export declare function enhanceToolCalls(toolCalls: any[], serverMappings: ServerMapping[]): any[];
87
- /**
88
- * Helper to track conversation metrics
89
- */
90
- export declare class ConversationMetrics {
91
- private startTime;
92
- private tokenCount;
93
- private toolCallCount;
94
- private errorCount;
95
- recordToken(): void;
96
- recordToolCall(): void;
97
- recordError(): void;
98
- getMetrics(): {
99
- duration: number;
100
- tokenCount: number;
101
- toolCallCount: number;
102
- errorCount: number;
103
- tokensPerSecond: number;
104
- };
105
- reset(): void;
106
- }
@@ -1,237 +0,0 @@
1
- import { ConversationRoleTypes, } from "./generated/graphql-types.js";
2
- export class StreamEventAggregator {
3
- conversationId = "";
4
- messageBuffer = "";
5
- toolCallsBuffer = new Map();
6
- isFirstAssistantMessage = true;
7
- hasReceivedToolCalls = false;
8
- tokenBuffer = [];
9
- /**
10
- * Process a stream event and return any complete messages ready for the UI
11
- */
12
- processEvent(event) {
13
- switch (event.type) {
14
- case "start":
15
- this.conversationId = event.conversationId;
16
- return {
17
- type: "conversationStarted",
18
- conversationId: event.conversationId,
19
- };
20
- case "token":
21
- this.messageBuffer += event.token;
22
- this.tokenBuffer.push(event.token);
23
- return {
24
- type: "token",
25
- token: event.token,
26
- accumulated: this.messageBuffer,
27
- };
28
- case "message":
29
- // SDK provides accumulated message - we can use this instead of our buffer
30
- this.messageBuffer = event.message;
31
- return null; // Don't emit, wait for complete event
32
- case "tool_call_start":
33
- this.hasReceivedToolCalls = true;
34
- this.toolCallsBuffer.set(event.toolCall.id, {
35
- id: event.toolCall.id,
36
- name: event.toolCall.name,
37
- argumentsBuffer: "",
38
- isComplete: false,
39
- startTime: Date.now(),
40
- });
41
- return null; // Buffer until complete
42
- case "tool_call_delta":
43
- const toolCall = this.toolCallsBuffer.get(event.toolCallId);
44
- if (toolCall) {
45
- toolCall.argumentsBuffer += event.argumentDelta;
46
- }
47
- return null; // Buffer until complete
48
- case "tool_call_complete":
49
- const completeToolCall = this.toolCallsBuffer.get(event.toolCall.id);
50
- if (completeToolCall) {
51
- completeToolCall.argumentsBuffer = event.toolCall.arguments;
52
- completeToolCall.isComplete = true;
53
- }
54
- // Check if all tool calls are complete
55
- const allComplete = Array.from(this.toolCallsBuffer.values()).every((tc) => tc.isComplete);
56
- if (allComplete &&
57
- this.hasReceivedToolCalls &&
58
- this.isFirstAssistantMessage) {
59
- // Emit complete assistant message with all tool calls
60
- const toolCalls = Array.from(this.toolCallsBuffer.values()).map((tc) => ({
61
- id: tc.id,
62
- name: tc.name,
63
- arguments: tc.argumentsBuffer,
64
- status: "pending",
65
- }));
66
- this.isFirstAssistantMessage = false;
67
- return {
68
- type: "assistantMessage",
69
- message: {
70
- message: this.messageBuffer,
71
- role: ConversationRoleTypes.Assistant,
72
- toolCalls,
73
- },
74
- isFinal: false,
75
- };
76
- }
77
- return null;
78
- case "complete":
79
- // If we haven't sent a message yet (no tool calls), send it now
80
- if (this.isFirstAssistantMessage && !this.hasReceivedToolCalls) {
81
- return {
82
- type: "assistantMessage",
83
- message: {
84
- message: this.messageBuffer,
85
- role: ConversationRoleTypes.Assistant,
86
- },
87
- isFinal: true,
88
- conversationId: event.conversationId,
89
- };
90
- }
91
- return { type: "streamComplete", conversationId: event.conversationId };
92
- case "error":
93
- return { type: "error", error: event.error };
94
- default:
95
- return null;
96
- }
97
- }
98
- /**
99
- * Reset the aggregator for a new conversation
100
- */
101
- reset() {
102
- this.conversationId = "";
103
- this.messageBuffer = "";
104
- this.toolCallsBuffer.clear();
105
- this.isFirstAssistantMessage = true;
106
- this.hasReceivedToolCalls = false;
107
- this.tokenBuffer = [];
108
- }
109
- /**
110
- * Get current state (useful for debugging)
111
- */
112
- getState() {
113
- return {
114
- conversationId: this.conversationId,
115
- messageBuffer: this.messageBuffer,
116
- toolCallsCount: this.toolCallsBuffer.size,
117
- hasReceivedToolCalls: this.hasReceivedToolCalls,
118
- isFirstAssistantMessage: this.isFirstAssistantMessage,
119
- tokenCount: this.tokenBuffer.length,
120
- };
121
- }
122
- }
123
- /**
124
- * Helper to create an SSE response with proper formatting
125
- */
126
- export function formatSSEEvent(data, eventName = "message") {
127
- if (typeof data === "string") {
128
- return `event: ${eventName}\ndata: ${data}\n\n`;
129
- }
130
- return `event: ${eventName}\ndata: ${JSON.stringify(data)}\n\n`;
131
- }
132
- /**
133
- * Helper to create a TransformStream for SSE with built-in ping support
134
- */
135
- export function createSSEStream(options) {
136
- const encoder = new TextEncoder();
137
- const { readable, writable } = new TransformStream();
138
- const writer = writable.getWriter();
139
- let pingInterval = null;
140
- if (options?.pingInterval) {
141
- pingInterval = globalThis.setInterval(() => {
142
- writer.write(encoder.encode(":\n\n")).catch(() => {
143
- // Ignore errors on ping
144
- });
145
- }, options.pingInterval);
146
- }
147
- const sendEvent = (data, eventName = "message") => {
148
- const formatted = formatSSEEvent(data, eventName);
149
- return writer.write(encoder.encode(formatted));
150
- };
151
- const close = async () => {
152
- if (pingInterval) {
153
- globalThis.clearInterval(pingInterval);
154
- }
155
- await writer.close();
156
- };
157
- return {
158
- readable,
159
- sendEvent,
160
- close,
161
- writer,
162
- };
163
- }
164
- export function wrapToolHandlers(handlers, emitResult) {
165
- const wrapped = {};
166
- Object.entries(handlers).forEach(([name, handler]) => {
167
- wrapped[name] = async (args) => {
168
- const toolCallId = `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
169
- const startTime = Date.now();
170
- try {
171
- const result = await handler(args);
172
- const duration = Date.now() - startTime;
173
- // Emit success result
174
- emitResult(toolCallId, { status: "success", result }, "complete", duration);
175
- return result;
176
- }
177
- catch (error) {
178
- const duration = Date.now() - startTime;
179
- // Emit error result
180
- emitResult(toolCallId, {
181
- status: "error",
182
- error: error instanceof Error ? error.message : String(error),
183
- }, "error", duration);
184
- throw error;
185
- }
186
- };
187
- });
188
- return wrapped;
189
- }
190
- export function enhanceToolCalls(toolCalls, serverMappings) {
191
- const mappingDict = serverMappings.reduce((acc, mapping) => {
192
- acc[mapping.toolName] = {
193
- serverName: mapping.serverName,
194
- serverId: mapping.serverId,
195
- };
196
- return acc;
197
- }, {});
198
- return toolCalls.map((toolCall) => ({
199
- ...toolCall,
200
- serverName: mappingDict[toolCall.name]?.serverName,
201
- serverId: mappingDict[toolCall.name]?.serverId,
202
- }));
203
- }
204
- /**
205
- * Helper to track conversation metrics
206
- */
207
- export class ConversationMetrics {
208
- startTime = Date.now();
209
- tokenCount = 0;
210
- toolCallCount = 0;
211
- errorCount = 0;
212
- recordToken() {
213
- this.tokenCount++;
214
- }
215
- recordToolCall() {
216
- this.toolCallCount++;
217
- }
218
- recordError() {
219
- this.errorCount++;
220
- }
221
- getMetrics() {
222
- const duration = Date.now() - this.startTime;
223
- return {
224
- duration,
225
- tokenCount: this.tokenCount,
226
- toolCallCount: this.toolCallCount,
227
- errorCount: this.errorCount,
228
- tokensPerSecond: this.tokenCount / (duration / 1000),
229
- };
230
- }
231
- reset() {
232
- this.startTime = Date.now();
233
- this.tokenCount = 0;
234
- this.toolCallCount = 0;
235
- this.errorCount = 0;
236
- }
237
- }