graphlit-client 1.0.20260626003 → 1.0.20260626005

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
@@ -8,10 +8,20 @@ import { attachPartialErrors } from "./partial-errors.js";
8
8
  import * as Types from "./generated/graphql-types.js";
9
9
  import * as Documents from "./generated/graphql-documents.js";
10
10
  import { getServiceType, getModelName, getModelEnum, isAnthropicAdaptiveThinkingOnlyModel, isOpenAIResponsesEligibleModel, } from "./model-mapping.js";
11
+ class StreamingLoopPartialError extends Error {
12
+ originalError;
13
+ partialResult;
14
+ constructor(error, partialResult) {
15
+ super(error instanceof Error ? error.message : String(error));
16
+ this.name = "StreamingLoopPartialError";
17
+ this.originalError = error;
18
+ this.partialResult = partialResult;
19
+ }
20
+ }
11
21
  import { StuckDetector } from "./helpers/stuck-detector.js";
12
22
  import { TurnEvaluator } from "./helpers/turn-evaluator.js";
13
23
  import { TokenBudgetTracker, truncateToolResult, windowToolRounds, estimateTokens, DEFAULT_CONTEXT_STRATEGY, } from "./helpers/context-management.js";
14
- import { assertRequiredToolChoiceConfig, deriveProviderToolChoicePolicy, normalizeToolVisibilityResult, toAnthropicToolChoice, toGoogleToolConfig, toOpenAIChatToolChoice, toOpenAIResponsesToolChoice, validateRequiredToolChoice, } from "./helpers/tool-visibility.js";
24
+ import { assertRequiredToolChoiceConfig, deriveProviderToolChoicePolicy, normalizeToolVisibilityResult, RequiredToolChoiceError, toAnthropicToolChoice, toGoogleToolConfig, toOpenAIChatToolChoice, toOpenAIResponsesToolChoice, validateRequiredToolChoice, } from "./helpers/tool-visibility.js";
15
25
  import { isRetryableGraphQLTransportError, ProviderError, } from "./types/internal.js";
16
26
  import { UIEventAdapter } from "./streaming/ui-event-adapter.js";
17
27
  import { formatMessagesForOpenAI, formatMessagesForOpenAIResponsesInitialRound, extractInstructionsForOpenAIResponses, extractSystemInstructionParts, buildResponsesFunctionCallOutputItems, formatToolsForOpenAIResponses, formatMessagesForAnthropic, formatMessagesForGoogle, formatMessagesForMistral, formatMessagesForBedrock, } from "./streaming/llm-formatters.js";
@@ -133,6 +143,15 @@ function normalizeToolCallForExecution(toolCall) {
133
143
  firstStatusAt: toolCall.firstStatusAt ?? undefined,
134
144
  };
135
145
  }
146
+ function cloneOpenAIResponsesInvocationState(state) {
147
+ if (!state)
148
+ return undefined;
149
+ return {
150
+ instructions: state.instructions,
151
+ initialInput: [...state.initialInput],
152
+ continuationItems: [...state.continuationItems],
153
+ };
154
+ }
136
155
  // Default eligible OpenAI GPT-5.4+ models to Responses. Explicit
137
156
  // `useResponsesApi: false` still forces legacy Chat Completions.
138
157
  const OPENAI_RESPONSES_AUTO_ROUTING_ENABLED = true;
@@ -6357,33 +6376,55 @@ class Graphlit {
6357
6376
  DEFAULT_CONTEXT_STRATEGY.rebudgetThreshold,
6358
6377
  };
6359
6378
  // Run the streaming loop
6360
- const loopResult = await this.executeStreamingLoop({
6361
- conversationId,
6362
- specification,
6363
- messages,
6364
- tools,
6365
- toolHandlers,
6366
- uiAdapter,
6367
- budgetTracker,
6368
- contextStrategy: mergedStrategy,
6369
- maxRounds,
6370
- abortSignal,
6371
- useResponsesApi,
6372
- correlationId,
6373
- persona,
6374
- mimeType,
6375
- data,
6376
- additionalSystemInstructions,
6377
- fallbackSpecifications,
6378
- resolveTools,
6379
- turnNumber: 0,
6380
- initialToolCallCount: 0,
6381
- initialPreviousToolCallNames: [],
6382
- });
6379
+ let loopResult;
6380
+ let loopOriginalError;
6381
+ let loopErrorMessage;
6382
+ try {
6383
+ loopResult = await this.executeStreamingLoop({
6384
+ conversationId,
6385
+ specification,
6386
+ messages,
6387
+ tools,
6388
+ toolHandlers,
6389
+ uiAdapter,
6390
+ budgetTracker,
6391
+ contextStrategy: mergedStrategy,
6392
+ maxRounds,
6393
+ abortSignal,
6394
+ useResponsesApi,
6395
+ correlationId,
6396
+ persona,
6397
+ mimeType,
6398
+ data,
6399
+ additionalSystemInstructions,
6400
+ fallbackSpecifications,
6401
+ resolveTools,
6402
+ turnNumber: 0,
6403
+ initialToolCallCount: 0,
6404
+ initialPreviousToolCallNames: [],
6405
+ });
6406
+ }
6407
+ catch (loopError) {
6408
+ if (loopError instanceof StreamingLoopPartialError) {
6409
+ loopResult = loopError.partialResult;
6410
+ loopOriginalError = loopError.originalError;
6411
+ loopErrorMessage =
6412
+ loopError.originalError instanceof Error
6413
+ ? loopError.originalError.message
6414
+ : String(loopError.originalError);
6415
+ }
6416
+ else {
6417
+ throw loopError;
6418
+ }
6419
+ }
6383
6420
  // Complete the conversation and get token count
6384
6421
  let finalTokens;
6385
6422
  const trimmedMessage = loopResult.finalAssistantMessage;
6386
- if (trimmedMessage) {
6423
+ const shouldPersistTurn = trimmedMessage ||
6424
+ (loopErrorMessage && loopResult.intermediateMessages.length > 0);
6425
+ if (shouldPersistTurn) {
6426
+ const completionMessage = trimmedMessage ||
6427
+ `Agent run failed after partial tool execution: ${loopErrorMessage ?? "Unknown error"}`;
6387
6428
  // Calculate metrics for completeConversation
6388
6429
  const completionTime = uiAdapter.getCompletionTime();
6389
6430
  const ttft = uiAdapter.getTTFT();
@@ -6402,11 +6443,13 @@ class Graphlit {
6402
6443
  : undefined;
6403
6444
  const finalInputMessage = finalMessageInputs?.[finalMessageInputs.length - 1];
6404
6445
  const finalMessageAlreadyIncluded = finalInputMessage?.role === Types.ConversationRoleTypes.Assistant &&
6405
- finalInputMessage.message?.trim() === trimmedMessage;
6406
- if (loopResult.lastRoundReasoning && !finalMessageAlreadyIncluded) {
6446
+ finalInputMessage.message?.trim() === completionMessage;
6447
+ if (trimmedMessage &&
6448
+ loopResult.lastRoundReasoning &&
6449
+ !finalMessageAlreadyIncluded) {
6407
6450
  const completionInput = {
6408
6451
  role: Types.ConversationRoleTypes.Assistant,
6409
- message: trimmedMessage,
6452
+ message: completionMessage,
6410
6453
  timestamp: new Date().toISOString(),
6411
6454
  thinkingContent: loopResult.lastRoundReasoning.content,
6412
6455
  };
@@ -6416,13 +6459,16 @@ class Graphlit {
6416
6459
  }
6417
6460
  finalMessageInputs = [...(finalMessageInputs || []), completionInput];
6418
6461
  }
6419
- const completeResponse = await this.completeConversation(trimmedMessage, conversationId, millisecondsToTimeSpan(completionTime), millisecondsToTimeSpan(ttft), throughput, collectedArtifacts.length > 0 ? collectedArtifacts : undefined, finalMessageInputs, correlationId);
6462
+ const completeResponse = await this.completeConversation(completionMessage, conversationId, millisecondsToTimeSpan(completionTime), millisecondsToTimeSpan(ttft), throughput, collectedArtifacts.length > 0 ? collectedArtifacts : undefined, finalMessageInputs, correlationId);
6420
6463
  finalTokens =
6421
6464
  completeResponse.completeConversation?.message?.tokens ?? undefined;
6422
6465
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6423
6466
  console.log(`📊 [completeConversation] Tokens used: ${finalTokens || "unknown"}`);
6424
6467
  }
6425
6468
  }
6469
+ if (loopOriginalError) {
6470
+ throw loopOriginalError;
6471
+ }
6426
6472
  if (loopResult.usage) {
6427
6473
  uiAdapter.setUsageData(loopResult.usage);
6428
6474
  }
@@ -6479,6 +6525,59 @@ class Graphlit {
6479
6525
  let openAIResponsesState;
6480
6526
  let openAIResponsesPendingToolMessages = [];
6481
6527
  let visibleToolsForCurrentRound = tools;
6528
+ const buildIntermediateMessageInputs = () => persistedIntermediateMessages.map((msg) => {
6529
+ const input = {
6530
+ role: msg.role,
6531
+ message: msg.message,
6532
+ timestamp: msg.timestamp,
6533
+ };
6534
+ if (msg.toolCallId)
6535
+ input.toolCallId = msg.toolCallId;
6536
+ if (msg.toolCalls) {
6537
+ input.toolCalls = msg.toolCalls
6538
+ .filter((tc) => tc !== null)
6539
+ .map((tc) => ({
6540
+ id: tc.id,
6541
+ name: tc.name,
6542
+ arguments: tc.arguments,
6543
+ startedAt: tc.startedAt,
6544
+ completedAt: tc.completedAt,
6545
+ durationMs: tc.durationMs,
6546
+ status: tc.status,
6547
+ failedAt: tc.failedAt,
6548
+ firstStatusAt: tc.firstStatusAt,
6549
+ }));
6550
+ }
6551
+ if (msg.thinkingContent) {
6552
+ input.thinkingContent = msg.thinkingContent;
6553
+ if (msg.thinkingSignature) {
6554
+ input.thinkingSignature = msg.thinkingSignature;
6555
+ }
6556
+ }
6557
+ return input;
6558
+ });
6559
+ const buildLoopResult = () => ({
6560
+ fullMessage,
6561
+ finalAssistantMessage,
6562
+ toolCallCount: totalToolCallCount,
6563
+ toolCallNames,
6564
+ errors,
6565
+ contextWindow: budgetTracker?.getUsageSnapshot(),
6566
+ contextActions,
6567
+ reasoning: lastRoundReasoning,
6568
+ intermediateMessages: buildIntermediateMessageInputs(),
6569
+ lastRoundReasoning,
6570
+ usedSpecification: specification,
6571
+ usage: (accumulatedUsage.rounds?.length ?? 0) > 0
6572
+ ? accumulatedUsage
6573
+ : undefined,
6574
+ });
6575
+ const throwWithPartialResult = (error) => {
6576
+ if (persistedIntermediateMessages.length > 0) {
6577
+ throw new StreamingLoopPartialError(error, buildLoopResult());
6578
+ }
6579
+ throw error;
6580
+ };
6482
6581
  const selectNextStreamingSpecification = (reason) => {
6483
6582
  for (let candidateIndex = currentSpecificationIndex + 1; candidateIndex < streamingSpecifications.length; candidateIndex++) {
6484
6583
  const candidate = streamingSpecifications[candidateIndex];
@@ -6588,6 +6687,7 @@ class Graphlit {
6588
6687
  roundMessage = "";
6589
6688
  roundReasoning = undefined;
6590
6689
  roundUsage = undefined;
6690
+ const preAttemptOpenAIResponsesState = cloneOpenAIResponsesInvocationState(openAIResponsesState);
6591
6691
  try {
6592
6692
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6593
6693
  console.log(`\n🔀 [Streaming Decision] Service: ${serviceType}, Round: ${currentRound}${providerAttempt > 0 ? `, Retry: ${providerAttempt}` : ""}`);
@@ -6611,10 +6711,7 @@ class Graphlit {
6611
6711
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING_MESSAGES) {
6612
6712
  console.log(`🔍 [OpenAI Responses] Sending ${openAIResponsesState.initialInput.length} initial items and ${openAIResponsesState.continuationItems.length} continuation items`);
6613
6713
  }
6614
- const responsesResult = await this.streamWithOpenAIResponses(specification, messages, openAIResponsesPendingToolMessages, visibleToolsForCurrentRound, uiAdapter, abortSignal, openAIResponsesState, toOpenAIResponsesToolChoice(providerToolChoicePolicy) ??
6615
- (currentRound === 0 && visibleToolsForCurrentRound?.length
6616
- ? "required"
6617
- : undefined));
6714
+ const responsesResult = await this.streamWithOpenAIResponses(specification, messages, openAIResponsesPendingToolMessages, visibleToolsForCurrentRound, uiAdapter, abortSignal, openAIResponsesState, toOpenAIResponsesToolChoice(providerToolChoicePolicy));
6618
6715
  roundMessage = responsesResult.message;
6619
6716
  toolCalls = responsesResult.toolCalls;
6620
6717
  openAIResponsesState = responsesResult.state;
@@ -6891,6 +6988,17 @@ class Graphlit {
6891
6988
  catch (retryError) {
6892
6989
  if (abortSignal?.aborted)
6893
6990
  throw retryError;
6991
+ if (retryError instanceof RequiredToolChoiceError) {
6992
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6993
+ console.log(`\n🔁 [Required Tool] ${retryError.message} Re-asking round ${currentRound} with the same visibility policy (attempt ${providerAttempt + 1}/${DEFAULT_PROVIDER_RETRIES + 1}).`);
6994
+ }
6995
+ uiAdapter.resetForRetry(preRoundMessage);
6996
+ openAIResponsesState = cloneOpenAIResponsesInvocationState(preAttemptOpenAIResponsesState);
6997
+ if (providerAttempt >= DEFAULT_PROVIDER_RETRIES) {
6998
+ throwWithPartialResult(retryError);
6999
+ }
7000
+ continue;
7001
+ }
6894
7002
  const isRetryable = retryError instanceof ProviderError && retryError.retryable;
6895
7003
  if (isRetryable &&
6896
7004
  providerAttempt >= DEFAULT_PROVIDER_RETRIES &&
@@ -6900,17 +7008,19 @@ class Graphlit {
6900
7008
  continue;
6901
7009
  }
6902
7010
  if (!isRetryable || providerAttempt >= DEFAULT_PROVIDER_RETRIES) {
6903
- throw retryError;
7011
+ throwWithPartialResult(retryError);
6904
7012
  }
6905
7013
  // Exponential backoff with jitter
6906
7014
  const delay = Math.min(PROVIDER_RETRY_BASE_DELAY_MS * Math.pow(2, providerAttempt), PROVIDER_RETRY_MAX_DELAY_MS);
6907
7015
  const jitter = Math.random() * delay * 0.1;
6908
7016
  const totalDelay = Math.round(delay + jitter);
7017
+ const providerError = retryError;
6909
7018
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6910
- console.log(`\n🔄 [Retry] ${retryError.provider} error (attempt ${providerAttempt + 1}/${DEFAULT_PROVIDER_RETRIES}): ${retryError.message}. Retrying in ${totalDelay}ms...`);
7019
+ console.log(`\n🔄 [Retry] ${providerError.provider} error (attempt ${providerAttempt + 1}/${DEFAULT_PROVIDER_RETRIES}): ${providerError.message}. Retrying in ${totalDelay}ms...`);
6911
7020
  }
6912
7021
  // Reset adapter to pre-round state so partial tokens are cleared
6913
7022
  uiAdapter.resetForRetry(preRoundMessage);
7023
+ openAIResponsesState = cloneOpenAIResponsesInvocationState(preAttemptOpenAIResponsesState);
6914
7024
  await new Promise((resolve) => setTimeout(resolve, totalDelay));
6915
7025
  }
6916
7026
  } // end retry for-loop
@@ -7297,55 +7407,7 @@ class Graphlit {
7297
7407
  }
7298
7408
  currentRound++;
7299
7409
  }
7300
- // Build intermediate messages for completeConversation
7301
- const intermediateMessages = persistedIntermediateMessages;
7302
- const messageInputs = intermediateMessages.map((msg, idx) => {
7303
- const input = {
7304
- role: msg.role,
7305
- message: msg.message,
7306
- timestamp: msg.timestamp,
7307
- };
7308
- if (msg.toolCallId)
7309
- input.toolCallId = msg.toolCallId;
7310
- if (msg.toolCalls) {
7311
- input.toolCalls = msg.toolCalls
7312
- .filter((tc) => tc !== null)
7313
- .map((tc) => ({
7314
- id: tc.id,
7315
- name: tc.name,
7316
- arguments: tc.arguments,
7317
- startedAt: tc.startedAt,
7318
- completedAt: tc.completedAt,
7319
- durationMs: tc.durationMs,
7320
- status: tc.status,
7321
- failedAt: tc.failedAt,
7322
- firstStatusAt: tc.firstStatusAt,
7323
- }));
7324
- }
7325
- if (msg.thinkingContent) {
7326
- input.thinkingContent = msg.thinkingContent;
7327
- if (msg.thinkingSignature) {
7328
- input.thinkingSignature = msg.thinkingSignature;
7329
- }
7330
- }
7331
- return input;
7332
- });
7333
- return {
7334
- fullMessage,
7335
- finalAssistantMessage,
7336
- toolCallCount: totalToolCallCount,
7337
- toolCallNames,
7338
- errors,
7339
- contextWindow: budgetTracker?.getUsageSnapshot(),
7340
- contextActions,
7341
- reasoning: lastRoundReasoning,
7342
- intermediateMessages: messageInputs,
7343
- lastRoundReasoning,
7344
- usedSpecification: specification,
7345
- usage: (accumulatedUsage.rounds?.length ?? 0) > 0
7346
- ? accumulatedUsage
7347
- : undefined,
7348
- };
7410
+ return buildLoopResult();
7349
7411
  }
7350
7412
  // ────────────────────────────────────────────────────────────────────────────
7351
7413
  // runAgent — multi-turn agent harness
@@ -7770,6 +7832,7 @@ class Graphlit {
7770
7832
  // 7. Execute streaming loop for this turn
7771
7833
  const turnStart = Date.now();
7772
7834
  let loopResult;
7835
+ let loopErrorMessage;
7773
7836
  try {
7774
7837
  loopResult = await this.executeStreamingLoop({
7775
7838
  conversationId,
@@ -7793,6 +7856,18 @@ class Graphlit {
7793
7856
  initialPreviousToolCallNames: turnResults.flatMap((t) => t.toolCalls),
7794
7857
  });
7795
7858
  }
7859
+ catch (loopError) {
7860
+ if (loopError instanceof StreamingLoopPartialError) {
7861
+ loopResult = loopError.partialResult;
7862
+ loopErrorMessage =
7863
+ loopError.originalError instanceof Error
7864
+ ? loopError.originalError.message
7865
+ : String(loopError.originalError);
7866
+ }
7867
+ else {
7868
+ throw loopError;
7869
+ }
7870
+ }
7796
7871
  finally {
7797
7872
  uiAdapter.dispose();
7798
7873
  }
@@ -7805,8 +7880,12 @@ class Graphlit {
7805
7880
  const taskCompleteThisTurn = this.detectTaskCompleteInMessages(loopResult.intermediateMessages);
7806
7881
  const terminalTextThisTurn = this.detectTerminalTextCompletion(loopResult, options?.completionMode);
7807
7882
  const trimmedMessage = loopResult.finalAssistantMessage;
7883
+ const shouldPersistTurn = trimmedMessage ||
7884
+ (loopErrorMessage && loopResult.intermediateMessages.length > 0);
7808
7885
  // 8b. Complete conversation (persist turn)
7809
- if (trimmedMessage) {
7886
+ if (shouldPersistTurn) {
7887
+ const completionMessage = trimmedMessage ||
7888
+ `Agent run failed after partial tool execution: ${loopErrorMessage ?? "Unknown error"}`;
7810
7889
  const completionTime = uiAdapter.getCompletionTime();
7811
7890
  const ttft = uiAdapter.getTTFT();
7812
7891
  const throughput = uiAdapter.getThroughput();
@@ -7830,11 +7909,13 @@ class Graphlit {
7830
7909
  }
7831
7910
  const finalInputMessage = turnMessageInputs?.[turnMessageInputs.length - 1];
7832
7911
  const finalMessageAlreadyIncluded = finalInputMessage?.role === Types.ConversationRoleTypes.Assistant &&
7833
- finalInputMessage.message?.trim() === trimmedMessage;
7834
- if (loopResult.lastRoundReasoning && !finalMessageAlreadyIncluded) {
7912
+ finalInputMessage.message?.trim() === completionMessage;
7913
+ if (trimmedMessage &&
7914
+ loopResult.lastRoundReasoning &&
7915
+ !finalMessageAlreadyIncluded) {
7835
7916
  const completionInput = {
7836
7917
  role: Types.ConversationRoleTypes.Assistant,
7837
- message: trimmedMessage,
7918
+ message: completionMessage,
7838
7919
  timestamp: new Date().toISOString(),
7839
7920
  thinkingContent: loopResult.lastRoundReasoning.content,
7840
7921
  };
@@ -7844,7 +7925,7 @@ class Graphlit {
7844
7925
  }
7845
7926
  turnMessageInputs = [...(turnMessageInputs || []), completionInput];
7846
7927
  }
7847
- await this.completeConversation(trimmedMessage, conversationId, millisecondsToTimeSpan(completionTime), millisecondsToTimeSpan(ttft), throughput, undefined, turnMessageInputs, options?.correlationId);
7928
+ await this.completeConversation(completionMessage, conversationId, millisecondsToTimeSpan(completionTime), millisecondsToTimeSpan(ttft), throughput, undefined, turnMessageInputs, options?.correlationId);
7848
7929
  // Emit completion event
7849
7930
  uiAdapter.handleEvent({
7850
7931
  type: "complete",
@@ -7854,6 +7935,10 @@ class Graphlit {
7854
7935
  // 9. Build TurnResult
7855
7936
  const turnDuration = Date.now() - turnStart;
7856
7937
  const turnToolNames = [...new Set(loopResult.toolCallNames)].sort();
7938
+ const turnErrors = [
7939
+ ...loopResult.errors,
7940
+ ...(loopErrorMessage ? [loopErrorMessage] : []),
7941
+ ];
7857
7942
  const turnResult = {
7858
7943
  turnNumber: turn,
7859
7944
  prompt: currentPrompt,
@@ -7871,7 +7956,7 @@ class Graphlit {
7871
7956
  contextActions: loopResult.contextActions.length > 0
7872
7957
  ? loopResult.contextActions
7873
7958
  : undefined,
7874
- errors: loopResult.errors.length > 0 ? loopResult.errors : undefined,
7959
+ errors: turnErrors.length > 0 ? turnErrors : undefined,
7875
7960
  usage: lastTurnUsage,
7876
7961
  };
7877
7962
  // Reset per-turn usage for next turn
@@ -7884,6 +7969,11 @@ class Graphlit {
7884
7969
  // 10. Notify callback
7885
7970
  options?.onTurnComplete?.(turnResult);
7886
7971
  // 11. Evaluate turn
7972
+ if (loopErrorMessage) {
7973
+ status = "error";
7974
+ errorMessage = loopErrorMessage;
7975
+ break;
7976
+ }
7887
7977
  // a. Terminal completion reached?
7888
7978
  if (turnResult.completionReason) {
7889
7979
  status = "completed";
@@ -545,7 +545,12 @@ onEvent, onComplete, abortSignal, thinkingConfig, toolChoice) {
545
545
  ...streamConfig.tools[streamConfig.tools.length - 1],
546
546
  cache_control: { type: "ephemeral" },
547
547
  };
548
- if (toolChoice) {
548
+ if (toolChoice && thinkingConfig) {
549
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
550
+ console.log("🧠 [Anthropic] Skipping native tool_choice because thinking is enabled; required tool policy will be validated after the response.");
551
+ }
552
+ }
553
+ else if (toolChoice) {
549
554
  streamConfig.tool_choice = toolChoice;
550
555
  }
551
556
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20260626003",
3
+ "version": "1.0.20260626005",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",