graphlit-client 1.0.20250611018 ā 1.0.20250611020
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.js +84 -16
- package/dist/streaming/providers.js +121 -5
- package/dist/streaming/ui-event-adapter.js +5 -9
- package/package.json +1 -1
package/dist/client.js
CHANGED
@@ -1419,26 +1419,28 @@ class Graphlit {
|
|
1419
1419
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1420
1420
|
console.log("[supportsStreaming] Checking support for:", {
|
1421
1421
|
serviceType,
|
1422
|
-
hasOpenAI: OpenAI !== undefined,
|
1423
|
-
hasAnthropic: Anthropic !== undefined,
|
1424
|
-
hasGoogle: GoogleGenerativeAI !== undefined,
|
1422
|
+
hasOpenAI: OpenAI !== undefined || this.openaiClient !== undefined,
|
1423
|
+
hasAnthropic: Anthropic !== undefined || this.anthropicClient !== undefined,
|
1424
|
+
hasGoogle: GoogleGenerativeAI !== undefined || this.googleClient !== undefined,
|
1425
1425
|
});
|
1426
1426
|
}
|
1427
1427
|
switch (serviceType) {
|
1428
1428
|
case Types.ModelServiceTypes.OpenAi:
|
1429
|
-
return OpenAI !== undefined;
|
1429
|
+
return OpenAI !== undefined || this.openaiClient !== undefined;
|
1430
1430
|
case Types.ModelServiceTypes.Anthropic:
|
1431
|
-
return Anthropic !== undefined;
|
1431
|
+
return Anthropic !== undefined || this.anthropicClient !== undefined;
|
1432
1432
|
case Types.ModelServiceTypes.Google:
|
1433
|
-
return GoogleGenerativeAI !== undefined;
|
1433
|
+
return GoogleGenerativeAI !== undefined || this.googleClient !== undefined;
|
1434
1434
|
default:
|
1435
1435
|
return false;
|
1436
1436
|
}
|
1437
1437
|
}
|
1438
|
-
// If we have no specification, check if
|
1439
|
-
//
|
1440
|
-
const hasOpenAI = OpenAI !== undefined;
|
1441
|
-
|
1438
|
+
// If we have no specification, check if any client is available
|
1439
|
+
// Check both module-level SDKs and instance-level clients
|
1440
|
+
const hasOpenAI = OpenAI !== undefined || this.openaiClient !== undefined;
|
1441
|
+
const hasAnthropic = Anthropic !== undefined || this.anthropicClient !== undefined;
|
1442
|
+
const hasGoogle = GoogleGenerativeAI !== undefined || this.googleClient !== undefined;
|
1443
|
+
return hasOpenAI || hasAnthropic || hasGoogle;
|
1442
1444
|
}
|
1443
1445
|
/**
|
1444
1446
|
* Execute an agent with non-streaming response
|
@@ -1640,9 +1642,7 @@ class Graphlit {
|
|
1640
1642
|
throw new Error("Failed to format conversation");
|
1641
1643
|
}
|
1642
1644
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1643
|
-
console.log("\nš [formatConversation] Response
|
1644
|
-
console.log("Formatted message:", formattedMessage.message);
|
1645
|
-
console.log("Full formatConversation response:", JSON.stringify(formatResponse.formatConversation, null, 2));
|
1645
|
+
console.log("\nš [formatConversation] Response", formattedMessage.message);
|
1646
1646
|
}
|
1647
1647
|
// Build message array with conversation history
|
1648
1648
|
const messages = [];
|
@@ -1677,7 +1677,16 @@ class Graphlit {
|
|
1677
1677
|
let toolCalls = [];
|
1678
1678
|
let roundMessage = "";
|
1679
1679
|
// Stream with appropriate provider
|
1680
|
-
if (
|
1680
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1681
|
+
console.log(`\nš [Streaming Decision] Service: ${serviceType}, Round: ${currentRound}`);
|
1682
|
+
console.log(` OpenAI available: ${!!(OpenAI || this.openaiClient)}`);
|
1683
|
+
console.log(` Anthropic available: ${!!(Anthropic || this.anthropicClient)}`);
|
1684
|
+
console.log(` Google available: ${!!(GoogleGenerativeAI || this.googleClient)}`);
|
1685
|
+
}
|
1686
|
+
if (serviceType === Types.ModelServiceTypes.OpenAi && (OpenAI || this.openaiClient)) {
|
1687
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1688
|
+
console.log(`\nā
[Streaming] Using OpenAI native streaming (Round ${currentRound})`);
|
1689
|
+
}
|
1681
1690
|
const openaiMessages = formatMessagesForOpenAI(messages);
|
1682
1691
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1683
1692
|
console.log("\nš [OpenAI] Formatted messages being sent to LLM:");
|
@@ -1688,9 +1697,15 @@ class Graphlit {
|
|
1688
1697
|
roundMessage = message;
|
1689
1698
|
toolCalls = calls;
|
1690
1699
|
});
|
1700
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1701
|
+
console.log(`\nš [Streaming] OpenAI native streaming completed (Round ${currentRound})`);
|
1702
|
+
}
|
1691
1703
|
}
|
1692
1704
|
else if (serviceType === Types.ModelServiceTypes.Anthropic &&
|
1693
|
-
Anthropic) {
|
1705
|
+
(Anthropic || this.anthropicClient)) {
|
1706
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1707
|
+
console.log(`\nā
[Streaming] Using Anthropic native streaming (Round ${currentRound})`);
|
1708
|
+
}
|
1694
1709
|
const { system, messages: anthropicMessages } = formatMessagesForAnthropic(messages);
|
1695
1710
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1696
1711
|
console.log("\nš [Anthropic] Formatted messages being sent to LLM:");
|
@@ -1702,9 +1717,15 @@ class Graphlit {
|
|
1702
1717
|
roundMessage = message;
|
1703
1718
|
toolCalls = calls;
|
1704
1719
|
});
|
1720
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1721
|
+
console.log(`\nš [Streaming] Anthropic native streaming completed (Round ${currentRound})`);
|
1722
|
+
}
|
1705
1723
|
}
|
1706
1724
|
else if (serviceType === Types.ModelServiceTypes.Google &&
|
1707
|
-
GoogleGenerativeAI) {
|
1725
|
+
(GoogleGenerativeAI || this.googleClient)) {
|
1726
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1727
|
+
console.log(`\nā
[Streaming] Using Google native streaming (Round ${currentRound})`);
|
1728
|
+
}
|
1708
1729
|
const googleMessages = formatMessagesForGoogle(messages);
|
1709
1730
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1710
1731
|
console.log("\nš [Google] Formatted messages being sent to LLM:");
|
@@ -1717,10 +1738,21 @@ class Graphlit {
|
|
1717
1738
|
roundMessage = message;
|
1718
1739
|
toolCalls = calls;
|
1719
1740
|
});
|
1741
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1742
|
+
console.log(`\nš [Streaming] Google native streaming completed (Round ${currentRound})`);
|
1743
|
+
}
|
1720
1744
|
}
|
1721
1745
|
else {
|
1722
1746
|
// Fallback to non-streaming
|
1747
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1748
|
+
console.log(`\nā ļø [Fallback] No native streaming available for ${serviceType} (Round ${currentRound})`);
|
1749
|
+
console.log(` Falling back to non-streaming promptConversation`);
|
1750
|
+
console.log(` This should NOT happen if clients are properly set!`);
|
1751
|
+
}
|
1723
1752
|
await this.fallbackToNonStreaming(prompt, conversationId, specification, tools, mimeType, data, uiAdapter, correlationId);
|
1753
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
1754
|
+
console.log(`\nš [Fallback] Non-streaming fallback completed (Round ${currentRound})`);
|
1755
|
+
}
|
1724
1756
|
break;
|
1725
1757
|
}
|
1726
1758
|
// Update the full message
|
@@ -1964,8 +1996,21 @@ class Graphlit {
|
|
1964
1996
|
* Fallback to non-streaming when streaming is not available
|
1965
1997
|
*/
|
1966
1998
|
async fallbackToNonStreaming(prompt, conversationId, specification, tools, mimeType, data, uiAdapter, correlationId) {
|
1999
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2000
|
+
console.log(`\nš [Fallback] Starting non-streaming fallback`);
|
2001
|
+
console.log(` Conversation ID: ${conversationId}`);
|
2002
|
+
console.log(` Specification: ${specification.name} (${specification.serviceType})`);
|
2003
|
+
console.log(` Prompt: "${prompt.substring(0, 100)}${prompt.length > 100 ? '...' : ''}"`);
|
2004
|
+
console.log(` About to call promptConversation...`);
|
2005
|
+
}
|
1967
2006
|
const response = await this.promptConversation(prompt, conversationId, { id: specification.id }, mimeType, data, tools, false, false, correlationId);
|
1968
2007
|
const message = response.promptConversation?.message;
|
2008
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2009
|
+
console.log(`\nā
[Fallback] promptConversation completed`);
|
2010
|
+
console.log(` Response message length: ${message?.message?.length || 0} chars`);
|
2011
|
+
console.log(` Response preview: "${message?.message?.substring(0, 100) || 'NO MESSAGE'}${(message?.message?.length || 0) > 100 ? '...' : ''}"`);
|
2012
|
+
console.log(` Now simulating streaming by splitting into tokens...`);
|
2013
|
+
}
|
1969
2014
|
if (message?.message) {
|
1970
2015
|
// Simulate streaming by emitting tokens
|
1971
2016
|
const words = message.message.split(" ");
|
@@ -1974,6 +2019,9 @@ class Graphlit {
|
|
1974
2019
|
uiAdapter.handleEvent({ type: "token", token });
|
1975
2020
|
}
|
1976
2021
|
uiAdapter.handleEvent({ type: "message", message: message.message });
|
2022
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2023
|
+
console.log(`\nšÆ [Fallback] Completed token simulation (${words.length} tokens)`);
|
2024
|
+
}
|
1977
2025
|
}
|
1978
2026
|
}
|
1979
2027
|
/**
|
@@ -1988,6 +2036,12 @@ class Graphlit {
|
|
1988
2036
|
new OpenAI({
|
1989
2037
|
apiKey: process.env.OPENAI_API_KEY || "",
|
1990
2038
|
});
|
2039
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2040
|
+
console.log("\nš [Graphlit SDK] Routing to OpenAI streaming provider");
|
2041
|
+
console.log(` š Specification: ${specification.name} (${specification.id})`);
|
2042
|
+
console.log(` š Messages: ${messages.length}`);
|
2043
|
+
console.log(` š§ Tools: ${tools?.length || 0}`);
|
2044
|
+
}
|
1991
2045
|
await streamWithOpenAI(specification, messages, tools, openaiClient, (event) => uiAdapter.handleEvent(event), onComplete);
|
1992
2046
|
}
|
1993
2047
|
/**
|
@@ -2002,6 +2056,13 @@ class Graphlit {
|
|
2002
2056
|
new Anthropic({
|
2003
2057
|
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
2004
2058
|
});
|
2059
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2060
|
+
console.log("\nš [Graphlit SDK] Routing to Anthropic streaming provider");
|
2061
|
+
console.log(` š Specification: ${specification.name} (${specification.id})`);
|
2062
|
+
console.log(` š Messages: ${messages.length}`);
|
2063
|
+
console.log(` š§ Tools: ${tools?.length || 0}`);
|
2064
|
+
console.log(` š¬ System Prompt: ${systemPrompt ? 'Yes' : 'No'}`);
|
2065
|
+
}
|
2005
2066
|
await streamWithAnthropic(specification, messages, systemPrompt, tools, anthropicClient, (event) => uiAdapter.handleEvent(event), onComplete);
|
2006
2067
|
}
|
2007
2068
|
/**
|
@@ -2014,6 +2075,13 @@ class Graphlit {
|
|
2014
2075
|
// Use provided client or create a new one
|
2015
2076
|
const googleClient = this.googleClient ||
|
2016
2077
|
new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || "");
|
2078
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
2079
|
+
console.log("\nš [Graphlit SDK] Routing to Google streaming provider");
|
2080
|
+
console.log(` š Specification: ${specification.name} (${specification.id})`);
|
2081
|
+
console.log(` š Messages: ${messages.length}`);
|
2082
|
+
console.log(` š§ Tools: ${tools?.length || 0}`);
|
2083
|
+
console.log(` š¬ System Prompt: ${systemPrompt ? 'Yes' : 'No'}`);
|
2084
|
+
}
|
2017
2085
|
await streamWithGoogle(specification, messages, systemPrompt, tools, googleClient, (event) => uiAdapter.handleEvent(event), onComplete);
|
2018
2086
|
}
|
2019
2087
|
// Helper method to execute tools for promptAgent
|
@@ -18,6 +18,12 @@ export async function streamWithOpenAI(specification, messages, tools, openaiCli
|
|
18
18
|
onEvent, onComplete) {
|
19
19
|
let fullMessage = "";
|
20
20
|
let toolCalls = [];
|
21
|
+
// Performance metrics
|
22
|
+
const startTime = Date.now();
|
23
|
+
let firstTokenTime = 0;
|
24
|
+
let tokenCount = 0;
|
25
|
+
let lastEventTime = 0;
|
26
|
+
const interTokenDelays = [];
|
21
27
|
try {
|
22
28
|
const modelName = getModelName(specification);
|
23
29
|
if (!modelName) {
|
@@ -55,6 +61,9 @@ onEvent, onComplete) {
|
|
55
61
|
},
|
56
62
|
}));
|
57
63
|
}
|
64
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
65
|
+
console.log("\nā±ļø [OpenAI] Starting LLM call at:", new Date().toISOString());
|
66
|
+
}
|
58
67
|
const stream = await openaiClient.chat.completions.create(streamConfig);
|
59
68
|
for await (const chunk of stream) {
|
60
69
|
const delta = chunk.choices[0]?.delta;
|
@@ -73,9 +82,23 @@ onEvent, onComplete) {
|
|
73
82
|
}
|
74
83
|
if (delta?.content) {
|
75
84
|
fullMessage += delta.content;
|
85
|
+
tokenCount++;
|
86
|
+
const currentTime = Date.now();
|
87
|
+
// Track TTFT
|
88
|
+
if (firstTokenTime === 0) {
|
89
|
+
firstTokenTime = currentTime - startTime;
|
90
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
91
|
+
console.log(`\nā” [OpenAI] Time to First Token (TTFT): ${firstTokenTime}ms`);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
// Track inter-token delays
|
95
|
+
if (lastEventTime > 0) {
|
96
|
+
const delay = currentTime - lastEventTime;
|
97
|
+
interTokenDelays.push(delay);
|
98
|
+
}
|
99
|
+
lastEventTime = currentTime;
|
76
100
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
77
|
-
console.log(`[OpenAI]
|
78
|
-
console.log(`[OpenAI] Current full message: "${fullMessage}"`);
|
101
|
+
console.log(`[OpenAI] Token #${tokenCount}: "${delta.content}" | Accumulated: ${fullMessage.length} chars`);
|
79
102
|
}
|
80
103
|
onEvent({
|
81
104
|
type: "token",
|
@@ -153,8 +176,27 @@ onEvent, onComplete) {
|
|
153
176
|
if (process.env.DEBUG_GRAPHLIT_STREAMING && toolCalls.length > 0) {
|
154
177
|
console.log(`[OpenAI] Successfully processed ${toolCalls.length} tool calls`);
|
155
178
|
}
|
179
|
+
// Calculate final metrics
|
180
|
+
const totalTime = Date.now() - startTime;
|
181
|
+
const tokensPerSecond = tokenCount > 0 ? tokenCount / (totalTime / 1000) : 0;
|
156
182
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
157
|
-
console.log(
|
183
|
+
console.log("\nš [OpenAI] Performance Metrics:");
|
184
|
+
console.log(` ā±ļø Total Time: ${totalTime}ms`);
|
185
|
+
console.log(` ā” Time to First Token (TTFT): ${firstTokenTime}ms`);
|
186
|
+
console.log(` š Tokens Generated: ${tokenCount}`);
|
187
|
+
console.log(` šØ Tokens Per Second (TPS): ${tokensPerSecond.toFixed(2)}`);
|
188
|
+
if (interTokenDelays.length > 0) {
|
189
|
+
const avgDelay = interTokenDelays.reduce((a, b) => a + b, 0) / interTokenDelays.length;
|
190
|
+
const sortedDelays = [...interTokenDelays].sort((a, b) => a - b);
|
191
|
+
const p50Delay = sortedDelays[Math.floor(sortedDelays.length * 0.5)];
|
192
|
+
const p95Delay = sortedDelays[Math.floor(sortedDelays.length * 0.95)];
|
193
|
+
const p99Delay = sortedDelays[Math.floor(sortedDelays.length * 0.99)];
|
194
|
+
console.log(` ā³ Average Inter-Token Delay: ${avgDelay.toFixed(2)}ms`);
|
195
|
+
console.log(` š P50 Delay: ${p50Delay}ms`);
|
196
|
+
console.log(` ā ļø P95 Delay: ${p95Delay}ms`);
|
197
|
+
console.log(` šØ P99 Delay: ${p99Delay}ms`);
|
198
|
+
}
|
199
|
+
console.log(`\nā
[OpenAI] Final message (${fullMessage.length} chars): "${fullMessage}"`);
|
158
200
|
}
|
159
201
|
onComplete(fullMessage, toolCalls);
|
160
202
|
}
|
@@ -173,6 +215,12 @@ export async function streamWithAnthropic(specification, messages, systemPrompt,
|
|
173
215
|
onEvent, onComplete) {
|
174
216
|
let fullMessage = "";
|
175
217
|
let toolCalls = [];
|
218
|
+
// Performance metrics
|
219
|
+
const startTime = Date.now();
|
220
|
+
let firstTokenTime = 0;
|
221
|
+
let tokenCount = 0;
|
222
|
+
let lastEventTime = 0;
|
223
|
+
const interTokenDelays = [];
|
176
224
|
try {
|
177
225
|
const modelName = getModelName(specification);
|
178
226
|
if (!modelName) {
|
@@ -207,6 +255,9 @@ onEvent, onComplete) {
|
|
207
255
|
input_schema: tool.schema ? JSON.parse(tool.schema) : {},
|
208
256
|
}));
|
209
257
|
}
|
258
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
259
|
+
console.log("\nā±ļø [Anthropic] Starting LLM call at:", new Date().toISOString());
|
260
|
+
}
|
210
261
|
const stream = await anthropicClient.messages.create(streamConfig);
|
211
262
|
let activeContentBlock = false;
|
212
263
|
for await (const chunk of stream) {
|
@@ -234,10 +285,25 @@ onEvent, onComplete) {
|
|
234
285
|
}
|
235
286
|
else if (chunk.type === "content_block_delta") {
|
236
287
|
if (chunk.delta.type === "text_delta") {
|
288
|
+
fullMessage += chunk.delta.text;
|
289
|
+
tokenCount++;
|
290
|
+
const currentTime = Date.now();
|
291
|
+
// Track TTFT
|
292
|
+
if (firstTokenTime === 0) {
|
293
|
+
firstTokenTime = currentTime - startTime;
|
294
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
295
|
+
console.log(`\nā” [Anthropic] Time to First Token (TTFT): ${firstTokenTime}ms`);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
// Track inter-token delays
|
299
|
+
if (lastEventTime > 0) {
|
300
|
+
const delay = currentTime - lastEventTime;
|
301
|
+
interTokenDelays.push(delay);
|
302
|
+
}
|
303
|
+
lastEventTime = currentTime;
|
237
304
|
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
238
|
-
console.log(`[Anthropic]
|
305
|
+
console.log(`[Anthropic] Token #${tokenCount}: "${chunk.delta.text}" | Accumulated: ${fullMessage.length} chars`);
|
239
306
|
}
|
240
|
-
fullMessage += chunk.delta.text;
|
241
307
|
onEvent({
|
242
308
|
type: "token",
|
243
309
|
token: chunk.delta.text,
|
@@ -336,6 +402,28 @@ onEvent, onComplete) {
|
|
336
402
|
console.log(`[Anthropic] Filtered out ${toolCalls.length - validToolCalls.length} incomplete tool calls`);
|
337
403
|
console.log(`[Anthropic] Successfully processed ${validToolCalls.length} valid tool calls`);
|
338
404
|
}
|
405
|
+
// Calculate final metrics
|
406
|
+
const totalTime = Date.now() - startTime;
|
407
|
+
const tokensPerSecond = tokenCount > 0 ? tokenCount / (totalTime / 1000) : 0;
|
408
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
409
|
+
console.log("\nš [Anthropic] Performance Metrics:");
|
410
|
+
console.log(` ā±ļø Total Time: ${totalTime}ms`);
|
411
|
+
console.log(` ā” Time to First Token (TTFT): ${firstTokenTime}ms`);
|
412
|
+
console.log(` š Tokens Generated: ${tokenCount}`);
|
413
|
+
console.log(` šØ Tokens Per Second (TPS): ${tokensPerSecond.toFixed(2)}`);
|
414
|
+
if (interTokenDelays.length > 0) {
|
415
|
+
const avgDelay = interTokenDelays.reduce((a, b) => a + b, 0) / interTokenDelays.length;
|
416
|
+
const sortedDelays = [...interTokenDelays].sort((a, b) => a - b);
|
417
|
+
const p50Delay = sortedDelays[Math.floor(sortedDelays.length * 0.5)];
|
418
|
+
const p95Delay = sortedDelays[Math.floor(sortedDelays.length * 0.95)];
|
419
|
+
const p99Delay = sortedDelays[Math.floor(sortedDelays.length * 0.99)];
|
420
|
+
console.log(` ā³ Average Inter-Token Delay: ${avgDelay.toFixed(2)}ms`);
|
421
|
+
console.log(` š P50 Delay: ${p50Delay}ms`);
|
422
|
+
console.log(` ā ļø P95 Delay: ${p95Delay}ms`);
|
423
|
+
console.log(` šØ P99 Delay: ${p99Delay}ms`);
|
424
|
+
}
|
425
|
+
console.log(`\nā
[Anthropic] Final message (${fullMessage.length} chars): "${fullMessage}"`);
|
426
|
+
}
|
339
427
|
onComplete(fullMessage, validToolCalls);
|
340
428
|
}
|
341
429
|
catch (error) {
|
@@ -353,6 +441,12 @@ export async function streamWithGoogle(specification, messages, systemPrompt, to
|
|
353
441
|
onEvent, onComplete) {
|
354
442
|
let fullMessage = "";
|
355
443
|
let toolCalls = [];
|
444
|
+
// Performance metrics
|
445
|
+
const startTime = Date.now();
|
446
|
+
let firstTokenTime = 0;
|
447
|
+
let tokenCount = 0;
|
448
|
+
let lastEventTime = 0;
|
449
|
+
const interTokenDelays = [];
|
356
450
|
try {
|
357
451
|
const modelName = getModelName(specification);
|
358
452
|
if (!modelName) {
|
@@ -559,6 +653,28 @@ onEvent, onComplete) {
|
|
559
653
|
if (process.env.DEBUG_GRAPHLIT_STREAMING && toolCalls.length > 0) {
|
560
654
|
console.log(`[Google] Successfully processed ${toolCalls.length} tool calls`);
|
561
655
|
}
|
656
|
+
// Calculate final metrics
|
657
|
+
const totalTime = Date.now() - startTime;
|
658
|
+
const tokensPerSecond = tokenCount > 0 ? tokenCount / (totalTime / 1000) : 0;
|
659
|
+
if (process.env.DEBUG_GRAPHLIT_STREAMING) {
|
660
|
+
console.log("\nš [Google] Performance Metrics:");
|
661
|
+
console.log(` ā±ļø Total Time: ${totalTime}ms`);
|
662
|
+
console.log(` ā” Time to First Token (TTFT): ${firstTokenTime}ms`);
|
663
|
+
console.log(` š Tokens Generated: ${tokenCount}`);
|
664
|
+
console.log(` šØ Tokens Per Second (TPS): ${tokensPerSecond.toFixed(2)}`);
|
665
|
+
if (interTokenDelays.length > 0) {
|
666
|
+
const avgDelay = interTokenDelays.reduce((a, b) => a + b, 0) / interTokenDelays.length;
|
667
|
+
const sortedDelays = [...interTokenDelays].sort((a, b) => a - b);
|
668
|
+
const p50Delay = sortedDelays[Math.floor(sortedDelays.length * 0.5)];
|
669
|
+
const p95Delay = sortedDelays[Math.floor(sortedDelays.length * 0.95)];
|
670
|
+
const p99Delay = sortedDelays[Math.floor(sortedDelays.length * 0.99)];
|
671
|
+
console.log(` ā³ Average Inter-Token Delay: ${avgDelay.toFixed(2)}ms`);
|
672
|
+
console.log(` š P50 Delay: ${p50Delay}ms`);
|
673
|
+
console.log(` ā ļø P95 Delay: ${p95Delay}ms`);
|
674
|
+
console.log(` šØ P99 Delay: ${p99Delay}ms`);
|
675
|
+
}
|
676
|
+
console.log(`\nā
[Google] Final message (${fullMessage.length} chars): "${fullMessage}"`);
|
677
|
+
}
|
562
678
|
onComplete(fullMessage, toolCalls);
|
563
679
|
}
|
564
680
|
catch (error) {
|
@@ -150,21 +150,17 @@ export class UIEventAdapter {
|
|
150
150
|
}
|
151
151
|
}
|
152
152
|
handleComplete() {
|
153
|
-
// Flush any remaining chunks from buffer
|
154
|
-
if (this.chunkBuffer) {
|
155
|
-
const remaining = this.chunkBuffer.flush();
|
156
|
-
this.chunkQueue.push(...remaining);
|
157
|
-
}
|
158
153
|
// Clear any pending updates
|
159
154
|
if (this.updateTimer) {
|
160
155
|
globalThis.clearTimeout(this.updateTimer);
|
161
156
|
this.updateTimer = undefined;
|
162
157
|
}
|
163
|
-
//
|
164
|
-
|
165
|
-
|
166
|
-
this.
|
158
|
+
// DO NOT re-process chunks here - they should already be in currentMessage
|
159
|
+
// Just clear any remaining state
|
160
|
+
if (this.chunkBuffer) {
|
161
|
+
this.chunkBuffer.flush(); // Clear the buffer but don't use the result
|
167
162
|
}
|
163
|
+
this.chunkQueue.length = 0; // Clear any remaining queue
|
168
164
|
this.isStreaming = false;
|
169
165
|
// Create final message
|
170
166
|
const finalMessage = {
|