Skip to content

Commit 04b294e

Browse files
[onechat] add first set of base tools (elastic#223367)
## Summary Fix elastic/search-team#10121 Add a base set of retrieval oriented tools, and expose them to the default agent. ## Tools **Warning: names are still TBD** We're starting to see two different "layers" of tool appear: "simple" tools, which are doing a simple programmatic (understand: no LLM) task, and "smart" tools, which are more like workflows, with some of the steps relying on a LLM. This PR introduces the following tools: ### Simple tools Simple tools (name TBD) are "programmatic" tools not relying on an LLM for their execution. This PR introduces this base set of tools: - `get_document_by_id`: resolve a full document based on its id/index. - `list_indices`: list the indices the current user has access to. - `get_index_mappings`: retrieve the full mappings based for a given index. - `execute_esql`: executes a provided ES|QL query ### Smart tools Smart tools can have multiple internal steps (even if it remains an implementation detail), and are using LLM calls for some, or all, of them. *Note: there are huge potential areas of improvement in the current implementation of all those smart tools. One of the intent of this work is precisely to identify such areas of improvement* #### `index_explorer` Based on a natural language query, returns a list of indices that should be searched, and their corresponding mappings. <img width="984" alt="Screenshot 2025-06-17 at 16 44 32" src="https://github.com/user-attachments/assets/edff3964-31e3-40ea-a761-adf7c45fcb17" /> #### `generate_esql` Based on a natural language query, generates an ES|QL query. - use the `nl-2-esql` task under the hood - optional use `index-explorer` if `index` is not specified. <img width="891" alt="Screenshot 2025-06-17 at 16 51 56" src="https://github.com/user-attachments/assets/ce141d6b-dd4f-4eb9-ab32-823b81bc810b" /> #### `relevance_search` Perform a "full-text search" based on given term and returns the most relevant highlights. <img width="1071" alt="Screenshot 2025-06-17 at 16 59 49" src="https://github.com/user-attachments/assets/1f873e70-e277-424d-93e4-24b269a554e5" /> #### `natural_language_search` Retrieve data based on a natural language query. Converts a natural language query to an ES|QL one then executes it, useing `generate_esql` and `execute_esql` under the hood. <img width="768" alt="Screenshot 2025-06-18 at 08 31 52" src="https://github.com/user-attachments/assets/cb319831-17ed-4ad7-9e1f-2fe90c2472fa" /> ## Researcher assistant The second part of this PR is implementing a researcher agent for deep research tasks. The researcher assistant is following a very classic "act->process->reflect" cycle. <img width="960" alt="Screenshot 2025-06-18 at 09 16 17" src="https://github.com/user-attachments/assets/c24be323-ecf2-4c43-88fb-eaf874b18afc" /> The implementation of the cycle is currently as follow: **1. Act** Given a research topic, the research history and a list of tools, select the tool best suited to search for this topic, and call it. The tools exposed to the agent in this phase are: - `index_explorer` - `relevance_search` - `nl_search` *Note: later the whole `act` step could evolve to instead call sub search agent with planning and multi-step execution.* **2. Process** Process the results from the latest `act` phase and create a corresponding entry in the search log. At the moment, we're simply storing the whole tool call + results to the search log in a LLM-friendly format. **3. Reflect** Based on the main research query and the search log, identify where the information collected are enough to answer the question. If not, identify follow-up questions or sub-problems that it would be useful to solve to gather more information ## What is out of scope of the current PR - Figuring out which set of tools should be exposed by default to the main agent (right now, all the tools listed in this PR are) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
1 parent d80885a commit 04b294e

75 files changed

Lines changed: 2405 additions & 66 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ x-pack/platform/packages/shared/ml/runtime_field_utils @elastic/ml-ui
868868
x-pack/platform/packages/shared/ml/trained_models_utils @elastic/ml-ui
869869
x-pack/platform/packages/shared/onechat/onechat-browser @elastic/workchat-eng
870870
x-pack/platform/packages/shared/onechat/onechat-common @elastic/workchat-eng
871+
x-pack/platform/packages/shared/onechat/onechat-genai-utils @elastic/workchat-eng
871872
x-pack/platform/packages/shared/onechat/onechat-server @elastic/workchat-eng
872873
x-pack/platform/packages/shared/security/api_key_management @elastic/kibana-security
873874
x-pack/platform/packages/shared/security/form_components @elastic/kibana-security

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@
739739
"@kbn/oidc-provider-plugin": "link:x-pack/test/security_api_integration/plugins/oidc_provider",
740740
"@kbn/onechat-browser": "link:x-pack/platform/packages/shared/onechat/onechat-browser",
741741
"@kbn/onechat-common": "link:x-pack/platform/packages/shared/onechat/onechat-common",
742+
"@kbn/onechat-genai-utils": "link:x-pack/platform/packages/shared/onechat/onechat-genai-utils",
742743
"@kbn/onechat-plugin": "link:x-pack/platform/plugins/shared/onechat",
743744
"@kbn/onechat-server": "link:x-pack/platform/packages/shared/onechat/onechat-server",
744745
"@kbn/open-telemetry-instrumented-plugin": "link:src/platform/test/common/plugins/otel_metrics",

tsconfig.base.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,8 @@
14061406
"@kbn/onechat-browser/*": ["x-pack/platform/packages/shared/onechat/onechat-browser/*"],
14071407
"@kbn/onechat-common": ["x-pack/platform/packages/shared/onechat/onechat-common"],
14081408
"@kbn/onechat-common/*": ["x-pack/platform/packages/shared/onechat/onechat-common/*"],
1409+
"@kbn/onechat-genai-utils": ["x-pack/platform/packages/shared/onechat/onechat-genai-utils"],
1410+
"@kbn/onechat-genai-utils/*": ["x-pack/platform/packages/shared/onechat/onechat-genai-utils/*"],
14091411
"@kbn/onechat-plugin": ["x-pack/platform/plugins/shared/onechat"],
14101412
"@kbn/onechat-plugin/*": ["x-pack/platform/plugins/shared/onechat/*"],
14111413
"@kbn/onechat-server": ["x-pack/platform/packages/shared/onechat/onechat-server"],

x-pack/platform/packages/shared/onechat/onechat-common/agents/events.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { StructuredToolIdentifier } from '../tools/tools';
1212
export enum ChatAgentEventType {
1313
toolCall = 'toolCall',
1414
toolResult = 'toolResult',
15+
reasoning = 'reasoning',
1516
messageChunk = 'messageChunk',
1617
messageComplete = 'messageComplete',
1718
roundComplete = 'roundComplete',
@@ -53,6 +54,18 @@ export const isToolResultEvent = (event: OnechatEvent<string, any>): event is To
5354
return event.type === ChatAgentEventType.toolResult;
5455
};
5556

57+
// reasoning
58+
59+
export interface ReasoningEventData {
60+
reasoning: string;
61+
}
62+
63+
export type ReasoningEvent = ChatAgentEventBase<ChatAgentEventType.reasoning, ReasoningEventData>;
64+
65+
export const isReasoningEvent = (event: OnechatEvent<string, any>): event is ReasoningEvent => {
66+
return event.type === ChatAgentEventType.reasoning;
67+
};
68+
5669
// Message chunk
5770

5871
export interface MessageChunkEventData {
@@ -116,6 +129,7 @@ export const isRoundCompleteEvent = (
116129
export type ChatAgentEvent =
117130
| ToolCallEvent
118131
| ToolResultEvent
132+
| ReasoningEvent
119133
| MessageChunkEvent
120134
| MessageCompleteEvent
121135
| RoundCompleteEvent;

x-pack/platform/packages/shared/onechat/onechat-common/agents/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export {
1919
type ToolResultEventData,
2020
type ToolCallEvent,
2121
type ToolCallEventData,
22+
type ReasoningEvent,
23+
type ReasoningEventData,
2224
type MessageChunkEventData,
2325
type MessageChunkEvent,
2426
type MessageCompleteEventData,
@@ -27,6 +29,7 @@ export {
2729
type RoundCompleteEvent,
2830
isToolCallEvent,
2931
isToolResultEvent,
32+
isReasoningEvent,
3033
isMessageChunkEvent,
3134
isMessageCompleteEvent,
3235
isRoundCompleteEvent,

x-pack/platform/packages/shared/onechat/onechat-common/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export {
2323
createBuiltinToolId,
2424
builtinToolProviderId,
2525
unknownToolProviderId,
26+
BuiltinToolIds,
27+
BuiltinTags,
2628
} from './tools';
2729
export {
2830
OnechatErrorCode,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
/**
9+
* Ids of built-in onechat tools
10+
*/
11+
export const BuiltinToolIds = {
12+
indexExplorer: 'index_explorer',
13+
relevanceSearch: 'relevance_search',
14+
naturalLanguageSearch: 'nl_search',
15+
listIndices: 'list_indices',
16+
getIndexMapping: 'get_index_mapping',
17+
getDocumentById: 'get_document_by_id',
18+
generateEsql: 'generate_esql',
19+
executeEsql: 'execute_esql',
20+
researcherAgent: 'researcher_agent',
21+
};
22+
23+
/**
24+
* Common set of tags used for platform tools.
25+
*/
26+
export const BuiltinTags = {
27+
/**
28+
* Tag associated to tools related to data retrieval
29+
*/
30+
retrieval: 'retrieval',
31+
};

x-pack/platform/packages/shared/onechat/onechat-common/tools/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ export {
2323
builtinToolProviderId,
2424
unknownToolProviderId,
2525
} from './tools';
26+
export { BuiltinToolIds, BuiltinTags } from './constants';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# @kbn/onechat-genai-utils
2+
3+
Empty package generated by @kbn/generate
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { KibanaRequest } from '@kbn/core-http-server';
9+
import type { PlainIdToolIdentifier, ToolProviderId, ToolDescriptor } from '@kbn/onechat-common';
10+
import type { ToolProvider, ExecutableTool } from '@kbn/onechat-server';
11+
12+
export interface ByToolIdRule {
13+
type: 'by_tool_id';
14+
providerId: ToolProviderId;
15+
toolIds: PlainIdToolIdentifier[];
16+
}
17+
18+
export interface ByProviderIdRule {
19+
type: 'by_provider_id';
20+
providerId: ToolProviderId;
21+
}
22+
23+
export type ToolFilterRule = ByToolIdRule | ByProviderIdRule;
24+
25+
const matches = (rule: ToolFilterRule, tool: ToolDescriptor): boolean => {
26+
if (rule.type === 'by_tool_id') {
27+
return tool.meta.providerId === rule.providerId && rule.toolIds.includes(tool.id);
28+
} else if (rule.type === 'by_provider_id') {
29+
return tool.meta.providerId === rule.providerId;
30+
} else {
31+
throw new Error('Unknown rule type');
32+
}
33+
};
34+
35+
const anyMatch = (rules: ToolFilterRule[], tool: ToolDescriptor): boolean => {
36+
return rules.some((rule) => matches(rule, tool));
37+
};
38+
39+
export const filterProviderTools = async ({
40+
provider,
41+
rules,
42+
request,
43+
}: {
44+
provider: ToolProvider;
45+
rules: ToolFilterRule[];
46+
request: KibanaRequest;
47+
}): Promise<ExecutableTool[]> => {
48+
const tools = await provider.list({ request });
49+
return tools.filter((tool) => anyMatch(rules, tool));
50+
};

0 commit comments

Comments
 (0)