diff --git a/x-pack/plugins/integration_assistant/docs/imgs/categorization_graph.png b/x-pack/plugins/integration_assistant/docs/imgs/categorization_graph.png index e7a011ad27b9aa..a15dbf54d905a5 100644 Binary files a/x-pack/plugins/integration_assistant/docs/imgs/categorization_graph.png and b/x-pack/plugins/integration_assistant/docs/imgs/categorization_graph.png differ diff --git a/x-pack/plugins/integration_assistant/docs/imgs/ecs_graph.png b/x-pack/plugins/integration_assistant/docs/imgs/ecs_graph.png index f2342cfc594c3f..49bb9c3243068d 100644 Binary files a/x-pack/plugins/integration_assistant/docs/imgs/ecs_graph.png and b/x-pack/plugins/integration_assistant/docs/imgs/ecs_graph.png differ diff --git a/x-pack/plugins/integration_assistant/docs/imgs/ecs_subgraph.png b/x-pack/plugins/integration_assistant/docs/imgs/ecs_subgraph.png index 85358ee453bcf8..8e3ea2bc5e0ca7 100644 Binary files a/x-pack/plugins/integration_assistant/docs/imgs/ecs_subgraph.png and b/x-pack/plugins/integration_assistant/docs/imgs/ecs_subgraph.png differ diff --git a/x-pack/plugins/integration_assistant/docs/imgs/kv_graph.png b/x-pack/plugins/integration_assistant/docs/imgs/kv_graph.png new file mode 100644 index 00000000000000..48a60999242487 Binary files /dev/null and b/x-pack/plugins/integration_assistant/docs/imgs/kv_graph.png differ diff --git a/x-pack/plugins/integration_assistant/docs/imgs/log_detection_graph.png b/x-pack/plugins/integration_assistant/docs/imgs/log_detection_graph.png index 94830a549dcf11..285e012c57a149 100644 Binary files a/x-pack/plugins/integration_assistant/docs/imgs/log_detection_graph.png and b/x-pack/plugins/integration_assistant/docs/imgs/log_detection_graph.png differ diff --git a/x-pack/plugins/integration_assistant/docs/imgs/related_graph.png b/x-pack/plugins/integration_assistant/docs/imgs/related_graph.png index cebb482a4b495e..73a2c3acac0d4c 100644 Binary files a/x-pack/plugins/integration_assistant/docs/imgs/related_graph.png and b/x-pack/plugins/integration_assistant/docs/imgs/related_graph.png differ diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts index 5c83b799979e93..5dcc55d4f0975c 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts @@ -5,14 +5,12 @@ * 2.0. */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { CategorizationState, SimplifiedProcessor, SimplifiedProcessors } from '../../types'; import { combineProcessors } from '../../util/processors'; import { CATEGORIZATION_EXAMPLE_PROCESSORS } from './constants'; import { CATEGORIZATION_MAIN_PROMPT } from './prompts'; import type { CategorizationNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleCategorization({ state, @@ -21,22 +19,13 @@ export async function handleCategorization({ const categorizationMainPrompt = CATEGORIZATION_MAIN_PROMPT; const outputParser = new JsonOutputParser(); const categorizationMainGraph = categorizationMainPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await categorizationMainGraph.invoke({ - pipeline_results: JSON.stringify(state.pipelineResults, null, 2), - example_processors: CATEGORIZATION_EXAMPLE_PROCESSORS, - ex_answer: state?.exAnswer, - ecs_categories: state?.ecsCategories, - ecs_types: state?.ecsTypes, - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const currentProcessors = (await categorizationMainGraph.invoke({ + pipeline_results: JSON.stringify(state.pipelineResults, null, 2), + example_processors: CATEGORIZATION_EXAMPLE_PROCESSORS, + ex_answer: state?.exAnswer, + ecs_categories: state?.ecsCategories, + ecs_types: state?.ecsTypes, + })) as SimplifiedProcessor[]; const processors = { type: 'categorization', diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts index 417fbdeaec5b07..789673af0ff286 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts @@ -6,13 +6,11 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { CategorizationNodeParams } from './types'; import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { CATEGORIZATION_ERROR_PROMPT } from './prompts'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleErrors({ state, @@ -22,23 +20,15 @@ export async function handleErrors({ const outputParser = new JsonOutputParser(); const categorizationErrorGraph = categorizationErrorPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await categorizationErrorGraph.invoke({ - current_processors: JSON.stringify(state.currentProcessors, null, 2), - ex_answer: state.exAnswer, - errors: JSON.stringify(state.errors, null, 2), - package_name: state.packageName, - data_stream_name: state.dataStreamName, - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const currentProcessors = (await categorizationErrorGraph.invoke({ + current_processors: JSON.stringify(state.currentProcessors, null, 2), + ex_answer: state.exAnswer, + errors: JSON.stringify(state.errors, null, 2), + package_name: state.packageName, + data_stream_name: state.dataStreamName, + })) as SimplifiedProcessor[]; + const processors = { type: 'categorization', processors: currentProcessors, diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts index c2322dbb66b264..62f7f3101ba9a6 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts @@ -6,14 +6,12 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { CategorizationNodeParams } from './types'; import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { ECS_EVENT_TYPES_PER_CATEGORY } from './constants'; import { CATEGORIZATION_VALIDATION_PROMPT } from './prompts'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleInvalidCategorization({ state, @@ -23,22 +21,14 @@ export async function handleInvalidCategorization({ const outputParser = new JsonOutputParser(); const categorizationInvalidGraph = categorizationInvalidPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await categorizationInvalidGraph.invoke({ - current_processors: JSON.stringify(state.currentProcessors, null, 2), - invalid_categorization: JSON.stringify(state.invalidCategorization, null, 2), - ex_answer: state.exAnswer, - compatible_types: JSON.stringify(ECS_EVENT_TYPES_PER_CATEGORY, null, 2), - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const currentProcessors = (await categorizationInvalidGraph.invoke({ + current_processors: JSON.stringify(state.currentProcessors, null, 2), + invalid_categorization: JSON.stringify(state.invalidCategorization, null, 2), + ex_answer: state.exAnswer, + compatible_types: JSON.stringify(ECS_EVENT_TYPES_PER_CATEGORY, null, 2), + })) as SimplifiedProcessor[]; + const processors = { type: 'categorization', processors: currentProcessors, diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts index 464b1ac27da5a1..19b8180ce33e57 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts @@ -6,14 +6,12 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import { CATEGORIZATION_REVIEW_PROMPT } from './prompts'; import type { Pipeline } from '../../../common'; import type { CategorizationNodeParams } from './types'; import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { ECS_EVENT_TYPES_PER_CATEGORY } from './constants'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleReview({ state, @@ -22,25 +20,17 @@ export async function handleReview({ const categorizationReviewPrompt = CATEGORIZATION_REVIEW_PROMPT; const outputParser = new JsonOutputParser(); const categorizationReview = categorizationReviewPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await categorizationReview.invoke({ - current_processors: JSON.stringify(state.currentProcessors, null, 2), - pipeline_results: JSON.stringify(state.pipelineResults, null, 2), - previous_invalid_categorization: state.previousInvalidCategorization, - previous_error: state.previousError, - ex_answer: state?.exAnswer, - package_name: state?.packageName, - compatibility_matrix: JSON.stringify(ECS_EVENT_TYPES_PER_CATEGORY, null, 2), - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const currentProcessors = (await categorizationReview.invoke({ + current_processors: JSON.stringify(state.currentProcessors, null, 2), + pipeline_results: JSON.stringify(state.pipelineResults, null, 2), + previous_invalid_categorization: state.previousInvalidCategorization, + previous_error: state.previousError, + ex_answer: state?.exAnswer, + package_name: state?.packageName, + compatibility_matrix: JSON.stringify(ECS_EVENT_TYPES_PER_CATEGORY, null, 2), + })) as SimplifiedProcessor[]; + const processors = { type: 'categorization', processors: currentProcessors, diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts index 29e735ad329ebf..2d59bd1c241d56 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts @@ -6,11 +6,9 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { EcsMappingState } from '../../types'; import { ECS_DUPLICATES_PROMPT } from './prompts'; import type { EcsNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleDuplicates({ state, @@ -21,22 +19,12 @@ export async function handleDuplicates({ const usesFinalMapping = state?.useFinalMapping; const mapping = usesFinalMapping ? state.finalMapping : state.currentMapping; - let result; - - try { - result = await ecsDuplicatesGraph.invoke({ - ecs: state.ecs, - current_mapping: JSON.stringify(mapping, null, 2), - ex_answer: state.exAnswer, - duplicate_fields: state.duplicateFields, - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const result = await ecsDuplicatesGraph.invoke({ + ecs: state.ecs, + current_mapping: JSON.stringify(mapping, null, 2), + ex_answer: state.exAnswer, + duplicate_fields: state.duplicateFields, + }); return { [usesFinalMapping ? 'finalMapping' : 'currentMapping']: result, diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts index a8aef37a303821..5440b5bc9b125f 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts @@ -5,11 +5,9 @@ * 2.0. */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { EcsMappingState } from '../../types'; import { ECS_INVALID_PROMPT } from './prompts'; import type { EcsNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleInvalidEcs({ state, @@ -20,22 +18,13 @@ export async function handleInvalidEcs({ const usesFinalMapping = state?.useFinalMapping; const mapping = usesFinalMapping ? state.finalMapping : state.currentMapping; - let result; - try { - result = await ecsInvalidEcsGraph.invoke({ - ecs: state.ecs, - current_mapping: JSON.stringify(mapping, null, 2), - ex_answer: state.exAnswer, - combined_samples: state.combinedSamples, - invalid_ecs_fields: state.invalidEcsFields, - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const result = await ecsInvalidEcsGraph.invoke({ + ecs: state.ecs, + current_mapping: JSON.stringify(mapping, null, 2), + ex_answer: state.exAnswer, + combined_samples: state.combinedSamples, + invalid_ecs_fields: state.invalidEcsFields, + }); return { [usesFinalMapping ? 'finalMapping' : 'currentMapping']: result, diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts index d5cba88c62c4f7..1386881d379f4d 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts @@ -6,11 +6,9 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { EcsMappingState } from '../../types'; import { ECS_MAIN_PROMPT } from './prompts'; import type { EcsNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleEcsMapping({ state, @@ -18,22 +16,13 @@ export async function handleEcsMapping({ }: EcsNodeParams): Promise> { const outputParser = new JsonOutputParser(); const ecsMainGraph = ECS_MAIN_PROMPT.pipe(model).pipe(outputParser); - let currentMapping; - try { - currentMapping = await ecsMainGraph.invoke({ - ecs: state.ecs, - combined_samples: state.combinedSamples, - package_name: state.packageName, - data_stream_name: state.dataStreamName, - ex_answer: state.exAnswer, - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const currentMapping = await ecsMainGraph.invoke({ + ecs: state.ecs, + combined_samples: state.combinedSamples, + package_name: state.packageName, + data_stream_name: state.dataStreamName, + ex_answer: state.exAnswer, + }); return { currentMapping, hasTriedOnce: true, lastExecutedChain: 'ecsMapping' }; } diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts index a182e257ffe436..0c22af98a41bce 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts @@ -6,11 +6,9 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import { EcsMappingState } from '../../types'; import { ECS_MISSING_KEYS_PROMPT } from './prompts'; import { EcsNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleMissingKeys({ state, @@ -20,22 +18,15 @@ export async function handleMissingKeys({ const ecsMissingGraph = ECS_MISSING_KEYS_PROMPT.pipe(model).pipe(outputParser); const usesFinalMapping = state?.useFinalMapping; const mapping = usesFinalMapping ? state.finalMapping : state.currentMapping; - let result; - try { - result = await ecsMissingGraph.invoke({ - ecs: state.ecs, - current_mapping: JSON.stringify(mapping, null, 2), - ex_answer: state.exAnswer, - combined_samples: state.combinedSamples, - missing_keys: state?.missingKeys, - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + + const result = await ecsMissingGraph.invoke({ + ecs: state.ecs, + current_mapping: JSON.stringify(mapping, null, 2), + ex_answer: state.exAnswer, + combined_samples: state.combinedSamples, + missing_keys: state?.missingKeys, + }); + return { [usesFinalMapping ? 'finalMapping' : 'currentMapping']: result, lastExecutedChain: 'missingKeys', diff --git a/x-pack/plugins/integration_assistant/server/graphs/kv/header.ts b/x-pack/plugins/integration_assistant/server/graphs/kv/header.ts index 7086ea3fd93629..36d8968ab9e675 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/kv/header.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/kv/header.ts @@ -6,12 +6,10 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { KVState } from '../../types'; import type { HandleKVNodeParams } from './types'; import { KV_HEADER_PROMPT } from './prompts'; import { KV_HEADER_EXAMPLE_ANSWER } from './constants'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleHeader({ state, @@ -20,20 +18,11 @@ export async function handleHeader({ }: HandleKVNodeParams): Promise> { const outputParser = new JsonOutputParser(); const kvHeaderGraph = KV_HEADER_PROMPT.pipe(model).pipe(outputParser); - let pattern; - try { - pattern = await kvHeaderGraph.invoke({ - samples: state.logSamples, - ex_answer: JSON.stringify(KV_HEADER_EXAMPLE_ANSWER, null, 2), - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const pattern = await kvHeaderGraph.invoke({ + samples: state.logSamples, + ex_answer: JSON.stringify(KV_HEADER_EXAMPLE_ANSWER, null, 2), + }); return { grokPattern: pattern.grok_pattern, diff --git a/x-pack/plugins/integration_assistant/server/graphs/kv/kv.ts b/x-pack/plugins/integration_assistant/server/graphs/kv/kv.ts index 60e7aa3b297cde..46820778e5a7df 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/kv/kv.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/kv/kv.ts @@ -5,14 +5,12 @@ * 2.0. */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { KVState } from '../../types'; import { KV_MAIN_PROMPT } from './prompts'; import { KVProcessor } from '../../processor_types'; import { HandleKVNodeParams } from './types'; import { KV_EXAMPLE_ANSWER } from './constants'; import { createKVProcessor } from '../../util/processors'; -import { RecursionLimitError } from '../../lib/errors'; /** * Handles the KV processor node in the graph @@ -30,20 +28,11 @@ export async function handleKV({ // Pick logSamples if there was no header detected. const samples = state.header ? state.kvLogMessages : state.logSamples; - let kvInput: KVProcessor; - try { - kvInput = (await kvMainGraph.invoke({ - samples: samples[0], - ex_answer: JSON.stringify(KV_EXAMPLE_ANSWER, null, 2), - })) as KVProcessor; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const kvInput = (await kvMainGraph.invoke({ + samples: samples[0], + ex_answer: JSON.stringify(KV_EXAMPLE_ANSWER, null, 2), + })) as KVProcessor; const kvProcessor = createKVProcessor(kvInput, state); diff --git a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/detection.ts b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/detection.ts index 3ee19abbaa6d7e..4920adb609967a 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/detection.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/detection.ts @@ -5,11 +5,9 @@ * 2.0. */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { LogFormatDetectionState } from '../../types'; import { LOG_FORMAT_DETECTION_PROMPT } from './prompts'; import type { LogDetectionNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; const MaxLogSamplesInPrompt = 5; @@ -24,20 +22,12 @@ export async function handleLogFormatDetection({ state.logSamples.length > MaxLogSamplesInPrompt ? state.logSamples.slice(0, MaxLogSamplesInPrompt) : state.logSamples; - let detectedLogFormatAnswer; - try { - detectedLogFormatAnswer = await logFormatDetectionNode.invoke({ - ex_answer: state.exAnswer, - log_samples: samples, - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const detectedLogFormatAnswer = await logFormatDetectionNode.invoke({ + ex_answer: state.exAnswer, + log_samples: samples, + }); + const logFormat = detectedLogFormatAnswer.log_type; const header = detectedLogFormatAnswer.header; diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts b/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts index b894eba899de7a..5601c4b5f5e333 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts @@ -6,14 +6,12 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; import type { RelatedNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { RELATED_ERROR_PROMPT } from './prompts'; import { COMMON_ERRORS } from './constants'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleErrors({ state, @@ -22,23 +20,15 @@ export async function handleErrors({ const relatedErrorPrompt = RELATED_ERROR_PROMPT; const outputParser = new JsonOutputParser(); const relatedErrorGraph = relatedErrorPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await relatedErrorGraph.invoke({ - current_processors: JSON.stringify(state.currentProcessors, null, 2), - common_errors: JSON.stringify(COMMON_ERRORS, null, 2), - ex_answer: state.exAnswer, - errors: JSON.stringify(state.errors, null, 2), - package_name: state.packageName, - data_stream_name: state.dataStreamName, - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + + const currentProcessors = (await relatedErrorGraph.invoke({ + current_processors: JSON.stringify(state.currentProcessors, null, 2), + common_errors: JSON.stringify(COMMON_ERRORS, null, 2), + ex_answer: state.exAnswer, + errors: JSON.stringify(state.errors, null, 2), + package_name: state.packageName, + data_stream_name: state.dataStreamName, + })) as SimplifiedProcessor[]; const processors = { type: 'related', diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/related.ts b/x-pack/plugins/integration_assistant/server/graphs/related/related.ts index fb2fea25e7ae19..902427a1c484fa 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/related.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/related.ts @@ -6,13 +6,11 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessor, SimplifiedProcessors } from '../../types'; import { combineProcessors } from '../../util/processors'; import { RELATED_MAIN_PROMPT } from './prompts'; import type { RelatedNodeParams } from './types'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleRelated({ state, @@ -21,20 +19,13 @@ export async function handleRelated({ const relatedMainPrompt = RELATED_MAIN_PROMPT; const outputParser = new JsonOutputParser(); const relatedMainGraph = relatedMainPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await relatedMainGraph.invoke({ - pipeline_results: JSON.stringify(state.pipelineResults, null, 2), - ex_answer: state.exAnswer, - ecs: state.ecs, - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + + const currentProcessors = (await relatedMainGraph.invoke({ + pipeline_results: JSON.stringify(state.pipelineResults, null, 2), + ex_answer: state.exAnswer, + ecs: state.ecs, + })) as SimplifiedProcessor[]; + const processors = { type: 'related', processors: currentProcessors, diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/review.ts b/x-pack/plugins/integration_assistant/server/graphs/related/review.ts index fb3bf4a9e4b374..300f33144b52ac 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/review.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/review.ts @@ -6,13 +6,11 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; import type { RelatedNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { RELATED_REVIEW_PROMPT } from './prompts'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleReview({ state, @@ -21,21 +19,14 @@ export async function handleReview({ const relatedReviewPrompt = RELATED_REVIEW_PROMPT; const outputParser = new JsonOutputParser(); const relatedReviewGraph = relatedReviewPrompt.pipe(model).pipe(outputParser); - let currentProcessors: SimplifiedProcessor[] = []; - try { - currentProcessors = (await relatedReviewGraph.invoke({ - current_processors: JSON.stringify(state.currentProcessors, null, 2), - ex_answer: state.exAnswer, - previous_error: state.previousError, - pipeline_results: JSON.stringify(state.pipelineResults, null, 2), - })) as SimplifiedProcessor[]; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + + const currentProcessors = (await relatedReviewGraph.invoke({ + current_processors: JSON.stringify(state.currentProcessors, null, 2), + ex_answer: state.exAnswer, + previous_error: state.previousError, + pipeline_results: JSON.stringify(state.pipelineResults, null, 2), + })) as SimplifiedProcessor[]; + const processors = { type: 'related', processors: currentProcessors, diff --git a/x-pack/plugins/integration_assistant/server/graphs/unstructured/error.ts b/x-pack/plugins/integration_assistant/server/graphs/unstructured/error.ts index f88bfe05f9fe41..d002dd19d54394 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/unstructured/error.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/unstructured/error.ts @@ -6,12 +6,10 @@ */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { UnstructuredLogState } from '../../types'; import type { HandleUnstructuredNodeParams } from './types'; import { GROK_ERROR_PROMPT } from './prompts'; import { GROK_ERROR_EXAMPLE_ANSWER } from './constants'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleUnstructuredError({ state, @@ -20,20 +18,12 @@ export async function handleUnstructuredError({ const outputParser = new JsonOutputParser(); const grokErrorGraph = GROK_ERROR_PROMPT.pipe(model).pipe(outputParser); const currentPatterns = state.grokPatterns; - let pattern; - try { - pattern = await grokErrorGraph.invoke({ - current_pattern: JSON.stringify(currentPatterns, null, 2), - errors: JSON.stringify(state.errors, null, 2), - ex_answer: JSON.stringify(GROK_ERROR_EXAMPLE_ANSWER, null, 2), - }); - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + + const pattern = await grokErrorGraph.invoke({ + current_pattern: JSON.stringify(currentPatterns, null, 2), + errors: JSON.stringify(state.errors, null, 2), + ex_answer: JSON.stringify(GROK_ERROR_EXAMPLE_ANSWER, null, 2), + }); return { grokPatterns: pattern.grok_patterns, diff --git a/x-pack/plugins/integration_assistant/server/graphs/unstructured/unstructured.ts b/x-pack/plugins/integration_assistant/server/graphs/unstructured/unstructured.ts index aaa0bfe90030e7..42186e796275fd 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/unstructured/unstructured.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/unstructured/unstructured.ts @@ -5,12 +5,10 @@ * 2.0. */ import { JsonOutputParser } from '@langchain/core/output_parsers'; -import { GraphRecursionError } from '@langchain/langgraph'; import type { UnstructuredLogState } from '../../types'; import { GROK_MAIN_PROMPT } from './prompts'; import { GrokResult, HandleUnstructuredNodeParams } from './types'; import { GROK_EXAMPLE_ANSWER } from './constants'; -import { RecursionLimitError } from '../../lib/errors'; export async function handleUnstructured({ state, @@ -21,20 +19,11 @@ export async function handleUnstructured({ // Pick logSamples if there was no header detected. const samples = state.logSamples; - let pattern: GrokResult; - try { - pattern = (await grokMainGraph.invoke({ - samples: samples[0], - ex_answer: JSON.stringify(GROK_EXAMPLE_ANSWER, null, 2), - })) as GrokResult; - } catch (e) { - if (e instanceof GraphRecursionError) { - throw new RecursionLimitError(e.message); - } else { - throw e; - } - } + const pattern = (await grokMainGraph.invoke({ + samples: samples[0], + ex_answer: JSON.stringify(GROK_EXAMPLE_ANSWER, null, 2), + })) as GrokResult; return { grokPatterns: pattern.grok_patterns, diff --git a/x-pack/plugins/integration_assistant/server/lib/errors/recursion_limit_error.ts b/x-pack/plugins/integration_assistant/server/lib/errors/recursion_limit_error.ts index 84bb95a39582c8..794ba871266695 100644 --- a/x-pack/plugins/integration_assistant/server/lib/errors/recursion_limit_error.ts +++ b/x-pack/plugins/integration_assistant/server/lib/errors/recursion_limit_error.ts @@ -8,8 +8,6 @@ import { KibanaResponseFactory } from '@kbn/core/server'; import { ErrorCode, ErrorThatHandlesItsOwnResponse } from './types'; -const RECURSION_LIMIT_ERROR = 'Recursion limit reached.'; - export class RecursionLimitError extends Error implements ErrorThatHandlesItsOwnResponse { private readonly errorCode: ErrorCode = ErrorCode.RECURSION_LIMIT; @@ -20,7 +18,7 @@ export class RecursionLimitError extends Error implements ErrorThatHandlesItsOwn public sendResponse(res: KibanaResponseFactory) { return res.badRequest({ - body: { message: RECURSION_LIMIT_ERROR, attributes: { errorCode: this.errorCode } }, + body: { message: this.message, attributes: { errorCode: this.errorCode } }, }); } } diff --git a/x-pack/plugins/integration_assistant/server/lib/errors/translations.ts b/x-pack/plugins/integration_assistant/server/lib/errors/translations.ts new file mode 100644 index 00000000000000..a8b1c116d4fef0 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/lib/errors/translations.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const RECURSION_LIMIT_ANALYZE_LOGS_ERROR = i18n.translate( + 'xpack.plugins.integration_assistant.server.errors.recursionLimitAnalyzeLogsErrorMessage', + { + defaultMessage: + 'Please verify the format of log samples is correct and try again. Try with a fewer samples if error persists.', + } +); + +export const RECURSION_LIMIT_ERROR = i18n.translate( + 'xpack.plugins.integration_assistant.server.errors.recursionLimitReached', + { + defaultMessage: 'Max attempts exceeded. Please try again.', + } +); + +export const UNSUPPORTED_LOG_SAMPLES = i18n.translate( + 'xpack.plugins.integration_assistant.server.errors.unsupportedLogSamples', + { + defaultMessage: 'Unsupported log format in the samples', + } +); diff --git a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts index a64374ae07be8c..16a048252119cd 100644 --- a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts @@ -17,6 +17,11 @@ import { getLLMClass, getLLMType } from '../util/llm'; import { buildRouteValidationWithZod } from '../util/route_validation'; import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse, UnsupportedLogFormatError } from '../lib/errors'; +import { + RECURSION_LIMIT_ANALYZE_LOGS_ERROR, + UNSUPPORTED_LOG_SAMPLES, +} from '../lib/errors/translations'; +import { handleRecursionError } from './routes_util'; export function registerAnalyzeLogsRoutes( router: IRouter @@ -83,14 +88,18 @@ export function registerAnalyzeLogsRoutes( const graphResults = await graph.invoke(logFormatParameters, options); const graphLogFormat = graphResults.results.samplesFormat.name; if (graphLogFormat === 'unsupported' || graphLogFormat === 'csv') { - throw new UnsupportedLogFormatError('Unsupported log format in the samples'); + throw new UnsupportedLogFormatError(UNSUPPORTED_LOG_SAMPLES); } return res.ok({ body: AnalyzeLogsResponse.parse(graphResults) }); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(res); + } catch (err) { + try { + handleRecursionError(err, RECURSION_LIMIT_ANALYZE_LOGS_ERROR); + } catch (e) { + if (isErrorThatHandlesItsOwnResponse(e)) { + return e.sendResponse(res); + } } - return res.badRequest({ body: e }); + return res.badRequest({ body: err }); } }) ); diff --git a/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts b/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts index efaf01ea06cd00..eabb2cd332ab2d 100644 --- a/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/build_integration_routes.ts @@ -12,6 +12,8 @@ import type { IntegrationAssistantRouteHandlerContext } from '../plugin'; import { buildRouteValidationWithZod } from '../util/route_validation'; import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse } from '../lib/errors'; +import { handleRecursionError } from './routes_util'; +import { RECURSION_LIMIT_ERROR } from '../lib/errors/translations'; export function registerIntegrationBuilderRoutes( router: IRouter @@ -39,11 +41,15 @@ export function registerIntegrationBuilderRoutes( body: zippedIntegration, headers: { 'Content-Type': 'application/zip' }, }); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(response); + } catch (err) { + try { + handleRecursionError(err, RECURSION_LIMIT_ERROR); + } catch (e) { + if (isErrorThatHandlesItsOwnResponse(e)) { + return e.sendResponse(response); + } } - return response.customError({ statusCode: 500, body: e }); + return response.customError({ statusCode: 500, body: err }); } }) ); diff --git a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts index 32dc9645bd82dc..028374ad80962d 100644 --- a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts @@ -21,6 +21,8 @@ import { getLLMClass, getLLMType } from '../util/llm'; import { buildRouteValidationWithZod } from '../util/route_validation'; import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse } from '../lib/errors'; +import { handleRecursionError } from './routes_util'; +import { RECURSION_LIMIT_ERROR } from '../lib/errors/translations'; export function registerCategorizationRoutes( router: IRouter @@ -99,11 +101,15 @@ export function registerCategorizationRoutes( const results = await graph.invoke(parameters, options); return res.ok({ body: CategorizationResponse.parse(results) }); - } catch (e) { - if (isErrorThatHandlesItsOwnResponse(e)) { - return e.sendResponse(res); + } catch (err) { + try { + handleRecursionError(err, RECURSION_LIMIT_ERROR); + } catch (e) { + if (isErrorThatHandlesItsOwnResponse(e)) { + return e.sendResponse(res); + } } - return res.badRequest({ body: e }); + return res.badRequest({ body: err }); } } ) diff --git a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts index a4997ae7f341bc..3ee0c8004ecb2d 100644 --- a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts @@ -17,6 +17,8 @@ import { getLLMClass, getLLMType } from '../util/llm'; import { buildRouteValidationWithZod } from '../util/route_validation'; import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse } from '../lib/errors'; +import { handleRecursionError } from './routes_util'; +import { RECURSION_LIMIT_ERROR } from '../lib/errors/translations'; export function registerEcsRoutes(router: IRouter) { router.versioned @@ -93,11 +95,15 @@ export function registerEcsRoutes(router: IRouter) { router.versioned @@ -47,11 +49,15 @@ export function registerPipelineRoutes(router: IRouter) { router.versioned @@ -90,11 +92,15 @@ export function registerRelatedRoutes(router: IRouter