graphlit-client 1.0.20260424002 → 1.0.20260424004

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
@@ -3130,6 +3130,7 @@ declare class Graphlit {
3130
3130
  * one for the same conversation, so messages are always processed in order.
3131
3131
  */
3132
3132
  private enqueueForConversation;
3133
+ private resolveSpecificationReferences;
3133
3134
  /**
3134
3135
  * Execute an agent with streaming response
3135
3136
  * @param prompt - The user prompt
package/dist/client.js CHANGED
@@ -164,6 +164,44 @@ function appendSystemMessages(messages, systemPrompt, additionalSystemInstructio
164
164
  });
165
165
  }
166
166
  }
167
+ function toEntityReferenceInput(reference) {
168
+ return reference?.id ? { id: reference.id } : undefined;
169
+ }
170
+ function uniqueEntityReferences(references) {
171
+ const seen = new Set();
172
+ const unique = [];
173
+ for (const reference of references) {
174
+ if (!reference?.id || seen.has(reference.id)) {
175
+ continue;
176
+ }
177
+ seen.add(reference.id);
178
+ unique.push({ id: reference.id });
179
+ }
180
+ return unique;
181
+ }
182
+ function uniqueSpecifications(specifications) {
183
+ const seen = new Set();
184
+ const unique = [];
185
+ for (const specification of specifications) {
186
+ if (!specification?.id || seen.has(specification.id)) {
187
+ continue;
188
+ }
189
+ seen.add(specification.id);
190
+ unique.push(specification);
191
+ }
192
+ return unique;
193
+ }
194
+ function rebuildMessagesForSpecification(messages, specification, additionalSystemInstructions) {
195
+ const rebuilt = [];
196
+ let firstNonSystemIndex = 0;
197
+ while (firstNonSystemIndex < messages.length &&
198
+ messages[firstNonSystemIndex].role === Types.ConversationRoleTypes.System) {
199
+ firstNonSystemIndex++;
200
+ }
201
+ appendSystemMessages(rebuilt, specification.systemPrompt, additionalSystemInstructions);
202
+ rebuilt.push(...messages.slice(firstNonSystemIndex));
203
+ return rebuilt;
204
+ }
167
205
  function computePersistedToolRoundDurationMs(toolCalls) {
168
206
  if (!toolCalls || toolCalls.length === 0) {
169
207
  return undefined;
@@ -5755,6 +5793,19 @@ class Graphlit {
5755
5793
  });
5756
5794
  return next;
5757
5795
  }
5796
+ async resolveSpecificationReferences(references) {
5797
+ const uniqueReferences = uniqueEntityReferences(references ?? []);
5798
+ const specifications = [];
5799
+ for (const reference of uniqueReferences) {
5800
+ const response = await this.getSpecification(reference.id);
5801
+ const specification = response.specification;
5802
+ if (!specification) {
5803
+ throw new Error(`Specification [${reference.id}] not found.`);
5804
+ }
5805
+ specifications.push(specification);
5806
+ }
5807
+ return specifications;
5808
+ }
5758
5809
  /**
5759
5810
  * Execute an agent with streaming response
5760
5811
  * @param prompt - The user prompt
@@ -5784,14 +5835,28 @@ class Graphlit {
5784
5835
  throw new Error("Operation aborted");
5785
5836
  }
5786
5837
  try {
5838
+ let actualConversationId = conversationId;
5839
+ let existingConversation;
5840
+ if (actualConversationId &&
5841
+ specification?.id &&
5842
+ !options?.fallbacks?.length) {
5843
+ existingConversation = (await this.getConversation(actualConversationId))
5844
+ .conversation;
5845
+ }
5846
+ const effectiveSpecification = specification;
5847
+ const conversationFallbacks = existingConversation?.fallbacks
5848
+ ?.map((fallback) => toEntityReferenceInput(fallback))
5849
+ .filter((fallback) => fallback != null) ?? [];
5850
+ const fallbackReferences = uniqueEntityReferences(options?.fallbacks?.length ? options.fallbacks : conversationFallbacks);
5787
5851
  // Get full specification if needed
5788
- const fullSpec = specification?.id
5789
- ? (await this.getSpecification(specification.id))
5852
+ const fullSpec = effectiveSpecification?.id
5853
+ ? (await this.getSpecification(effectiveSpecification.id))
5790
5854
  .specification
5791
5855
  : undefined;
5856
+ const fallbackSpecs = await this.resolveSpecificationReferences(fallbackReferences.filter((fallback) => fallback.id !== effectiveSpecification?.id));
5792
5857
  // Fail fast if a specification was requested but not found
5793
- if (specification?.id && !fullSpec) {
5794
- throw new Error(`Specification [${specification.id}] not found. Cannot fall back to promptAgent.`);
5858
+ if (effectiveSpecification?.id && !fullSpec) {
5859
+ throw new Error(`Specification [${effectiveSpecification.id}] not found. Cannot fall back to promptAgent.`);
5795
5860
  }
5796
5861
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING && fullSpec) {
5797
5862
  console.log(`🔍 [streamAgent] Retrieved full specification:`, {
@@ -5805,11 +5870,13 @@ class Graphlit {
5805
5870
  });
5806
5871
  }
5807
5872
  // Ensure conversation exists first (before streaming check)
5808
- let actualConversationId = conversationId;
5809
5873
  if (!actualConversationId) {
5810
5874
  const createResponse = await this.createConversation({
5811
5875
  name: `Streaming agent conversation`,
5812
- specification: specification,
5876
+ specification: effectiveSpecification,
5877
+ ...(fallbackReferences.length > 0 && {
5878
+ fallbacks: fallbackReferences,
5879
+ }),
5813
5880
  tools: tools,
5814
5881
  filter: contentFilter,
5815
5882
  augmentedFilter: augmentedFilter,
@@ -5832,13 +5899,16 @@ class Graphlit {
5832
5899
  await this.enqueueForConversation(actualConversationId, async () => {
5833
5900
  // Check streaming support - fallback to promptAgent if not supported
5834
5901
  // Also fall back when no specification is provided (can't route to provider locally)
5835
- if (!fullSpec || !this.supportsStreaming(fullSpec, tools)) {
5902
+ const hasStreamingSpecification = !!fullSpec &&
5903
+ (this.supportsStreaming(fullSpec, tools) ||
5904
+ fallbackSpecs.some((fallbackSpec) => this.supportsStreaming(fallbackSpec, tools)));
5905
+ if (!fullSpec || !hasStreamingSpecification) {
5836
5906
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
5837
5907
  console.log(`\n⚠️ [streamAgent] ${!fullSpec ? "No specification provided" : "Streaming not supported"}, falling back to promptAgent with same conversation`);
5838
5908
  }
5839
5909
  // Fallback to promptAgent using the same conversation and parameters
5840
5910
  const promptResult = await this.promptAgent(prompt, actualConversationId, // Preserve conversation
5841
- specification, tools, toolHandlers, {
5911
+ effectiveSpecification, tools, toolHandlers, {
5842
5912
  maxToolRounds: maxRounds,
5843
5913
  }, mimeType, data, contentFilter, augmentedFilter, correlationId, persona);
5844
5914
  // Convert promptAgent result to streaming events
@@ -5905,9 +5975,18 @@ class Graphlit {
5905
5975
  return; // Exit early after successful fallback
5906
5976
  }
5907
5977
  // Create UI event adapter with model information
5908
- const modelName = fullSpec ? getModelName(fullSpec) : undefined;
5909
- const modelEnum = fullSpec ? getModelEnum(fullSpec) : undefined;
5910
- const serviceType = fullSpec ? getServiceType(fullSpec) : undefined;
5978
+ const initialStreamingSpec = this.supportsStreaming(fullSpec, tools)
5979
+ ? fullSpec
5980
+ : fallbackSpecs.find((fallbackSpec) => this.supportsStreaming(fallbackSpec, tools)) || fullSpec;
5981
+ const modelName = initialStreamingSpec
5982
+ ? getModelName(initialStreamingSpec)
5983
+ : undefined;
5984
+ const modelEnum = initialStreamingSpec
5985
+ ? getModelEnum(initialStreamingSpec)
5986
+ : undefined;
5987
+ const serviceType = initialStreamingSpec
5988
+ ? getServiceType(initialStreamingSpec)
5989
+ : undefined;
5911
5990
  uiAdapter = new UIEventAdapter(onEvent, actualConversationId, {
5912
5991
  smoothingEnabled: options?.smoothingEnabled ?? true,
5913
5992
  chunkingStrategy: options?.chunkingStrategy ?? "word",
@@ -5918,7 +5997,7 @@ class Graphlit {
5918
5997
  });
5919
5998
  // Start the streaming conversation
5920
5999
  // fullSpec is guaranteed non-null here — the !fullSpec check above returns early
5921
- await this.executeStreamingAgent(prompt, actualConversationId, fullSpec, tools, toolHandlers, uiAdapter, maxRounds, abortSignal, mimeType, data, correlationId, persona, options?.contextStrategy, options?.useResponsesApi, options?.instructions, options?.scratchpad, options?.skills, cacheableSystemInstructions);
6000
+ await this.executeStreamingAgent(prompt, actualConversationId, fullSpec, tools, toolHandlers, uiAdapter, maxRounds, abortSignal, mimeType, data, correlationId, persona, options?.contextStrategy, options?.useResponsesApi, options?.instructions, options?.scratchpad, options?.skills, cacheableSystemInstructions, fallbackSpecs);
5922
6001
  }, abortSignal);
5923
6002
  }
5924
6003
  catch (error) {
@@ -5964,7 +6043,7 @@ class Graphlit {
5964
6043
  /**
5965
6044
  * Execute the streaming agent workflow with tool calling loop
5966
6045
  */
5967
- async executeStreamingAgent(prompt, conversationId, specification, tools, toolHandlers, uiAdapter, maxRounds, abortSignal, mimeType, data, correlationId, persona, contextStrategy, useResponsesApi, instructions, scratchpad, skills, additionalSystemInstructions) {
6046
+ async executeStreamingAgent(prompt, conversationId, specification, tools, toolHandlers, uiAdapter, maxRounds, abortSignal, mimeType, data, correlationId, persona, contextStrategy, useResponsesApi, instructions, scratchpad, skills, additionalSystemInstructions, fallbackSpecifications) {
5968
6047
  // Collects artifact content IDs from tool handlers (e.g. code_execution).
5969
6048
  // Handlers register async ingestion promises; we await all of them before
5970
6049
  // completeConversation so the IDs are available without blocking the LLM.
@@ -6134,6 +6213,7 @@ class Graphlit {
6134
6213
  mimeType,
6135
6214
  data,
6136
6215
  additionalSystemInstructions,
6216
+ fallbackSpecifications,
6137
6217
  });
6138
6218
  // Complete the conversation and get token count
6139
6219
  let finalTokens;
@@ -6190,8 +6270,19 @@ class Graphlit {
6190
6270
  * Shared between streamAgent (single turn) and runAgent (multi-turn harness).
6191
6271
  */
6192
6272
  async executeStreamingLoop(config) {
6193
- const { conversationId, specification, tools, toolHandlers, uiAdapter, budgetTracker, contextStrategy: { toolResultTokenLimit, toolRoundLimit, rebudgetThreshold, }, maxRounds, abortSignal, useResponsesApi, mimeType, data, correlationId, persona, additionalSystemInstructions, } = config;
6273
+ const { conversationId, specification: initialSpecification, tools, toolHandlers, uiAdapter, budgetTracker, contextStrategy: { toolResultTokenLimit, toolRoundLimit, rebudgetThreshold, }, maxRounds, abortSignal, useResponsesApi, mimeType, data, correlationId, persona, additionalSystemInstructions, fallbackSpecifications, } = config;
6194
6274
  let messages = config.messages;
6275
+ let specification = initialSpecification;
6276
+ const streamingSpecifications = uniqueSpecifications([
6277
+ initialSpecification,
6278
+ ...(fallbackSpecifications ?? []),
6279
+ ]);
6280
+ let currentSpecificationIndex = 0;
6281
+ let serviceType = getServiceType(specification);
6282
+ let useOpenAIResponses = (useResponsesApi === true ||
6283
+ (OPENAI_RESPONSES_AUTO_ROUTING_ENABLED && useResponsesApi !== false)) &&
6284
+ serviceType === Types.ModelServiceTypes.OpenAi &&
6285
+ isOpenAIResponsesEligibleModel(specification);
6195
6286
  let currentRound = 0;
6196
6287
  let fullMessage = "";
6197
6288
  let finalAssistantMessage = "";
@@ -6211,14 +6302,42 @@ class Graphlit {
6211
6302
  return results.filter((r) => r != null);
6212
6303
  },
6213
6304
  };
6214
- const serviceType = getServiceType(specification);
6215
- const useOpenAIResponses = (useResponsesApi === true ||
6216
- (OPENAI_RESPONSES_AUTO_ROUTING_ENABLED && useResponsesApi !== false)) &&
6217
- serviceType === Types.ModelServiceTypes.OpenAi &&
6218
- isOpenAIResponsesEligibleModel(specification);
6219
6305
  let lastRoundReasoning;
6220
6306
  let openAIResponsesState;
6221
6307
  let openAIResponsesPendingToolMessages = [];
6308
+ const selectNextStreamingSpecification = (reason) => {
6309
+ for (let candidateIndex = currentSpecificationIndex + 1; candidateIndex < streamingSpecifications.length; candidateIndex++) {
6310
+ const candidate = streamingSpecifications[candidateIndex];
6311
+ if (!this.supportsStreaming(candidate, tools)) {
6312
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6313
+ console.log(`\n⚠️ [Failover] Skipping fallback specification ${candidate.name} (${candidate.id}) because native streaming is not available`);
6314
+ }
6315
+ continue;
6316
+ }
6317
+ currentSpecificationIndex = candidateIndex;
6318
+ specification = candidate;
6319
+ serviceType = getServiceType(specification);
6320
+ useOpenAIResponses =
6321
+ (useResponsesApi === true ||
6322
+ (OPENAI_RESPONSES_AUTO_ROUTING_ENABLED &&
6323
+ useResponsesApi !== false)) &&
6324
+ serviceType === Types.ModelServiceTypes.OpenAi &&
6325
+ isOpenAIResponsesEligibleModel(specification);
6326
+ messages = rebuildMessagesForSpecification(messages, specification, additionalSystemInstructions);
6327
+ openAIResponsesState = undefined;
6328
+ openAIResponsesPendingToolMessages = [];
6329
+ uiAdapter.setModelInfo({
6330
+ model: getModelEnum(specification),
6331
+ modelName: getModelName(specification),
6332
+ modelService: getServiceType(specification),
6333
+ });
6334
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6335
+ console.log(`\n🔁 [Failover] Switching streaming provider after ${reason} | Spec: ${specification.name} (${specification.id}) | Service: ${serviceType}`);
6336
+ }
6337
+ return true;
6338
+ }
6339
+ return false;
6340
+ };
6222
6341
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING && budgetTracker) {
6223
6342
  console.log(`📊 [Context Management] Initialized budget tracker: ${budgetTracker.usagePercent}% used, ` +
6224
6343
  `${budgetTracker.remaining.toLocaleString()} tokens remaining. ` +
@@ -6542,9 +6661,15 @@ class Graphlit {
6542
6661
  }
6543
6662
  }
6544
6663
  else {
6664
+ const unsupportedServiceType = serviceType;
6665
+ if (selectNextStreamingSpecification(`no native streaming available for ${unsupportedServiceType}`)) {
6666
+ uiAdapter.resetForRetry(preRoundMessage);
6667
+ providerAttempt = -1;
6668
+ continue;
6669
+ }
6545
6670
  // Fallback to non-streaming
6546
6671
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
6547
- console.log(`\n⚠️ [Fallback] No native streaming available for ${serviceType} (Round ${currentRound})`);
6672
+ console.log(`\n⚠️ [Fallback] No native streaming available for ${unsupportedServiceType} (Round ${currentRound})`);
6548
6673
  console.log(` Falling back to non-streaming promptConversation`);
6549
6674
  console.log(` This should NOT happen if clients are properly set!`);
6550
6675
  }
@@ -6561,6 +6686,13 @@ class Graphlit {
6561
6686
  if (abortSignal?.aborted)
6562
6687
  throw retryError;
6563
6688
  const isRetryable = retryError instanceof ProviderError && retryError.retryable;
6689
+ if (isRetryable &&
6690
+ providerAttempt >= DEFAULT_PROVIDER_RETRIES &&
6691
+ selectNextStreamingSpecification(`${retryError.provider} retry exhaustion: ${retryError.message}`)) {
6692
+ uiAdapter.resetForRetry(preRoundMessage);
6693
+ providerAttempt = -1;
6694
+ continue;
6695
+ }
6564
6696
  if (!isRetryable || providerAttempt >= DEFAULT_PROVIDER_RETRIES) {
6565
6697
  throw retryError;
6566
6698
  }
@@ -6999,6 +7131,7 @@ class Graphlit {
6999
7131
  reasoning: lastRoundReasoning,
7000
7132
  intermediateMessages: messageInputs,
7001
7133
  lastRoundReasoning,
7134
+ usedSpecification: specification,
7002
7135
  };
7003
7136
  }
7004
7137
  // ────────────────────────────────────────────────────────────────────────────
@@ -7127,6 +7260,8 @@ class Graphlit {
7127
7260
  ? (await this.getSpecification(agentSpec.id))
7128
7261
  .specification
7129
7262
  : undefined;
7263
+ let activeFullSpec = fullSpec;
7264
+ let fallbackReferences = [];
7130
7265
  // Initialize evaluator and stuck detector
7131
7266
  const evaluator = new TurnEvaluator({
7132
7267
  maxTurns,
@@ -7192,7 +7327,6 @@ class Graphlit {
7192
7327
  filter: agentFilter,
7193
7328
  persona: options?.persona,
7194
7329
  augmentedFilter: options?.augmentedFilter,
7195
- fallbacks: options?.fallbacks,
7196
7330
  }, options?.correlationId);
7197
7331
  conversationId = createResponse.createConversation?.id ?? "";
7198
7332
  if (!conversationId) {
@@ -7203,6 +7337,9 @@ class Graphlit {
7203
7337
  // Resume: reconstruct TurnResults from conversation history so the
7204
7338
  // stuck detector has full context from prior turns.
7205
7339
  const convResponse = await this.getConversation(conversationId);
7340
+ fallbackReferences = uniqueEntityReferences(convResponse.conversation?.fallbacks
7341
+ ?.map((fallback) => toEntityReferenceInput(fallback))
7342
+ .filter((fallback) => fallback != null) ?? []);
7206
7343
  const existingMessages = convResponse.conversation?.messages;
7207
7344
  if (existingMessages && existingMessages.length > 0) {
7208
7345
  const resumedTurns = this.reconstructTurnResults(existingMessages);
@@ -7214,6 +7351,7 @@ class Graphlit {
7214
7351
  }
7215
7352
  }
7216
7353
  }
7354
+ const fallbackSpecs = await this.resolveSpecificationReferences(fallbackReferences.filter((fallback) => fallback.id !== fullSpec?.id));
7217
7355
  // ── Phase 2: The Loop ──────────────────────────────────────────────
7218
7356
  let pendingStuckIntervention;
7219
7357
  let currentPrompt = prompt;
@@ -7279,7 +7417,7 @@ class Graphlit {
7279
7417
  // Bare fast-path: skip formatConversation, reuse cached token limits
7280
7418
  // Build message from last turn's context
7281
7419
  // The messages array is rebuilt from the conversation state
7282
- const bareMessages = this.buildBareMessages(fullSpec, turnResults, currentPrompt, options?.additionalSystemInstructions);
7420
+ const bareMessages = this.buildBareMessages(activeFullSpec, turnResults, currentPrompt, options?.additionalSystemInstructions);
7283
7421
  loopMessages = bareMessages;
7284
7422
  // Estimate tokens from the messages
7285
7423
  const usedTokens = loopMessages.reduce((sum, msg) => sum + estimateTokens(msg.message || ""), 0);
@@ -7287,7 +7425,7 @@ class Graphlit {
7287
7425
  }
7288
7426
  else {
7289
7427
  // Formatted path: call formatConversation
7290
- const formatResponse = await this.formatConversation(turn === 0 ? prompt : "Continue.", conversationId, agentSpec, allTools, undefined, true, options?.correlationId, options?.persona, mergedInstructions, agentScratchpad, options?.skills);
7428
+ const formatResponse = await this.formatConversation(turn === 0 ? prompt : "Continue.", conversationId, activeFullSpec ? { id: activeFullSpec.id } : agentSpec, allTools, undefined, true, options?.correlationId, options?.persona, mergedInstructions, agentScratchpad, options?.skills);
7291
7429
  const formattedMessage = formatResponse.formatConversation?.message;
7292
7430
  const conversationHistory = formatResponse.formatConversation?.details?.messages;
7293
7431
  const formatDetails = formatResponse.formatConversation?.details;
@@ -7302,7 +7440,7 @@ class Graphlit {
7302
7440
  }
7303
7441
  // Build messages from format response
7304
7442
  loopMessages = [];
7305
- appendSystemMessages(loopMessages, fullSpec?.systemPrompt, options?.additionalSystemInstructions);
7443
+ appendSystemMessages(loopMessages, activeFullSpec?.systemPrompt, options?.additionalSystemInstructions);
7306
7444
  if (conversationHistory && conversationHistory.length > 0) {
7307
7445
  for (const historyMessage of conversationHistory) {
7308
7446
  if (historyMessage) {
@@ -7361,9 +7499,15 @@ class Graphlit {
7361
7499
  }
7362
7500
  }
7363
7501
  // 6. Create UI adapter for this turn
7364
- const modelName = fullSpec ? getModelName(fullSpec) : undefined;
7365
- const modelEnum = fullSpec ? getModelEnum(fullSpec) : undefined;
7366
- const serviceType = fullSpec ? getServiceType(fullSpec) : undefined;
7502
+ const modelName = activeFullSpec
7503
+ ? getModelName(activeFullSpec)
7504
+ : undefined;
7505
+ const modelEnum = activeFullSpec
7506
+ ? getModelEnum(activeFullSpec)
7507
+ : undefined;
7508
+ const serviceType = activeFullSpec
7509
+ ? getServiceType(activeFullSpec)
7510
+ : undefined;
7367
7511
  const uiAdapter = new UIEventAdapter((event) => {
7368
7512
  wrappedOnEvent(event);
7369
7513
  options?.onStreamEvent?.(event);
@@ -7382,7 +7526,7 @@ class Graphlit {
7382
7526
  });
7383
7527
  // Resolve context strategy
7384
7528
  const callerStrategy = options?.contextStrategy ?? {};
7385
- const serverStrategy = fullSpec?.strategy;
7529
+ const serverStrategy = activeFullSpec?.strategy;
7386
7530
  const mergedStrategy = {
7387
7531
  toolResultTokenLimit: callerStrategy.toolResultTokenLimit ??
7388
7532
  serverStrategy?.toolResultTokenLimit ??
@@ -7400,7 +7544,7 @@ class Graphlit {
7400
7544
  try {
7401
7545
  loopResult = await this.executeStreamingLoop({
7402
7546
  conversationId,
7403
- specification: fullSpec,
7547
+ specification: activeFullSpec,
7404
7548
  messages: loopMessages,
7405
7549
  tools: allTools,
7406
7550
  toolHandlers: allToolHandlers,
@@ -7413,11 +7557,15 @@ class Graphlit {
7413
7557
  correlationId: options?.correlationId,
7414
7558
  persona: options?.persona,
7415
7559
  additionalSystemInstructions: options?.additionalSystemInstructions,
7560
+ fallbackSpecifications: fallbackSpecs,
7416
7561
  });
7417
7562
  }
7418
7563
  finally {
7419
7564
  uiAdapter.dispose();
7420
7565
  }
7566
+ if (loopResult.usedSpecification) {
7567
+ activeFullSpec = loopResult.usedSpecification;
7568
+ }
7421
7569
  // 8. Detect task_complete before persistence. The streaming loop
7422
7570
  // records the terminal assistant/tool-call round, but does not execute
7423
7571
  // the completion handler or start a follow-up filler round.
@@ -10379,6 +10379,38 @@ export const GetFeed = gql `
10379
10379
  }
10380
10380
  readLimit
10381
10381
  }
10382
+ skill {
10383
+ type
10384
+ isRecursive
10385
+ allowedPaths
10386
+ excludedPaths
10387
+ github {
10388
+ authenticationType
10389
+ uri
10390
+ repositoryOwner
10391
+ repositoryName
10392
+ clientId
10393
+ clientSecret
10394
+ refreshToken
10395
+ personalAccessToken
10396
+ connector {
10397
+ id
10398
+ }
10399
+ }
10400
+ gitlab {
10401
+ authenticationType
10402
+ projectPath
10403
+ branch
10404
+ clientId
10405
+ clientSecret
10406
+ refreshToken
10407
+ personalAccessToken
10408
+ connector {
10409
+ id
10410
+ }
10411
+ }
10412
+ readLimit
10413
+ }
10382
10414
  email {
10383
10415
  type
10384
10416
  includeAttachments
@@ -11482,6 +11514,38 @@ export const QueryFeeds = gql `
11482
11514
  }
11483
11515
  readLimit
11484
11516
  }
11517
+ skill {
11518
+ type
11519
+ isRecursive
11520
+ allowedPaths
11521
+ excludedPaths
11522
+ github {
11523
+ authenticationType
11524
+ uri
11525
+ repositoryOwner
11526
+ repositoryName
11527
+ clientId
11528
+ clientSecret
11529
+ refreshToken
11530
+ personalAccessToken
11531
+ connector {
11532
+ id
11533
+ }
11534
+ }
11535
+ gitlab {
11536
+ authenticationType
11537
+ projectPath
11538
+ branch
11539
+ clientId
11540
+ clientSecret
11541
+ refreshToken
11542
+ personalAccessToken
11543
+ connector {
11544
+ id
11545
+ }
11546
+ }
11547
+ readLimit
11548
+ }
11485
11549
  email {
11486
11550
  type
11487
11551
  includeAttachments
@@ -19157,6 +19221,10 @@ export const GetSkill = gql `
19157
19221
  correlationId
19158
19222
  text
19159
19223
  skillOwner
19224
+ feed {
19225
+ id
19226
+ name
19227
+ }
19160
19228
  arguments {
19161
19229
  name
19162
19230
  description
@@ -19187,6 +19255,10 @@ export const QuerySkills = gql `
19187
19255
  correlationId
19188
19256
  text
19189
19257
  skillOwner
19258
+ feed {
19259
+ id
19260
+ name
19261
+ }
19190
19262
  arguments {
19191
19263
  name
19192
19264
  description
@@ -3373,6 +3373,8 @@ export type ConnectorUpdateInput = {
3373
3373
  integration?: InputMaybe<IntegrationConnectorInput>;
3374
3374
  /** The name of the connector. */
3375
3375
  name?: InputMaybe<Scalars['String']['input']>;
3376
+ /** The connector type. */
3377
+ type?: InputMaybe<ConnectorTypes>;
3376
3378
  };
3377
3379
  /** Represents content. */
3378
3380
  export type Content = {
@@ -7905,6 +7907,8 @@ export type Feed = {
7905
7907
  search?: Maybe<SearchFeedProperties>;
7906
7908
  /** The site feed properties. */
7907
7909
  site?: Maybe<SiteFeedProperties>;
7910
+ /** The skill feed properties. */
7911
+ skill?: Maybe<SkillFeedProperties>;
7908
7912
  /** The Slack feed properties. */
7909
7913
  slack?: Maybe<SlackFeedProperties>;
7910
7914
  /** The state of the feed (i.e. created, finished). */
@@ -8095,6 +8099,8 @@ export type FeedInput = {
8095
8099
  search?: InputMaybe<SearchFeedPropertiesInput>;
8096
8100
  /** The site feed properties. */
8097
8101
  site?: InputMaybe<SiteFeedPropertiesInput>;
8102
+ /** The skill feed properties. */
8103
+ skill?: InputMaybe<SkillFeedPropertiesInput>;
8098
8104
  /** The Slack feed properties. */
8099
8105
  slack?: InputMaybe<SlackFeedPropertiesInput>;
8100
8106
  /** The feed sync mode. */
@@ -8177,6 +8183,8 @@ export type FeedPreviewInput = {
8177
8183
  search?: InputMaybe<SearchFeedPropertiesInput>;
8178
8184
  /** The site feed properties. */
8179
8185
  site?: InputMaybe<SiteFeedPropertiesInput>;
8186
+ /** The skill feed properties. */
8187
+ skill?: InputMaybe<SkillFeedPropertiesInput>;
8180
8188
  /** The Slack feed properties. */
8181
8189
  slack?: InputMaybe<SlackFeedPropertiesInput>;
8182
8190
  /** The Twitter feed properties. */
@@ -8205,6 +8213,10 @@ export type FeedPreviewResult = {
8205
8213
  itemCount: Scalars['Long']['output'];
8206
8214
  /** The observable type histogram. */
8207
8215
  observableTypeSummary?: Maybe<Array<ObservableTypeSummary>>;
8216
+ /** The skill feed preview summary. */
8217
+ skillSummary?: Maybe<SkillFeedPreviewSummary>;
8218
+ /** The skill feed preview items. */
8219
+ skills?: Maybe<Array<SkillFeedPreviewItem>>;
8208
8220
  /** Any warnings generated during the preview scan. */
8209
8221
  warnings?: Maybe<Array<Scalars['String']['output']>>;
8210
8222
  };
@@ -8429,6 +8441,8 @@ export declare enum FeedTypes {
8429
8441
  Search = "SEARCH",
8430
8442
  /** Cloud storage site feed */
8431
8443
  Site = "SITE",
8444
+ /** Skill package feed */
8445
+ Skill = "SKILL",
8432
8446
  /** Slack channel feed */
8433
8447
  Slack = "SLACK",
8434
8448
  /** Twitter/X feed */
@@ -8506,6 +8520,8 @@ export type FeedUpdateInput = {
8506
8520
  search?: InputMaybe<SearchFeedPropertiesUpdateInput>;
8507
8521
  /** The site feed properties. */
8508
8522
  site?: InputMaybe<SiteFeedPropertiesUpdateInput>;
8523
+ /** The skill feed properties. */
8524
+ skill?: InputMaybe<SkillFeedPropertiesUpdateInput>;
8509
8525
  /** The Slack feed properties. */
8510
8526
  slack?: InputMaybe<SlackFeedPropertiesUpdateInput>;
8511
8527
  /** The feed sync mode. */
@@ -24280,6 +24296,8 @@ export type Skill = {
24280
24296
  creationDate: Scalars['DateTime']['output'];
24281
24297
  /** The description of the skill. */
24282
24298
  description?: Maybe<Scalars['String']['output']>;
24299
+ /** The feed that installed this skill. */
24300
+ feed?: Maybe<Feed>;
24283
24301
  /** The ID of the skill. */
24284
24302
  id: Scalars['ID']['output'];
24285
24303
  /** The skill external identifier. */
@@ -24320,6 +24338,107 @@ export type SkillArgumentInput = {
24320
24338
  /** Whether this argument is required. Defaults to true. */
24321
24339
  required?: InputMaybe<Scalars['Boolean']['input']>;
24322
24340
  };
24341
+ /** Represents a skill feed preview item. */
24342
+ export type SkillFeedPreviewItem = {
24343
+ __typename?: 'SkillFeedPreviewItem';
24344
+ /** The current skill hash. */
24345
+ currentHash?: Maybe<Scalars['String']['output']>;
24346
+ /** The skill description. */
24347
+ description?: Maybe<Scalars['String']['output']>;
24348
+ /** The skill file identifier. */
24349
+ fileIdentifier: Scalars['String']['output'];
24350
+ /** The skill name. */
24351
+ name?: Maybe<Scalars['String']['output']>;
24352
+ /** The preview operation. */
24353
+ operation: SkillFeedPreviewOperations;
24354
+ /** The skill file path. */
24355
+ path: Scalars['String']['output'];
24356
+ /** The number of inlined markdown references. */
24357
+ referenceCount?: Maybe<Scalars['Long']['output']>;
24358
+ /** The inlined markdown references. */
24359
+ references?: Maybe<Array<Scalars['String']['output']>>;
24360
+ /** The upstream skill hash. */
24361
+ upstreamHash?: Maybe<Scalars['String']['output']>;
24362
+ /** Warnings generated for this skill. */
24363
+ warnings?: Maybe<Array<Scalars['String']['output']>>;
24364
+ };
24365
+ /** Skill feed preview operation */
24366
+ export declare enum SkillFeedPreviewOperations {
24367
+ /** Invalid skill */
24368
+ Invalid = "INVALID",
24369
+ /** New skill */
24370
+ New = "NEW",
24371
+ /** Unchanged skill */
24372
+ Unchanged = "UNCHANGED",
24373
+ /** Updated skill */
24374
+ Update = "UPDATE"
24375
+ }
24376
+ /** Represents a skill feed preview summary. */
24377
+ export type SkillFeedPreviewSummary = {
24378
+ __typename?: 'SkillFeedPreviewSummary';
24379
+ /** The total number of skills found. */
24380
+ foundCount: Scalars['Long']['output'];
24381
+ /** The number of invalid skills. */
24382
+ invalidCount: Scalars['Long']['output'];
24383
+ /** The number of new skills. */
24384
+ newCount: Scalars['Long']['output'];
24385
+ /** The number of unchanged skills. */
24386
+ unchangedCount: Scalars['Long']['output'];
24387
+ /** The number of updated skills. */
24388
+ updateCount: Scalars['Long']['output'];
24389
+ };
24390
+ /** Represents skill feed properties. */
24391
+ export type SkillFeedProperties = {
24392
+ __typename?: 'SkillFeedProperties';
24393
+ /** The list of regular expressions for URL paths to be crawled, i.e. "^/public/blogs/.*". */
24394
+ allowedPaths?: Maybe<Array<Scalars['String']['output']>>;
24395
+ /** Feed connector type. */
24396
+ connectorType: FeedConnectorTypes;
24397
+ /** The list of regular expressions for URL paths to not be crawled, i.e. "^/internal/private/.*". */
24398
+ excludedPaths?: Maybe<Array<Scalars['String']['output']>>;
24399
+ /** GitHub properties. */
24400
+ github?: Maybe<GitHubFeedProperties>;
24401
+ /** GitLab properties. */
24402
+ gitlab?: Maybe<GitLabFeedProperties>;
24403
+ /** Should the feed enumerate files recursively via folders. */
24404
+ isRecursive?: Maybe<Scalars['Boolean']['output']>;
24405
+ /** The limit of items to be read from feed, defaults to 100. */
24406
+ readLimit?: Maybe<Scalars['Int']['output']>;
24407
+ /** Feed service type. */
24408
+ type: FeedServiceTypes;
24409
+ };
24410
+ /** Represents skill feed properties. */
24411
+ export type SkillFeedPropertiesInput = {
24412
+ /** The list of regular expressions for URL paths to be crawled, i.e. "^/public/blogs/.*". */
24413
+ allowedPaths?: InputMaybe<Array<Scalars['String']['input']>>;
24414
+ /** The list of regular expressions for URL paths to not be crawled, i.e. "^/internal/private/.*". */
24415
+ excludedPaths?: InputMaybe<Array<Scalars['String']['input']>>;
24416
+ /** GitHub properties. */
24417
+ github?: InputMaybe<GitHubFeedPropertiesInput>;
24418
+ /** GitLab properties. */
24419
+ gitlab?: InputMaybe<GitLabFeedPropertiesInput>;
24420
+ /** Should the feed enumerate files recursively via folders. */
24421
+ isRecursive?: InputMaybe<Scalars['Boolean']['input']>;
24422
+ /** The limit of items to be read from feed, defaults to 100. */
24423
+ readLimit?: InputMaybe<Scalars['Int']['input']>;
24424
+ /** Feed service type. */
24425
+ type: FeedServiceTypes;
24426
+ };
24427
+ /** Represents skill feed properties. */
24428
+ export type SkillFeedPropertiesUpdateInput = {
24429
+ /** The list of regular expressions for URL paths to be crawled, i.e. "^/public/blogs/.*". */
24430
+ allowedPaths?: InputMaybe<Array<Scalars['String']['input']>>;
24431
+ /** The list of regular expressions for URL paths to not be crawled, i.e. "^/internal/private/.*". */
24432
+ excludedPaths?: InputMaybe<Array<Scalars['String']['input']>>;
24433
+ /** GitHub properties. */
24434
+ github?: InputMaybe<GitHubFeedPropertiesUpdateInput>;
24435
+ /** GitLab properties. */
24436
+ gitlab?: InputMaybe<GitLabFeedPropertiesUpdateInput>;
24437
+ /** Should the feed enumerate files recursively via folders. */
24438
+ isRecursive?: InputMaybe<Scalars['Boolean']['input']>;
24439
+ /** The limit of items to be read from feed, defaults to 100. */
24440
+ readLimit?: InputMaybe<Scalars['Int']['input']>;
24441
+ };
24323
24442
  /** Represents a filter for skills. */
24324
24443
  export type SkillFilter = {
24325
24444
  /** Filter by collections. */
@@ -24330,8 +24449,12 @@ export type SkillFilter = {
24330
24449
  creationDateRange?: InputMaybe<DateRangeFilter>;
24331
24450
  /** The sort direction for query results. */
24332
24451
  direction?: InputMaybe<OrderDirectionTypes>;
24452
+ /** Filter by feeds. */
24453
+ feeds?: InputMaybe<Array<EntityReferenceFilter>>;
24333
24454
  /** Filter by whether the skill belongs to any collections. */
24334
24455
  hasCollections?: InputMaybe<Scalars['Boolean']['input']>;
24456
+ /** Filter by whether the skill is associated with any feeds. */
24457
+ hasFeeds?: InputMaybe<Scalars['Boolean']['input']>;
24335
24458
  /** Filter skill(s) by their unique ID. */
24336
24459
  id?: InputMaybe<Scalars['ID']['input']>;
24337
24460
  /** Filter by external identifier. */
@@ -24365,6 +24488,8 @@ export type SkillInput = {
24365
24488
  collections?: InputMaybe<Array<EntityReferenceInput>>;
24366
24489
  /** The description of the skill. */
24367
24490
  description?: InputMaybe<Scalars['String']['input']>;
24491
+ /** The feed that installed this skill. */
24492
+ feed?: InputMaybe<EntityReferenceInput>;
24368
24493
  /** The skill external identifier. */
24369
24494
  identifier?: InputMaybe<Scalars['String']['input']>;
24370
24495
  /** The name of the skill. */
@@ -38780,6 +38905,43 @@ export type GetFeedQuery = {
38780
38905
  } | null;
38781
38906
  } | null;
38782
38907
  } | null;
38908
+ skill?: {
38909
+ __typename?: 'SkillFeedProperties';
38910
+ type: FeedServiceTypes;
38911
+ isRecursive?: boolean | null;
38912
+ allowedPaths?: Array<string> | null;
38913
+ excludedPaths?: Array<string> | null;
38914
+ readLimit?: number | null;
38915
+ github?: {
38916
+ __typename?: 'GitHubFeedProperties';
38917
+ authenticationType?: GitHubAuthenticationTypes | null;
38918
+ uri?: any | null;
38919
+ repositoryOwner: string;
38920
+ repositoryName: string;
38921
+ clientId?: string | null;
38922
+ clientSecret?: string | null;
38923
+ refreshToken?: string | null;
38924
+ personalAccessToken?: string | null;
38925
+ connector?: {
38926
+ __typename?: 'EntityReference';
38927
+ id: string;
38928
+ } | null;
38929
+ } | null;
38930
+ gitlab?: {
38931
+ __typename?: 'GitLabFeedProperties';
38932
+ authenticationType?: GitLabAuthenticationTypes | null;
38933
+ projectPath: string;
38934
+ branch?: string | null;
38935
+ clientId?: string | null;
38936
+ clientSecret?: string | null;
38937
+ refreshToken?: string | null;
38938
+ personalAccessToken?: string | null;
38939
+ connector?: {
38940
+ __typename?: 'EntityReference';
38941
+ id: string;
38942
+ } | null;
38943
+ } | null;
38944
+ } | null;
38783
38945
  email?: {
38784
38946
  __typename?: 'EmailFeedProperties';
38785
38947
  type: FeedServiceTypes;
@@ -40099,6 +40261,43 @@ export type QueryFeedsQuery = {
40099
40261
  } | null;
40100
40262
  } | null;
40101
40263
  } | null;
40264
+ skill?: {
40265
+ __typename?: 'SkillFeedProperties';
40266
+ type: FeedServiceTypes;
40267
+ isRecursive?: boolean | null;
40268
+ allowedPaths?: Array<string> | null;
40269
+ excludedPaths?: Array<string> | null;
40270
+ readLimit?: number | null;
40271
+ github?: {
40272
+ __typename?: 'GitHubFeedProperties';
40273
+ authenticationType?: GitHubAuthenticationTypes | null;
40274
+ uri?: any | null;
40275
+ repositoryOwner: string;
40276
+ repositoryName: string;
40277
+ clientId?: string | null;
40278
+ clientSecret?: string | null;
40279
+ refreshToken?: string | null;
40280
+ personalAccessToken?: string | null;
40281
+ connector?: {
40282
+ __typename?: 'EntityReference';
40283
+ id: string;
40284
+ } | null;
40285
+ } | null;
40286
+ gitlab?: {
40287
+ __typename?: 'GitLabFeedProperties';
40288
+ authenticationType?: GitLabAuthenticationTypes | null;
40289
+ projectPath: string;
40290
+ branch?: string | null;
40291
+ clientId?: string | null;
40292
+ clientSecret?: string | null;
40293
+ refreshToken?: string | null;
40294
+ personalAccessToken?: string | null;
40295
+ connector?: {
40296
+ __typename?: 'EntityReference';
40297
+ id: string;
40298
+ } | null;
40299
+ } | null;
40300
+ } | null;
40102
40301
  email?: {
40103
40302
  __typename?: 'EmailFeedProperties';
40104
40303
  type: FeedServiceTypes;
@@ -49437,6 +49636,11 @@ export type GetSkillQuery = {
49437
49636
  __typename?: 'EntityReference';
49438
49637
  id: string;
49439
49638
  } | null;
49639
+ feed?: {
49640
+ __typename?: 'Feed';
49641
+ id: string;
49642
+ name: string;
49643
+ } | null;
49440
49644
  arguments?: Array<{
49441
49645
  __typename?: 'SkillArgument';
49442
49646
  name: string;
@@ -49475,6 +49679,11 @@ export type QuerySkillsQuery = {
49475
49679
  __typename?: 'Owner';
49476
49680
  id: string;
49477
49681
  };
49682
+ feed?: {
49683
+ __typename?: 'Feed';
49684
+ id: string;
49685
+ name: string;
49686
+ } | null;
49478
49687
  arguments?: Array<{
49479
49688
  __typename?: 'SkillArgument';
49480
49689
  name: string;
@@ -1594,6 +1594,8 @@ export var FeedTypes;
1594
1594
  FeedTypes["Search"] = "SEARCH";
1595
1595
  /** Cloud storage site feed */
1596
1596
  FeedTypes["Site"] = "SITE";
1597
+ /** Skill package feed */
1598
+ FeedTypes["Skill"] = "SKILL";
1597
1599
  /** Slack channel feed */
1598
1600
  FeedTypes["Slack"] = "SLACK";
1599
1601
  /** Twitter/X feed */
@@ -3225,6 +3227,18 @@ export var SiteTypes;
3225
3227
  /** Watch cloud storage site */
3226
3228
  SiteTypes["Watch"] = "WATCH";
3227
3229
  })(SiteTypes || (SiteTypes = {}));
3230
+ /** Skill feed preview operation */
3231
+ export var SkillFeedPreviewOperations;
3232
+ (function (SkillFeedPreviewOperations) {
3233
+ /** Invalid skill */
3234
+ SkillFeedPreviewOperations["Invalid"] = "INVALID";
3235
+ /** New skill */
3236
+ SkillFeedPreviewOperations["New"] = "NEW";
3237
+ /** Unchanged skill */
3238
+ SkillFeedPreviewOperations["Unchanged"] = "UNCHANGED";
3239
+ /** Updated skill */
3240
+ SkillFeedPreviewOperations["Update"] = "UPDATE";
3241
+ })(SkillFeedPreviewOperations || (SkillFeedPreviewOperations = {}));
3228
3242
  export var SlackAuthenticationTypes;
3229
3243
  (function (SlackAuthenticationTypes) {
3230
3244
  SlackAuthenticationTypes["Connector"] = "CONNECTOR";
@@ -48,6 +48,11 @@ export declare class UIEventAdapter {
48
48
  modelName?: string;
49
49
  modelService?: string;
50
50
  });
51
+ setModelInfo(options: {
52
+ model?: string;
53
+ modelName?: string;
54
+ modelService?: string;
55
+ }): void;
51
56
  /**
52
57
  * Process a raw streaming event and emit appropriate UI events
53
58
  */
@@ -64,6 +64,11 @@ export class UIEventAdapter {
64
64
  this.reasoningBuffer = new ChunkBuffer("sentence");
65
65
  }
66
66
  }
67
+ setModelInfo(options) {
68
+ this.model = options.model;
69
+ this.modelName = options.modelName;
70
+ this.modelService = options.modelService;
71
+ }
67
72
  /**
68
73
  * Process a raw streaming event and emit appropriate UI events
69
74
  */
@@ -76,6 +76,8 @@ export interface StreamAgentOptions {
76
76
  skills?: EntityReferenceInput[];
77
77
  /** Stable, caller-supplied system-channel content to append after the specification system prompt. */
78
78
  additionalSystemInstructions?: string;
79
+ /** Ordered fallback specifications to try for native streaming after retryable provider failures. */
80
+ fallbacks?: EntityReferenceInput[];
79
81
  }
80
82
  export interface ToolCallResult {
81
83
  id: string;
@@ -152,7 +154,6 @@ export interface RunAgentOptions {
152
154
  toolHandlers?: Record<string, ToolHandler>;
153
155
  persona?: EntityReferenceInput;
154
156
  augmentedFilter?: ContentCriteriaInput;
155
- fallbacks?: EntityReferenceInput[];
156
157
  maxTurns?: number;
157
158
  maxWallClockMs?: number;
158
159
  maxToolCalls?: number;
@@ -225,6 +226,7 @@ export interface StreamingLoopConfig {
225
226
  mimeType?: string;
226
227
  data?: string;
227
228
  additionalSystemInstructions?: string;
229
+ fallbackSpecifications?: Specification[];
228
230
  }
229
231
  /** Result returned from executeStreamingLoop. */
230
232
  export interface StreamingLoopResult {
@@ -238,4 +240,5 @@ export interface StreamingLoopResult {
238
240
  reasoning?: ReasoningMetadata;
239
241
  intermediateMessages: ConversationMessageInput[];
240
242
  lastRoundReasoning?: ReasoningMetadata;
243
+ usedSpecification?: Specification;
241
244
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20260424002",
3
+ "version": "1.0.20260424004",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",