Skip to content

Commit e7cff86

Browse files
[9.3] [inference] handle array type without items property (#250350) (#250426)
# Backport This will backport the following commits from `main` to `9.3`: - [[inference] handle array type without items property (#250350)](#250350) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Pierre Gayvallet","email":"pierre.gayvallet@elastic.co"},"sourceCommit":{"committedDate":"2026-01-26T15:26:58Z","message":"[inference] handle array type without items property (#250350)\n\n## Summary\n\nFix a bug which was causing a runtime error when using tools with\n`array` schema without an `items` property (which is somewhat valid JSON\nschema but somehow getting away in the schema types we use for\ninference)","sha":"8571eaddf8e2b7e4fc89334dce0ca34e99948802","branchLabelMapping":{"^v9.4.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","backport:version","v9.4.0","v9.3.1"],"title":"[inference] handle array type without items property","number":250350,"url":"https://github.com/elastic/kibana/pull/250350","mergeCommit":{"message":"[inference] handle array type without items property (#250350)\n\n## Summary\n\nFix a bug which was causing a runtime error when using tools with\n`array` schema without an `items` property (which is somewhat valid JSON\nschema but somehow getting away in the schema types we use for\ninference)","sha":"8571eaddf8e2b7e4fc89334dce0ca34e99948802"}},"sourceBranch":"main","suggestedTargetBranches":["9.3"],"targetPullRequestStates":[{"branch":"main","label":"v9.4.0","branchLabelMappingKey":"^v9.4.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/250350","number":250350,"mergeCommit":{"message":"[inference] handle array type without items property (#250350)\n\n## Summary\n\nFix a bug which was causing a runtime error when using tools with\n`array` schema without an `items` property (which is somewhat valid JSON\nschema but somehow getting away in the schema types we use for\ninference)","sha":"8571eaddf8e2b7e4fc89334dce0ca34e99948802"}},{"branch":"9.3","label":"v9.3.1","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Pierre Gayvallet <pierre.gayvallet@elastic.co>
1 parent b7374f1 commit e7cff86

4 files changed

Lines changed: 47 additions & 10 deletions

File tree

x-pack/platform/packages/shared/ai-infra/inference-common/src/chat_complete/tool_schema.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface ToolSchemaTypeNumber extends ToolSchemaFragmentBase {
3737

3838
interface ToolSchemaTypeArray extends ToolSchemaFragmentBase {
3939
type: 'array';
40-
items: Exclude<ToolSchemaType, ToolSchemaTypeArray>;
40+
items?: Exclude<ToolSchemaType, ToolSchemaTypeArray>;
4141
}
4242

4343
/**
@@ -64,9 +64,10 @@ type FromToolSchemaObject<TToolSchemaObject extends ToolSchemaTypeObject> =
6464
>
6565
: never;
6666

67-
type FromToolSchemaArray<TToolSchemaObject extends ToolSchemaTypeArray> = Array<
68-
FromToolSchema<TToolSchemaObject['items']>
69-
>;
67+
type FromToolSchemaArray<TToolSchemaObject extends ToolSchemaTypeArray> =
68+
TToolSchemaObject['items'] extends Exclude<ToolSchemaType, ToolSchemaTypeArray>
69+
? Array<FromToolSchema<TToolSchemaObject['items']>>
70+
: unknown[];
7071

7172
type FromToolSchemaString<TToolSchemaString extends ToolSchemaTypeString> =
7273
TToolSchemaString extends { const: string }

x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/bedrock/convert_tools.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export function fixSchemaArrayProperties<T extends ToolSchemaType>(schemaPart: T
9494
description: schemaPart.description
9595
? `${schemaPart.description}. Must be provided as a JSON array`
9696
: 'Must be provided as a JSON array',
97-
items: fixSchemaArrayProperties(schemaPart.items),
97+
items: schemaPart.items ? fixSchemaArrayProperties(schemaPart.items) : {},
9898
};
9999
}
100100

x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/gemini/gemini_adapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ function toolSchemaToGemini({ schema }: { schema: ToolSchema }): Gemini.Function
119119
return {
120120
type: Gemini.SchemaType.ARRAY,
121121
description: def.description,
122-
items: convertSchemaType({ def: def.items }),
122+
// @ts-expect-error - items is optional (empty object means any)
123+
items: def.items ? convertSchemaType({ def: def.items }) : {},
123124
};
124125
case 'object':
125126
return {

x-pack/platform/plugins/shared/inference/server/chat_complete/adapters/openai/to_openai.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,55 @@ import type { Message, ToolOptions, InferenceConnector } from '@kbn/inference-co
1919
import { MessageRole } from '@kbn/inference-common';
2020
import { OpenAiProviderType } from './types';
2121

22+
/**
23+
* Recursively processes a schema to ensure all array types have an `items` property.
24+
* OpenAI requires `items` to be present for array types.
25+
*/
26+
function ensureArrayItems(schema: Record<string, unknown>): Record<string, unknown> {
27+
if (typeof schema !== 'object' || schema === null) {
28+
return schema;
29+
}
30+
31+
const result = { ...schema };
32+
33+
if (result.type === 'array' && !('items' in result)) {
34+
result.items = {};
35+
}
36+
37+
if (result.items && typeof result.items === 'object') {
38+
result.items = ensureArrayItems(result.items as Record<string, unknown>);
39+
}
40+
41+
if (result.properties && typeof result.properties === 'object') {
42+
const properties = result.properties as Record<string, unknown>;
43+
result.properties = Object.fromEntries(
44+
Object.entries(properties).map(([key, value]) => [
45+
key,
46+
ensureArrayItems(value as Record<string, unknown>),
47+
])
48+
);
49+
}
50+
51+
return result;
52+
}
53+
2254
export function toolsToOpenAI(
2355
tools: ToolOptions['tools']
2456
): OpenAI.ChatCompletionCreateParams['tools'] {
2557
return tools
2658
? Object.entries(tools).map(([toolName, { description, schema }]) => {
59+
const parameters = schema ?? {
60+
type: 'object' as const,
61+
properties: {},
62+
};
2763
return {
2864
type: 'function',
2965
function: {
3066
name: toolName,
3167
description,
32-
parameters: (schema ?? {
33-
type: 'object' as const,
34-
properties: {},
35-
}) as unknown as Record<string, unknown>,
68+
parameters: ensureArrayItems(
69+
parameters as unknown as Record<string, unknown>
70+
) as unknown as Record<string, unknown>,
3671
},
3772
};
3873
})

0 commit comments

Comments
 (0)