graphlit-client 1.0.20250613009 → 1.0.20250615001

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.
@@ -61,7 +61,7 @@ onEvent, onComplete) {
61
61
  try {
62
62
  const modelName = getModelName(specification);
63
63
  if (!modelName) {
64
- throw new Error(`No model name found for OpenAI specification: ${specification.name}`);
64
+ throw new Error(`No model name found for specification: ${specification.name} (service: ${specification.serviceType})`);
65
65
  }
66
66
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
67
67
  console.log(`🤖 [OpenAI] Model Config: Service=OpenAI | Model=${modelName} | Temperature=${specification.openAI?.temperature} | MaxTokens=${specification.openAI?.completionTokenLimit || "null"} | Tools=${tools?.length || 0} | Spec="${specification.name}"`);
@@ -979,3 +979,623 @@ onEvent, onComplete) {
979
979
  throw error;
980
980
  }
981
981
  }
982
+ /**
983
+ * Stream with Groq SDK (OpenAI-compatible)
984
+ */
985
+ export async function streamWithGroq(specification, messages, tools, groqClient, // Groq client instance (OpenAI-compatible)
986
+ onEvent, onComplete) {
987
+ // Groq uses the same API as OpenAI, so we can reuse the OpenAI streaming logic
988
+ return streamWithOpenAI(specification, messages, tools, groqClient, onEvent, onComplete);
989
+ }
990
+ /**
991
+ * Stream with Cerebras SDK (OpenAI-compatible)
992
+ */
993
+ export async function streamWithCerebras(specification, messages, tools, cerebrasClient, // OpenAI client instance configured for Cerebras
994
+ onEvent, onComplete) {
995
+ // Cerebras uses the same API as OpenAI, so we can reuse the OpenAI streaming logic
996
+ return streamWithOpenAI(specification, messages, tools, cerebrasClient, onEvent, onComplete);
997
+ }
998
+ /**
999
+ * Stream with Deepseek SDK (OpenAI-compatible)
1000
+ */
1001
+ export async function streamWithDeepseek(specification, messages, tools, deepseekClient, // OpenAI client instance configured for Deepseek
1002
+ onEvent, onComplete) {
1003
+ let fullMessage = "";
1004
+ let toolCalls = [];
1005
+ // Performance metrics
1006
+ const startTime = Date.now();
1007
+ let firstTokenTime = 0;
1008
+ let firstMeaningfulContentTime = 0;
1009
+ let tokenCount = 0;
1010
+ let toolArgumentTokens = 0;
1011
+ let lastEventTime = 0;
1012
+ const interTokenDelays = [];
1013
+ // Tool calling metrics
1014
+ const toolMetrics = {
1015
+ totalTools: 0,
1016
+ successfulTools: 0,
1017
+ failedTools: 0,
1018
+ toolTimes: [],
1019
+ currentToolStart: 0,
1020
+ roundStartTime: startTime,
1021
+ rounds: [],
1022
+ currentRound: 1,
1023
+ };
1024
+ try {
1025
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1026
+ console.log(`🔍 [Deepseek] Specification object:`, {
1027
+ name: specification.name,
1028
+ serviceType: specification.serviceType,
1029
+ deepseek: specification.deepseek,
1030
+ hasDeepseekModel: !!specification.deepseek?.model,
1031
+ deepseekModelValue: specification.deepseek?.model
1032
+ });
1033
+ }
1034
+ const modelName = getModelName(specification);
1035
+ if (!modelName) {
1036
+ console.error(`❌ [Deepseek] Model resolution failed:`, {
1037
+ name: specification.name,
1038
+ serviceType: specification.serviceType,
1039
+ deepseek: specification.deepseek,
1040
+ hasCustomModelName: !!specification.deepseek?.modelName
1041
+ });
1042
+ throw new Error(`No model name found for specification: ${specification.name} (service: ${specification.serviceType})`);
1043
+ }
1044
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1045
+ console.log(`🤖 [Deepseek] Model Config: Service=Deepseek | Model=${modelName} | Temperature=${specification.deepseek?.temperature} | MaxTokens=${specification.deepseek?.completionTokenLimit || "null"} | Tools=${tools?.length || 0} | Spec="${specification.name}"`);
1046
+ }
1047
+ const streamConfig = {
1048
+ model: modelName,
1049
+ messages,
1050
+ stream: true,
1051
+ temperature: specification.deepseek?.temperature,
1052
+ };
1053
+ // Only add max_completion_tokens if it's defined
1054
+ if (specification.deepseek?.completionTokenLimit) {
1055
+ streamConfig.max_completion_tokens =
1056
+ specification.deepseek.completionTokenLimit;
1057
+ }
1058
+ // Add tools if provided
1059
+ if (tools && tools.length > 0) {
1060
+ streamConfig.tools = tools.map((tool) => ({
1061
+ type: "function",
1062
+ function: {
1063
+ name: tool.name,
1064
+ description: tool.description,
1065
+ parameters: tool.schema ? JSON.parse(tool.schema) : {},
1066
+ },
1067
+ }));
1068
+ }
1069
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1070
+ console.log(`⏱️ [Deepseek] Starting LLM call at: ${new Date().toISOString()}`);
1071
+ }
1072
+ const stream = await deepseekClient.chat.completions.create(streamConfig);
1073
+ for await (const chunk of stream) {
1074
+ const delta = chunk.choices[0]?.delta;
1075
+ if (!delta)
1076
+ continue;
1077
+ const currentTime = Date.now();
1078
+ // Track first token time
1079
+ if (firstTokenTime === 0) {
1080
+ firstTokenTime = currentTime - startTime;
1081
+ }
1082
+ // Track inter-token delays
1083
+ if (lastEventTime > 0) {
1084
+ const delay = currentTime - lastEventTime;
1085
+ interTokenDelays.push(delay);
1086
+ }
1087
+ lastEventTime = currentTime;
1088
+ // Handle message content
1089
+ if (delta.content) {
1090
+ tokenCount++;
1091
+ fullMessage += delta.content;
1092
+ // Track first meaningful content
1093
+ if (firstMeaningfulContentTime === 0 && fullMessage.trim().length > 0) {
1094
+ firstMeaningfulContentTime = currentTime - startTime;
1095
+ }
1096
+ onEvent({
1097
+ type: "message",
1098
+ message: fullMessage,
1099
+ });
1100
+ // Performance metrics tracking (internal only)
1101
+ if (tokenCount % 10 === 0) {
1102
+ const totalTokens = tokenCount + toolArgumentTokens;
1103
+ const tokensPerSecond = totalTokens > 0 ? totalTokens / ((currentTime - startTime) / 1000) : 0;
1104
+ const avgInterTokenDelay = interTokenDelays.length > 0
1105
+ ? interTokenDelays.reduce((a, b) => a + b, 0) / interTokenDelays.length
1106
+ : 0;
1107
+ }
1108
+ }
1109
+ // Handle tool calls
1110
+ if (delta.tool_calls) {
1111
+ for (const toolCall of delta.tool_calls) {
1112
+ const index = toolCall.index;
1113
+ // Initialize tool call if it doesn't exist
1114
+ if (!toolCalls[index]) {
1115
+ toolCalls[index] = {
1116
+ id: toolCall.id || `tool_${index}`,
1117
+ name: toolCall.function?.name || "",
1118
+ arguments: "",
1119
+ };
1120
+ // Start tool timing
1121
+ toolMetrics.totalTools++;
1122
+ toolMetrics.currentToolStart = currentTime;
1123
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1124
+ console.log(`🔧 [Deepseek] Tool call started: ${toolCalls[index].name}`);
1125
+ }
1126
+ onEvent({
1127
+ type: "tool_call_parsed",
1128
+ toolCall: { ...toolCalls[index] },
1129
+ });
1130
+ }
1131
+ // Update tool call name if provided
1132
+ if (toolCall.function?.name) {
1133
+ toolCalls[index].name = toolCall.function.name;
1134
+ }
1135
+ // Accumulate arguments
1136
+ if (toolCall.function?.arguments) {
1137
+ toolCalls[index].arguments += toolCall.function.arguments;
1138
+ toolArgumentTokens++;
1139
+ }
1140
+ // Update with current state
1141
+ onEvent({
1142
+ type: "tool_call_delta",
1143
+ toolCallId: toolCalls[index].id,
1144
+ argumentDelta: toolCall.function?.arguments || "",
1145
+ });
1146
+ }
1147
+ }
1148
+ }
1149
+ // Process completed tool calls
1150
+ const validToolCalls = toolCalls.filter((tc, idx) => {
1151
+ if (!isValidJSON(tc.arguments)) {
1152
+ console.warn(`[Deepseek] Filtering out incomplete tool call ${idx} (${tc.name}) with INVALID JSON (${tc.arguments.length} chars)`);
1153
+ return false;
1154
+ }
1155
+ return true;
1156
+ });
1157
+ if (toolCalls.length !== validToolCalls.length) {
1158
+ console.log(`[Deepseek] Filtered out ${toolCalls.length - validToolCalls.length} incomplete tool calls`);
1159
+ }
1160
+ // Final performance metrics
1161
+ const totalTime = Date.now() - startTime;
1162
+ const totalTokens = tokenCount + toolArgumentTokens;
1163
+ const tokensPerSecond = totalTokens > 0 ? totalTokens / (totalTime / 1000) : 0;
1164
+ if (process.env.DEBUG_GRAPHLIT_SDK_METRICS) {
1165
+ const metricsData = {
1166
+ totalTime: `${totalTime}ms`,
1167
+ ttft: `${firstTokenTime}ms`,
1168
+ ttfmc: firstMeaningfulContentTime > 0
1169
+ ? `${firstMeaningfulContentTime}ms`
1170
+ : null,
1171
+ contentTokens: tokenCount,
1172
+ toolTokens: toolArgumentTokens,
1173
+ totalTokens: totalTokens,
1174
+ tps: tokensPerSecond.toFixed(2),
1175
+ };
1176
+ console.log(`📊 [Deepseek] Performance: Total=${metricsData.totalTime} | TTFT=${metricsData.ttft}${metricsData.ttfmc ? ` | TTFMC=${metricsData.ttfmc}` : ""} | Tokens(content/tool/total)=${metricsData.contentTokens}/${metricsData.toolTokens}/${metricsData.totalTokens} | TPS=${metricsData.tps}`);
1177
+ }
1178
+ // Send completion event
1179
+ onEvent({
1180
+ type: "complete",
1181
+ tokens: totalTokens,
1182
+ });
1183
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1184
+ console.log(`✅ [Deepseek] Stream completed: ${fullMessage.length} chars, ${validToolCalls.length} tools`);
1185
+ }
1186
+ onComplete(fullMessage, validToolCalls);
1187
+ }
1188
+ catch (error) {
1189
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1190
+ console.error(`❌ [Deepseek] Stream error:`, error);
1191
+ }
1192
+ onEvent({
1193
+ type: "error",
1194
+ error: `Deepseek streaming error: ${error}`,
1195
+ });
1196
+ throw error;
1197
+ }
1198
+ }
1199
+ /**
1200
+ * Stream with Cohere SDK
1201
+ */
1202
+ export async function streamWithCohere(specification, messages, tools, cohereClient, // CohereClient instance
1203
+ onEvent, onComplete) {
1204
+ let fullMessage = "";
1205
+ let toolCalls = [];
1206
+ // Performance metrics
1207
+ const startTime = Date.now();
1208
+ let firstTokenTime = 0;
1209
+ let tokenCount = 0;
1210
+ try {
1211
+ const modelName = getModelName(specification);
1212
+ if (!modelName) {
1213
+ throw new Error(`No model name found for Cohere specification: ${specification.name}`);
1214
+ }
1215
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1216
+ console.log(`🤖 [Cohere] Model Config: Service=Cohere | Model=${modelName} | Temperature=${specification.cohere?.temperature} | Tools=${tools?.length || 0} | Spec="${specification.name}"`);
1217
+ }
1218
+ // Prepare the latest user message and chat history
1219
+ const lastMessage = messages[messages.length - 1];
1220
+ const chatHistory = messages.slice(0, -1);
1221
+ const streamConfig = {
1222
+ model: modelName,
1223
+ message: lastMessage.message,
1224
+ chatHistory: chatHistory,
1225
+ temperature: specification.cohere?.temperature,
1226
+ };
1227
+ // Add tools if provided
1228
+ if (tools && tools.length > 0) {
1229
+ streamConfig.tools = tools.map((tool) => {
1230
+ if (!tool.schema) {
1231
+ return {
1232
+ name: tool.name,
1233
+ description: tool.description,
1234
+ parameterDefinitions: {},
1235
+ };
1236
+ }
1237
+ // Parse the JSON schema
1238
+ const schema = JSON.parse(tool.schema);
1239
+ // Convert JSON Schema to Cohere's expected format
1240
+ const parameterDefinitions = {};
1241
+ if (schema.properties) {
1242
+ for (const [key, value] of Object.entries(schema.properties)) {
1243
+ const prop = value;
1244
+ parameterDefinitions[key] = {
1245
+ type: prop.type || "string",
1246
+ description: prop.description || "",
1247
+ required: schema.required?.includes(key) || false,
1248
+ };
1249
+ // Add additional properties that Cohere might expect
1250
+ if (prop.enum) {
1251
+ parameterDefinitions[key].options = prop.enum;
1252
+ }
1253
+ if (prop.default !== undefined) {
1254
+ parameterDefinitions[key].default = prop.default;
1255
+ }
1256
+ if (prop.items) {
1257
+ parameterDefinitions[key].items = prop.items;
1258
+ }
1259
+ }
1260
+ }
1261
+ return {
1262
+ name: tool.name,
1263
+ description: tool.description,
1264
+ parameterDefinitions,
1265
+ };
1266
+ });
1267
+ }
1268
+ const stream = await cohereClient.chatStream(streamConfig);
1269
+ for await (const chunk of stream) {
1270
+ if (chunk.eventType === "text-generation") {
1271
+ const text = chunk.text;
1272
+ if (text) {
1273
+ fullMessage += text;
1274
+ tokenCount++;
1275
+ if (firstTokenTime === 0) {
1276
+ firstTokenTime = Date.now() - startTime;
1277
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1278
+ console.log(`⚡ [Cohere] Time to First Token: ${firstTokenTime}ms`);
1279
+ }
1280
+ }
1281
+ onEvent({
1282
+ type: "token",
1283
+ token: text,
1284
+ });
1285
+ }
1286
+ }
1287
+ else if (chunk.eventType === "tool-calls-generation") {
1288
+ // Handle tool calls
1289
+ if (chunk.toolCalls) {
1290
+ for (const toolCall of chunk.toolCalls) {
1291
+ const id = `tool_${Date.now()}_${toolCalls.length}`;
1292
+ const formattedToolCall = {
1293
+ id,
1294
+ name: toolCall.name,
1295
+ arguments: JSON.stringify(toolCall.parameters),
1296
+ };
1297
+ toolCalls.push(formattedToolCall);
1298
+ onEvent({
1299
+ type: "tool_call_start",
1300
+ toolCall: { id, name: toolCall.name },
1301
+ });
1302
+ onEvent({
1303
+ type: "tool_call_parsed",
1304
+ toolCall: formattedToolCall,
1305
+ });
1306
+ }
1307
+ }
1308
+ }
1309
+ }
1310
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1311
+ console.log(`✅ [Cohere] Complete. Total tokens: ${tokenCount} | Message length: ${fullMessage.length}`);
1312
+ }
1313
+ onComplete(fullMessage, toolCalls);
1314
+ }
1315
+ catch (error) {
1316
+ throw error;
1317
+ }
1318
+ }
1319
+ /**
1320
+ * Stream with Mistral SDK
1321
+ */
1322
+ export async function streamWithMistral(specification, messages, tools, mistralClient, // Mistral client instance
1323
+ onEvent, onComplete) {
1324
+ let fullMessage = "";
1325
+ let toolCalls = [];
1326
+ // Performance metrics
1327
+ const startTime = Date.now();
1328
+ let firstTokenTime = 0;
1329
+ let tokenCount = 0;
1330
+ try {
1331
+ const modelName = getModelName(specification);
1332
+ if (!modelName) {
1333
+ throw new Error(`No model name found for Mistral specification: ${specification.name}`);
1334
+ }
1335
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1336
+ console.log(`🤖 [Mistral] Model Config: Service=Mistral | Model=${modelName} | Temperature=${specification.mistral?.temperature} | Tools=${tools?.length || 0} | Spec="${specification.name}"`);
1337
+ }
1338
+ const streamConfig = {
1339
+ model: modelName,
1340
+ messages,
1341
+ temperature: specification.mistral?.temperature,
1342
+ };
1343
+ // Add tools if provided
1344
+ if (tools && tools.length > 0) {
1345
+ streamConfig.tools = tools.map((tool) => ({
1346
+ type: "function",
1347
+ function: {
1348
+ name: tool.name,
1349
+ description: tool.description,
1350
+ parameters: tool.schema ? JSON.parse(tool.schema) : {},
1351
+ },
1352
+ }));
1353
+ }
1354
+ const stream = await mistralClient.chat.stream(streamConfig);
1355
+ for await (const chunk of stream) {
1356
+ const delta = chunk.data.choices[0]?.delta;
1357
+ if (delta?.content) {
1358
+ fullMessage += delta.content;
1359
+ tokenCount++;
1360
+ if (firstTokenTime === 0) {
1361
+ firstTokenTime = Date.now() - startTime;
1362
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1363
+ console.log(`⚡ [Mistral] Time to First Token: ${firstTokenTime}ms`);
1364
+ }
1365
+ }
1366
+ onEvent({
1367
+ type: "token",
1368
+ token: delta.content,
1369
+ });
1370
+ }
1371
+ // Handle tool calls
1372
+ if (delta?.tool_calls) {
1373
+ for (const toolCallDelta of delta.tool_calls) {
1374
+ const index = toolCallDelta.index || 0;
1375
+ if (!toolCalls[index]) {
1376
+ toolCalls[index] = {
1377
+ id: toolCallDelta.id || `tool_${Date.now()}_${index}`,
1378
+ name: "",
1379
+ arguments: "",
1380
+ };
1381
+ onEvent({
1382
+ type: "tool_call_start",
1383
+ toolCall: {
1384
+ id: toolCalls[index].id,
1385
+ name: toolCallDelta.function?.name || "",
1386
+ },
1387
+ });
1388
+ }
1389
+ if (toolCallDelta.function?.name) {
1390
+ toolCalls[index].name = toolCallDelta.function.name;
1391
+ }
1392
+ if (toolCallDelta.function?.arguments) {
1393
+ toolCalls[index].arguments += toolCallDelta.function.arguments;
1394
+ onEvent({
1395
+ type: "tool_call_delta",
1396
+ toolCallId: toolCalls[index].id,
1397
+ argumentDelta: toolCallDelta.function.arguments,
1398
+ });
1399
+ }
1400
+ }
1401
+ }
1402
+ }
1403
+ // Emit complete events for tool calls
1404
+ for (const toolCall of toolCalls) {
1405
+ if (isValidJSON(toolCall.arguments)) {
1406
+ onEvent({
1407
+ type: "tool_call_parsed",
1408
+ toolCall,
1409
+ });
1410
+ }
1411
+ }
1412
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1413
+ console.log(`✅ [Mistral] Complete. Total tokens: ${tokenCount} | Message length: ${fullMessage.length}`);
1414
+ }
1415
+ onComplete(fullMessage, toolCalls);
1416
+ }
1417
+ catch (error) {
1418
+ throw error;
1419
+ }
1420
+ }
1421
+ /**
1422
+ * Stream with Bedrock SDK (for Claude models)
1423
+ */
1424
+ export async function streamWithBedrock(specification, messages, systemPrompt, tools, bedrockClient, // BedrockRuntimeClient instance
1425
+ onEvent, onComplete) {
1426
+ let fullMessage = "";
1427
+ let toolCalls = [];
1428
+ // Map contentBlockIndex to tool calls for proper correlation
1429
+ const toolCallsByIndex = new Map();
1430
+ // Performance metrics
1431
+ const startTime = Date.now();
1432
+ let firstTokenTime = 0;
1433
+ let tokenCount = 0;
1434
+ try {
1435
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1436
+ console.log(`🔍 [Bedrock] Specification object:`, JSON.stringify(specification, null, 2));
1437
+ }
1438
+ const modelName = getModelName(specification);
1439
+ if (!modelName) {
1440
+ console.error(`❌ [Bedrock] Model resolution failed for specification:`, {
1441
+ name: specification.name,
1442
+ serviceType: specification.serviceType,
1443
+ bedrock: specification.bedrock,
1444
+ hasCustomModelName: !!specification.bedrock?.modelName
1445
+ });
1446
+ throw new Error(`No model name found for Bedrock specification: ${specification.name} (service: ${specification.serviceType}, bedrock.model: ${specification.bedrock?.model})`);
1447
+ }
1448
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1449
+ console.log(`🤖 [Bedrock] Model Config: Service=Bedrock | Model=${modelName} | Temperature=${specification.bedrock?.temperature} | Tools=${tools?.length || 0} | Spec="${specification.name}"`);
1450
+ }
1451
+ // Import the ConverseStreamCommand for unified API
1452
+ const { ConverseStreamCommand } = await import("@aws-sdk/client-bedrock-runtime");
1453
+ // Convert messages to Bedrock Converse format
1454
+ // The AWS SDK expects content as an array of content blocks
1455
+ const converseMessages = messages.map((msg) => ({
1456
+ role: msg.role,
1457
+ content: [{
1458
+ text: typeof msg.content === 'string' ? msg.content : msg.content.toString()
1459
+ }]
1460
+ }));
1461
+ // Prepare the request using Converse API format
1462
+ // Using 'any' type because:
1463
+ // 1. We're dynamically importing the SDK (can't import types at compile time)
1464
+ // 2. The ConverseStreamCommandInput type has complex union types for system/toolConfig
1465
+ // 3. The structure matches the AWS SDK expectations
1466
+ const request = {
1467
+ modelId: modelName,
1468
+ messages: converseMessages,
1469
+ inferenceConfig: {
1470
+ temperature: specification.bedrock?.temperature ?? undefined,
1471
+ topP: specification.bedrock?.probability ?? undefined,
1472
+ maxTokens: specification.bedrock?.completionTokenLimit || 1000,
1473
+ },
1474
+ };
1475
+ // Add system prompt if provided
1476
+ if (systemPrompt) {
1477
+ request.system = [{ text: systemPrompt }];
1478
+ }
1479
+ // Add tools if provided
1480
+ if (tools && tools.length > 0) {
1481
+ request.toolConfig = {
1482
+ tools: tools.map((tool) => ({
1483
+ toolSpec: {
1484
+ name: tool.name,
1485
+ description: tool.description,
1486
+ inputSchema: {
1487
+ json: tool.schema ? JSON.parse(tool.schema) : {},
1488
+ },
1489
+ },
1490
+ })),
1491
+ };
1492
+ }
1493
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1494
+ console.log(`🔍 [Bedrock] Converse request:`, JSON.stringify(request, null, 2));
1495
+ }
1496
+ const command = new ConverseStreamCommand(request);
1497
+ const response = await bedrockClient.send(command);
1498
+ if (response.stream) {
1499
+ for await (const event of response.stream) {
1500
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1501
+ console.log(`🔍 [Bedrock] Stream event:`, JSON.stringify(event));
1502
+ }
1503
+ // Handle different event types from Converse API
1504
+ if (event.contentBlockDelta) {
1505
+ const delta = event.contentBlockDelta.delta;
1506
+ const contentIndex = event.contentBlockDelta.contentBlockIndex;
1507
+ if (delta?.text) {
1508
+ const text = delta.text;
1509
+ fullMessage += text;
1510
+ tokenCount++;
1511
+ if (firstTokenTime === 0) {
1512
+ firstTokenTime = Date.now() - startTime;
1513
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1514
+ console.log(`⚡ [Bedrock] Time to First Token: ${firstTokenTime}ms`);
1515
+ }
1516
+ }
1517
+ onEvent({
1518
+ type: "token",
1519
+ token: text,
1520
+ });
1521
+ onEvent({
1522
+ type: "message",
1523
+ message: fullMessage,
1524
+ });
1525
+ }
1526
+ else if (delta?.toolUse) {
1527
+ // Handle tool use input delta
1528
+ if (delta.toolUse.input && contentIndex !== undefined) {
1529
+ // Find the corresponding tool call by index
1530
+ // Bedrock uses contentBlockIndex to correlate deltas with their starts
1531
+ const toolCall = toolCallsByIndex.get(contentIndex);
1532
+ if (toolCall) {
1533
+ toolCall.arguments += delta.toolUse.input;
1534
+ }
1535
+ }
1536
+ }
1537
+ }
1538
+ else if (event.contentBlockStart) {
1539
+ // Handle tool use start
1540
+ const start = event.contentBlockStart.start;
1541
+ const startIndex = event.contentBlockStart.contentBlockIndex;
1542
+ if (start?.toolUse && startIndex !== undefined) {
1543
+ const toolUse = start.toolUse;
1544
+ const id = toolUse.toolUseId || `tool_${Date.now()}_${toolCalls.length}`;
1545
+ // Initialize the tool call
1546
+ const toolCall = {
1547
+ id,
1548
+ name: toolUse.name || "",
1549
+ arguments: "",
1550
+ };
1551
+ // Store in both array and map
1552
+ toolCalls.push(toolCall);
1553
+ toolCallsByIndex.set(startIndex, toolCall);
1554
+ onEvent({
1555
+ type: "tool_call_start",
1556
+ toolCall: { id, name: toolUse.name || "" },
1557
+ });
1558
+ }
1559
+ }
1560
+ else if (event.contentBlockStop) {
1561
+ // Handle tool use completion
1562
+ const stopIndex = event.contentBlockStop.contentBlockIndex;
1563
+ if (stopIndex !== undefined) {
1564
+ const toolCall = toolCallsByIndex.get(stopIndex);
1565
+ if (toolCall) {
1566
+ // Emit tool_call_parsed event when tool arguments are complete
1567
+ onEvent({
1568
+ type: "tool_call_parsed",
1569
+ toolCall: toolCall,
1570
+ });
1571
+ }
1572
+ }
1573
+ }
1574
+ else if (event.metadata) {
1575
+ // Metadata events contain usage information
1576
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1577
+ console.log(`📊 [Bedrock] Metadata:`, event.metadata);
1578
+ }
1579
+ }
1580
+ }
1581
+ }
1582
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1583
+ console.log(`✅ [Bedrock] Complete. Total tokens: ${tokenCount} | Message length: ${fullMessage.length}`);
1584
+ }
1585
+ onEvent({
1586
+ type: "complete",
1587
+ tokens: tokenCount,
1588
+ });
1589
+ onComplete(fullMessage, toolCalls);
1590
+ }
1591
+ catch (error) {
1592
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1593
+ console.error(`❌ [Bedrock] Stream error:`, error);
1594
+ }
1595
+ onEvent({
1596
+ type: "error",
1597
+ error: `Bedrock streaming error: ${error}`,
1598
+ });
1599
+ throw error;
1600
+ }
1601
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20250613009",
3
+ "version": "1.0.20250615001",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",
@@ -65,11 +65,27 @@
65
65
  },
66
66
  "@google/generative-ai": {
67
67
  "optional": true
68
+ },
69
+ "groq-sdk": {
70
+ "optional": true
71
+ },
72
+ "cohere-ai": {
73
+ "optional": true
74
+ },
75
+ "@mistralai/mistralai": {
76
+ "optional": true
77
+ },
78
+ "@aws-sdk/client-bedrock-runtime": {
79
+ "optional": true
68
80
  }
69
81
  },
70
82
  "optionalDependencies": {
71
83
  "@anthropic-ai/sdk": "^0.53.0",
84
+ "@aws-sdk/client-bedrock-runtime": "^3.828.0",
72
85
  "@google/generative-ai": "^0.24.1",
86
+ "@mistralai/mistralai": "^1.7.2",
87
+ "cohere-ai": "^7.17.1",
88
+ "groq-sdk": "^0.25.0",
73
89
  "openai": "^5.3.0"
74
90
  },
75
91
  "devDependencies": {