graphlit-client 1.0.20260402001 → 1.0.20260403001

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 CHANGED
@@ -200,6 +200,8 @@ catch (e) {
200
200
  }
201
201
  }
202
202
  const DEFAULT_MAX_TOOL_ROUNDS = 100;
203
+ /** Maximum number of tool calls to execute concurrently within a single streaming round. */
204
+ const DEFAULT_MAX_PARALLEL_TOOL_CALLS = 4;
203
205
  /** Maximum number of retries for transient provider errors (5xx, network, overloaded). */
204
206
  const DEFAULT_PROVIDER_RETRIES = 3;
205
207
  /** Base delay in ms for exponential backoff between provider retries. */
@@ -5873,7 +5875,7 @@ class Graphlit {
5873
5875
  });
5874
5876
  // Complete the conversation and get token count
5875
5877
  let finalTokens;
5876
- const trimmedMessage = loopResult.fullMessage?.trim();
5878
+ const trimmedMessage = loopResult.finalAssistantMessage;
5877
5879
  if (trimmedMessage) {
5878
5880
  // Calculate metrics for completeConversation
5879
5881
  const completionTime = uiAdapter.getCompletionTime();
@@ -5930,6 +5932,7 @@ class Graphlit {
5930
5932
  let messages = config.messages;
5931
5933
  let currentRound = 0;
5932
5934
  let fullMessage = "";
5935
+ let finalAssistantMessage = "";
5933
5936
  const contextActions = [];
5934
5937
  const toolCallNames = [];
5935
5938
  const errors = [];
@@ -6285,6 +6288,9 @@ class Graphlit {
6285
6288
  }
6286
6289
  // Update the full message and capture reasoning for persistence
6287
6290
  fullMessage = roundMessage;
6291
+ if (roundMessage.trim()) {
6292
+ finalAssistantMessage = roundMessage.trim();
6293
+ }
6288
6294
  lastRoundReasoning = roundReasoning;
6289
6295
  // Check abort after streaming completes, before starting tool execution
6290
6296
  if (abortSignal?.aborted) {
@@ -6330,8 +6336,8 @@ class Graphlit {
6330
6336
  roundToolCalls.reduce((sum, tc) => sum + estimateTokens(tc.arguments), 0);
6331
6337
  budgetTracker.addMessage("", assistantTokens);
6332
6338
  }
6333
- // Execute tools and add responses
6334
- for (const toolCall of roundToolCalls) {
6339
+ const toolExecutionResults = new Array(roundToolCalls.length);
6340
+ const executeStreamingToolCall = async (toolCall, index) => {
6335
6341
  if (abortSignal?.aborted) {
6336
6342
  throw new Error("Operation aborted");
6337
6343
  }
@@ -6359,20 +6365,21 @@ class Graphlit {
6359
6365
  },
6360
6366
  error: errorMessage,
6361
6367
  });
6362
- const errorToolMessage = {
6363
- __typename: "ConversationMessage",
6364
- role: Types.ConversationRoleTypes.Tool,
6365
- message: `Error: ${errorMessage}`,
6366
- toolCallId: toolCall.id,
6367
- timestamp: terminalAt,
6368
- toolCallResponse: toolCall.name,
6368
+ const errorText = `Error: ${errorMessage}`;
6369
+ toolExecutionResults[index] = {
6370
+ index,
6371
+ toolMessage: {
6372
+ __typename: "ConversationMessage",
6373
+ role: Types.ConversationRoleTypes.Tool,
6374
+ message: errorText,
6375
+ toolCallId: toolCall.id,
6376
+ timestamp: terminalAt,
6377
+ toolCallResponse: toolCall.name,
6378
+ },
6379
+ budgetText: errorText,
6380
+ errorEntry: `${toolCall.name}: ${errorMessage}`,
6369
6381
  };
6370
- messages.push(errorToolMessage);
6371
- errors.push(`${toolCall.name}: ${errorMessage}`);
6372
- if (budgetTracker) {
6373
- budgetTracker.addMessage(errorToolMessage.message || "");
6374
- }
6375
- continue;
6382
+ return;
6376
6383
  }
6377
6384
  try {
6378
6385
  let args;
@@ -6453,20 +6460,21 @@ class Graphlit {
6453
6460
  },
6454
6461
  error: parseErrorText,
6455
6462
  });
6456
- const errorToolMessage = {
6457
- __typename: "ConversationMessage",
6458
- role: Types.ConversationRoleTypes.Tool,
6459
- message: `Error: ${parseErrorText}`,
6460
- toolCallId: toolCall.id,
6461
- timestamp: terminalAt,
6462
- toolCallResponse: toolCall.name,
6463
+ const errorText = `Error: ${parseErrorText}`;
6464
+ toolExecutionResults[index] = {
6465
+ index,
6466
+ toolMessage: {
6467
+ __typename: "ConversationMessage",
6468
+ role: Types.ConversationRoleTypes.Tool,
6469
+ message: errorText,
6470
+ toolCallId: toolCall.id,
6471
+ timestamp: terminalAt,
6472
+ toolCallResponse: toolCall.name,
6473
+ },
6474
+ budgetText: errorText,
6475
+ errorEntry: parseErrorText,
6463
6476
  };
6464
- messages.push(errorToolMessage);
6465
- errors.push(parseErrorText);
6466
- if (budgetTracker) {
6467
- budgetTracker.addMessage(errorToolMessage.message || "");
6468
- }
6469
- continue;
6477
+ return;
6470
6478
  }
6471
6479
  }
6472
6480
  const executionStartMs = Date.now();
@@ -6504,44 +6512,36 @@ class Graphlit {
6504
6512
  });
6505
6513
  const rawResult = typeof result === "string" ? result : JSON.stringify(result);
6506
6514
  const truncatedResult = truncateToolResult(rawResult, toolResultTokenLimit, toolCall.name);
6515
+ let contextAction;
6507
6516
  if (truncatedResult.length < rawResult.length) {
6508
- const action = {
6517
+ contextAction = {
6509
6518
  type: "truncated_tool_result",
6510
6519
  toolName: toolCall.name,
6511
6520
  originalTokens: estimateTokens(rawResult),
6512
6521
  truncatedTokens: estimateTokens(truncatedResult),
6513
6522
  };
6514
- contextActions.push(action);
6515
- if (budgetTracker) {
6516
- uiAdapter.handleEvent({
6517
- type: "context_management",
6518
- action,
6519
- usage: budgetTracker.getUsageSnapshot(),
6520
- timestamp: new Date(),
6521
- });
6522
- }
6523
6523
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6524
6524
  console.log(`📊 [Context Management] Truncated tool result for ${toolCall.name}: ` +
6525
6525
  `${estimateTokens(rawResult)} → ${estimateTokens(truncatedResult)} tokens`);
6526
6526
  }
6527
6527
  }
6528
- const toolMessage = {
6529
- __typename: "ConversationMessage",
6530
- role: Types.ConversationRoleTypes.Tool,
6531
- message: truncatedResult,
6532
- toolCallId: toolCall.id,
6533
- timestamp: new Date().toISOString(),
6534
- toolCallResponse: toolCall.name,
6528
+ toolExecutionResults[index] = {
6529
+ index,
6530
+ toolMessage: {
6531
+ __typename: "ConversationMessage",
6532
+ role: Types.ConversationRoleTypes.Tool,
6533
+ message: truncatedResult,
6534
+ toolCallId: toolCall.id,
6535
+ timestamp: new Date().toISOString(),
6536
+ toolCallResponse: toolCall.name,
6537
+ },
6538
+ budgetText: truncatedResult,
6539
+ contextAction,
6535
6540
  };
6536
- messages.push(toolMessage);
6537
- if (budgetTracker) {
6538
- budgetTracker.addMessage(truncatedResult);
6539
- }
6540
6541
  }
6541
6542
  catch (error) {
6542
6543
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
6543
6544
  console.error(`Tool execution error for ${toolCall.name}:`, error);
6544
- errors.push(`${toolCall.name}: ${errorMessage}`);
6545
6545
  const completedAt = nowIsoString();
6546
6546
  if (!toolCall.startedAt) {
6547
6547
  toolCall.startedAt = completedAt;
@@ -6567,19 +6567,58 @@ class Graphlit {
6567
6567
  error: errorMessage,
6568
6568
  });
6569
6569
  const errorText = `Error: ${errorMessage}`;
6570
- const errorToolMessage = {
6571
- __typename: "ConversationMessage",
6572
- role: Types.ConversationRoleTypes.Tool,
6573
- message: errorText,
6574
- toolCallId: toolCall.id,
6575
- timestamp: new Date().toISOString(),
6576
- toolCallResponse: toolCall.name,
6570
+ toolExecutionResults[index] = {
6571
+ index,
6572
+ toolMessage: {
6573
+ __typename: "ConversationMessage",
6574
+ role: Types.ConversationRoleTypes.Tool,
6575
+ message: errorText,
6576
+ toolCallId: toolCall.id,
6577
+ timestamp: new Date().toISOString(),
6578
+ toolCallResponse: toolCall.name,
6579
+ },
6580
+ budgetText: errorText,
6581
+ errorEntry: `${toolCall.name}: ${errorMessage}`,
6577
6582
  };
6578
- messages.push(errorToolMessage);
6583
+ }
6584
+ };
6585
+ const workerCount = Math.min(DEFAULT_MAX_PARALLEL_TOOL_CALLS, roundToolCalls.length);
6586
+ let nextToolIndex = 0;
6587
+ await Promise.all(Array.from({ length: workerCount }, async () => {
6588
+ while (true) {
6589
+ if (abortSignal?.aborted) {
6590
+ throw new Error("Operation aborted");
6591
+ }
6592
+ const currentIndex = nextToolIndex;
6593
+ nextToolIndex += 1;
6594
+ if (currentIndex >= roundToolCalls.length) {
6595
+ break;
6596
+ }
6597
+ await executeStreamingToolCall(roundToolCalls[currentIndex], currentIndex);
6598
+ }
6599
+ }));
6600
+ for (const executionResult of toolExecutionResults) {
6601
+ if (!executionResult) {
6602
+ continue;
6603
+ }
6604
+ if (executionResult.contextAction) {
6605
+ contextActions.push(executionResult.contextAction);
6579
6606
  if (budgetTracker) {
6580
- budgetTracker.addMessage(errorText);
6607
+ uiAdapter.handleEvent({
6608
+ type: "context_management",
6609
+ action: executionResult.contextAction,
6610
+ usage: budgetTracker.getUsageSnapshot(),
6611
+ timestamp: new Date(),
6612
+ });
6581
6613
  }
6582
6614
  }
6615
+ messages.push(executionResult.toolMessage);
6616
+ if (executionResult.errorEntry) {
6617
+ errors.push(executionResult.errorEntry);
6618
+ }
6619
+ if (budgetTracker) {
6620
+ budgetTracker.addMessage(executionResult.budgetText);
6621
+ }
6583
6622
  }
6584
6623
  }
6585
6624
  // Emit context window usage after each tool round
@@ -6628,6 +6667,7 @@ class Graphlit {
6628
6667
  });
6629
6668
  return {
6630
6669
  fullMessage,
6670
+ finalAssistantMessage,
6631
6671
  toolCallCount: totalToolCallCount,
6632
6672
  toolCallNames,
6633
6673
  errors,
@@ -7012,7 +7052,7 @@ class Graphlit {
7012
7052
  uiAdapter.dispose();
7013
7053
  }
7014
7054
  // 8. Complete conversation (persist turn)
7015
- const trimmedMessage = loopResult.fullMessage?.trim();
7055
+ const trimmedMessage = loopResult.finalAssistantMessage;
7016
7056
  if (trimmedMessage) {
7017
7057
  const completionTime = uiAdapter.getCompletionTime();
7018
7058
  const ttft = uiAdapter.getTTFT();
@@ -7068,7 +7108,7 @@ class Graphlit {
7068
7108
  };
7069
7109
  turnResults.push(turnResult);
7070
7110
  totalToolCalls += loopResult.toolCallCount;
7071
- finalMessage = loopResult.fullMessage;
7111
+ finalMessage = loopResult.finalAssistantMessage || loopResult.fullMessage;
7072
7112
  lastContextWindow = loopResult.contextWindow;
7073
7113
  // 10. Notify callback
7074
7114
  options?.onTurnComplete?.(turnResult);
@@ -208,6 +208,7 @@ export interface StreamingLoopConfig {
208
208
  /** Result returned from executeStreamingLoop. */
209
209
  export interface StreamingLoopResult {
210
210
  fullMessage: string;
211
+ finalAssistantMessage: string;
211
212
  toolCallCount: number;
212
213
  toolCallNames: string[];
213
214
  errors: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20260402001",
3
+ "version": "1.0.20260403001",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",