diff --git a/packages/kbn-io-ts-utils/src/strict_keys_rt/index.test.ts b/packages/kbn-io-ts-utils/src/strict_keys_rt/index.test.ts index 3751e3b2674af..4105d0c6c18f1 100644 --- a/packages/kbn-io-ts-utils/src/strict_keys_rt/index.test.ts +++ b/packages/kbn-io-ts-utils/src/strict_keys_rt/index.test.ts @@ -206,7 +206,38 @@ describe('strictKeysRt', () => { { type: t.array(t.type({ foo: t.string })), passes: [[{ foo: 'bar' }], [{ foo: 'baz' }, { foo: 'bar' }]], - fails: [], + fails: [{ foo: 'bar', bar: 'foo' }], + }, + { + type: t.type({ + nestedArray: t.array( + t.type({ + bar: t.string, + }) + ), + }), + passes: [ + { + nestedArray: [], + }, + { + nestedArray: [ + { + bar: 'foo', + }, + ], + }, + ], + fails: [ + { + nestedArray: [ + { + bar: 'foo', + foo: 'bar', + }, + ], + }, + ], }, ]; diff --git a/packages/kbn-io-ts-utils/src/strict_keys_rt/index.ts b/packages/kbn-io-ts-utils/src/strict_keys_rt/index.ts index 268b9055959c2..8e097d03300db 100644 --- a/packages/kbn-io-ts-utils/src/strict_keys_rt/index.ts +++ b/packages/kbn-io-ts-utils/src/strict_keys_rt/index.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { either, isRight } from 'fp-ts/lib/Either'; -import { difference, isPlainObject, forEach } from 'lodash'; +import { difference, isPlainObject, forEach, isArray, castArray } from 'lodash'; import { MergeType } from '../merge_rt'; /* @@ -100,11 +100,31 @@ function getHandledKeys>( keys.handled.add(ownPrefix); } + const processObject = (typeForObject: t.Mixed, objectToProcess: Record) => { + const nextKeys = getHandledKeys(typeForObject, objectToProcess, ownPrefix); + nextKeys.all.forEach((k) => keys.all.add(k)); + nextKeys.handled.forEach((k) => keys.handled.add(k)); + }; + if (isPlainObject(value)) { - handlingTypes.forEach((i) => { - const nextKeys = getHandledKeys(i, value as Record, ownPrefix); - nextKeys.all.forEach((k) => keys.all.add(k)); - nextKeys.handled.forEach((k) => keys.handled.add(k)); + handlingTypes.forEach((typeAtIndex) => { + processObject(typeAtIndex, value as Record); + }); + } + + if (isArray(value)) { + handlingTypes.forEach((typeAtIndex) => { + if (!isParsableType(typeAtIndex) || typeAtIndex._tag !== 'ArrayType') { + return; + } + + const innerType = typeAtIndex.type; + + castArray(value).forEach((valueAtIndex) => { + if (isPlainObject(valueAtIndex)) { + processObject(innerType, valueAtIndex as Record); + } + }); }); } }); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts index 68595e457a355..eb34e2bb2ee5e 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts @@ -115,6 +115,7 @@ export enum KnowledgeBaseType { } export interface ObservabilityAIAssistantScreenContextRequest { + starterPrompts?: StarterPrompt[]; screenDescription?: string; data?: Array<{ name: string; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/runtime_types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/runtime_types.ts index 1c4de53fc4420..968c182ed75cf 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/runtime_types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/runtime_types.ts @@ -14,6 +14,7 @@ import { type Message, MessageRole, type ObservabilityAIAssistantScreenContextRequest, + type StarterPrompt, } from '../../common/types'; const serializeableRt = t.any; @@ -129,6 +130,12 @@ export const functionRt = t.intersection([ }), ]); +export const starterPromptRt: t.Type = t.type({ + title: t.string, + prompt: t.string, + icon: t.any, +}); + export const screenContextRt: t.Type = t.partial({ description: t.string, data: t.array( @@ -139,4 +146,6 @@ export const screenContextRt: t.Type