[workchat] prepare the workflow framework (#218138)

## Summary

Setup the foundations of the workflow framework, adding types and
initial implementation.


## Examples

### Looping over some input to call the LLM

**workflow**
```typescript
{
      id: 'my_test_workflow',
      name: 'Just a test workflow',
      type: 'graph',
      inputs: [
        {
          name: 'input',
          type: 'array',
          required: true,
        },
      ],
      steps: [
        {
          id: 'mainLoop',
          type: NodeType.loop,
          configuration: {
            inputList: 'input',
            itemVar: 'prompt',
            output: {
              source: 'output',
              destination: 'results',
            },
            steps: [
              {
                id: 'step1',
                type: NodeType.prompt,
                configuration: {
                  prompt:
                    'How much is {prompt}? Please just output the result without anything else',
                  output: 'output',
                },
              },
            ],
          },
        },
      ],
      outputs: [
        {
          name: 'results',
          ref: 'results',
        },
      ],
    }
``` 

**Running**
```ts
workchatFramework.workflows.run({
    id: 'my_test_workflow',
    inputs: { input: ['3 + 3', '7 - 1', '4 * 6'] },
    request,
})
```

**Output**

```ts
 {
  runId: '6f254746-57fc-4fd3-8bfa-25014725f53f',
  output: { results: [ '6', '6', '24' ] }
}
```

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Pierre Gayvallet 2025-04-22 22:04:26 +02:00 committed by GitHub
parent afc004a520
commit 29a81d8972
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
169 changed files with 6023 additions and 5 deletions

4
.github/CODEOWNERS vendored
View file

@ -938,6 +938,9 @@ x-pack/platform/plugins/shared/streams_app @elastic/streams-program-team
x-pack/platform/plugins/shared/task_manager @elastic/response-ops
x-pack/platform/plugins/shared/timelines @elastic/security-threat-hunting-investigations
x-pack/platform/plugins/shared/triggers_actions_ui @elastic/response-ops
x-pack/solutions/chat/packages/wc-framework-types-browser @elastic/search-kibana
x-pack/solutions/chat/packages/wc-framework-types-common @elastic/search-kibana
x-pack/solutions/chat/packages/wc-framework-types-server @elastic/search-kibana
x-pack/solutions/chat/packages/wc-genai-utils @elastic/search-kibana
x-pack/solutions/chat/packages/wc-index-schema-builder @elastic/search-kibana
x-pack/solutions/chat/packages/wc-integration-utils @elastic/search-kibana
@ -949,6 +952,7 @@ x-pack/solutions/chat/plugins/wci-external-server @elastic/search-kibana
x-pack/solutions/chat/plugins/wci-index-source @elastic/search-kibana
x-pack/solutions/chat/plugins/wci-salesforce @elastic/search-kibana
x-pack/solutions/chat/plugins/workchat-app @elastic/search-kibana
x-pack/solutions/chat/plugins/workchat-framework @elastic/search-kibana
x-pack/solutions/observability/packages/alert-details @elastic/obs-ux-management-team
x-pack/solutions/observability/packages/alerting-test-data @elastic/obs-ux-management-team
x-pack/solutions/observability/packages/get-padded-alert-time-range-util @elastic/obs-ux-management-team

View file

@ -10,6 +10,7 @@ xpack.cloud.serverless.project_type: search
uiSettings.overrides.defaultRoute: /app/workchat
## Enable workchat plugins
xpack.workchatFramework.enabled: true
xpack.workchatApp.enabled: true
xpack.wciSalesforce.enabled: true
xpack.wciIndexSource.enabled: true

View file

@ -237,3 +237,4 @@ mapped_pages:
| [wciIndexSource](https://github.com/elastic/kibana/blob/main/x-pack/solutions/chat/plugins/wci-index-source/README.md) | WorkChat Index Source integration plugin that provides functionality to search Elasticsearch indices for the WorkChat application. |
| [wciSalesforce](https://github.com/elastic/kibana/blob/main/x-pack/solutions/chat/plugins/wci-salesforce/README.md) | WorkChat Salesforce integration plugin that provides Salesforce-specific functionality for the WorkChat application. |
| [workchatApp](https://github.com/elastic/kibana/blob/main/x-pack/solutions/chat/plugins/workchat-app/README.md) | WorkChat application plugin |
| [workchatFramework](https://github.com/elastic/kibana/blob/main/x-pack/solutions/chat/plugins/workchat-framework/README.md) | WorkChat framework plugin |

View file

@ -1034,6 +1034,9 @@
"@kbn/visualization-utils": "link:src/platform/packages/shared/kbn-visualization-utils",
"@kbn/visualizations-plugin": "link:src/platform/plugins/shared/visualizations",
"@kbn/watcher-plugin": "link:x-pack/platform/plugins/private/watcher",
"@kbn/wc-framework-types-browser": "link:x-pack/solutions/chat/packages/wc-framework-types-browser",
"@kbn/wc-framework-types-common": "link:x-pack/solutions/chat/packages/wc-framework-types-common",
"@kbn/wc-framework-types-server": "link:x-pack/solutions/chat/packages/wc-framework-types-server",
"@kbn/wc-genai-utils": "link:x-pack/solutions/chat/packages/wc-genai-utils",
"@kbn/wc-index-schema-builder": "link:x-pack/solutions/chat/packages/wc-index-schema-builder",
"@kbn/wc-integration-utils": "link:x-pack/solutions/chat/packages/wc-integration-utils",
@ -1044,6 +1047,7 @@
"@kbn/wci-salesforce": "link:x-pack/solutions/chat/plugins/wci-salesforce",
"@kbn/wci-server": "link:x-pack/solutions/chat/packages/wci-server",
"@kbn/workchat-app": "link:x-pack/solutions/chat/plugins/workchat-app",
"@kbn/workchat-framework-plugin": "link:x-pack/solutions/chat/plugins/workchat-framework",
"@kbn/xstate-utils": "link:src/platform/packages/shared/kbn-xstate-utils",
"@kbn/zod": "link:src/platform/packages/shared/kbn-zod",
"@kbn/zod-helpers": "link:src/platform/packages/shared/kbn-zod-helpers",

View file

@ -819,6 +819,13 @@
"state",
"type"
],
"onechat_workflow": [
"access_control",
"access_control.public",
"categories",
"user_id",
"workflow_id"
],
"osquery-manager-usage-metric": [
"count",
"errors"

View file

@ -2749,6 +2749,27 @@
}
}
},
"onechat_workflow": {
"dynamic": false,
"properties": {
"access_control": {
"properties": {
"public": {
"type": "boolean"
}
}
},
"categories": {
"type": "keyword"
},
"user_id": {
"type": "keyword"
},
"workflow_id": {
"type": "keyword"
}
}
},
"osquery-manager-usage-metric": {
"properties": {
"count": {

View file

@ -195,3 +195,4 @@ pageLoadAssetSize:
wciIndexSource: 40000
wciSalesforce: 25000
workchatApp: 25000
workchatFramework: 25000

View file

@ -2124,6 +2124,12 @@
"@kbn/visualizations-plugin/*": ["src/platform/plugins/shared/visualizations/*"],
"@kbn/watcher-plugin": ["x-pack/platform/plugins/private/watcher"],
"@kbn/watcher-plugin/*": ["x-pack/platform/plugins/private/watcher/*"],
"@kbn/wc-framework-types-browser": ["x-pack/solutions/chat/packages/wc-framework-types-browser"],
"@kbn/wc-framework-types-browser/*": ["x-pack/solutions/chat/packages/wc-framework-types-browser/*"],
"@kbn/wc-framework-types-common": ["x-pack/solutions/chat/packages/wc-framework-types-common"],
"@kbn/wc-framework-types-common/*": ["x-pack/solutions/chat/packages/wc-framework-types-common/*"],
"@kbn/wc-framework-types-server": ["x-pack/solutions/chat/packages/wc-framework-types-server"],
"@kbn/wc-framework-types-server/*": ["x-pack/solutions/chat/packages/wc-framework-types-server/*"],
"@kbn/wc-genai-utils": ["x-pack/solutions/chat/packages/wc-genai-utils"],
"@kbn/wc-genai-utils/*": ["x-pack/solutions/chat/packages/wc-genai-utils/*"],
"@kbn/wc-index-schema-builder": ["x-pack/solutions/chat/packages/wc-index-schema-builder"],
@ -2148,6 +2154,8 @@
"@kbn/whereis-pkg-cli/*": ["packages/kbn-whereis-pkg-cli/*"],
"@kbn/workchat-app": ["x-pack/solutions/chat/plugins/workchat-app"],
"@kbn/workchat-app/*": ["x-pack/solutions/chat/plugins/workchat-app/*"],
"@kbn/workchat-framework-plugin": ["x-pack/solutions/chat/plugins/workchat-framework"],
"@kbn/workchat-framework-plugin/*": ["x-pack/solutions/chat/plugins/workchat-framework/*"],
"@kbn/xstate-utils": ["src/platform/packages/shared/kbn-xstate-utils"],
"@kbn/xstate-utils/*": ["src/platform/packages/shared/kbn-xstate-utils/*"],
"@kbn/yarn-lock-validator": ["packages/kbn-yarn-lock-validator"],

View file

@ -0,0 +1,3 @@
# @kbn/wc-framework-types-browser
Exposes browser-side types and utilities for the wc framework.

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
export type {
WorkflowDefinition,
GraphWorkflowDefinition,
FunctionWorkflowDefinition,
} from './src/workflows';

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../..',
roots: ['<rootDir>/x-pack/solutions/chat/packages/wc-framework-types-browser'],
};

View file

@ -0,0 +1,7 @@
{
"type": "shared-common",
"id": "@kbn/wc-framework-types-browser",
"owner": "@elastic/search-kibana",
"group": "chat",
"visibility": "private"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/wc-framework-types-browser",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -0,0 +1,15 @@
/*
* 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 type {
GraphWorkflowDefinition as ServerGraphWorkflowDefinition,
FunctionWorkflowDefinition as ServerFunctionWorkflowDefinition,
} from '@kbn/wc-framework-types-server';
export type FunctionWorkflowDefinition = Omit<ServerFunctionWorkflowDefinition, 'handler'>;
export type GraphWorkflowDefinition = ServerGraphWorkflowDefinition;
export type WorkflowDefinition = FunctionWorkflowDefinition | GraphWorkflowDefinition;

View file

@ -0,0 +1,21 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/wc-framework-types-server",
]
}

View file

@ -0,0 +1,3 @@
# @kbn/wc-framework-types-common
Exposes common (browser+server) types and utilities for the wc framework.

View file

@ -0,0 +1,21 @@
/*
* 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.
*/
export { type ToolDescriptor, BuiltInToolId } from './src/tools';
export {
NodeType,
type NodeProgressionEvent,
type NodeEvent,
type NodeEventMeta,
} from './src/nodes';
export {
type WorkflowEvent,
type WorkflowProgressionEvent,
type WorkflowRunEvent,
isNodeProgressionEvent,
isWorkflowProgressionEvent,
} from './src/workflows';

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../..',
roots: ['<rootDir>/x-pack/solutions/chat/packages/wc-framework-types-common'],
};

View file

@ -0,0 +1,7 @@
{
"type": "shared-common",
"id": "@kbn/wc-framework-types-common",
"owner": "@elastic/search-kibana",
"group": "chat",
"visibility": "private"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/wc-framework-types-common",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export type { NodeEvent, NodeProgressionEvent, NodeEventMeta } from './node_events';
export { NodeType } from './node_types';

View file

@ -0,0 +1,50 @@
/*
* 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.
*/
/**
* Node progression event.
*
* Can be emitted to do real time status update during a workflow execution.
*/
export interface NodeProgressionEvent {
/**
* The type of event, `node_progression`.
*/
eventType: 'node_progression';
/**
* Meta bound to this event
*/
meta: NodeEventMeta;
/**
* A human-readable label to display for this progression event.
*/
label: string;
/**
* Optional, arbitrary data associated with this event.
*/
data?: Record<string, string>;
}
/**
* Meta information attached to a node event.
*/
export interface NodeEventMeta {
/**
* The id of the node this event was fired from.
*/
nodeId: string;
/**
* The type of the node this event was fired from.
*/
nodeType: string;
/**
* The id of the workflow this event was fired from
*/
workflowId: string;
}
export type NodeEvent = NodeProgressionEvent;

View file

@ -0,0 +1,19 @@
/*
* 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.
*/
export enum NodeType {
// flow nodes
parallelSequences = 'parallelSequences',
loop = 'loop',
// action nodes
toolExecution = 'toolExecution',
workflowExecution = 'workflowExecution',
// LLM nodes
prompt = 'prompt',
// conditional nodes
intentRecognition = 'intentRecognition',
}

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export type { ToolDescriptor } from './tool';
export { BuiltInToolId } from './tool_names';

View file

@ -0,0 +1,28 @@
/*
* 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.
*/
/**
* Represents the definition of a tool, without its handler or schema.
*/
export interface ToolDescriptor {
/**
* A unique id for this tool.
*/
id: string;
/**
* Name of the tool, which will be exposed to the LLM.
*/
name: string;
/**
* The description for this tool, which will be exposed to the LLM.
*/
description: string;
/**
* An arbitrary record of meta, that can be used for filtering / identifying tools in workflows.
*/
meta?: Record<string, string>;
}

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
/**
* List of built-in tool names.
*/
export enum BuiltInToolId {
calculator = 'calculator',
}

View file

@ -0,0 +1,14 @@
/*
* 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.
*/
export {
type WorkflowProgressionEvent,
type WorkflowEvent,
type WorkflowRunEvent,
isWorkflowProgressionEvent,
isNodeProgressionEvent,
} from './workflow_events';

View file

@ -0,0 +1,60 @@
/*
* 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 type { NodeEvent, NodeProgressionEvent } from '../nodes';
/**
* Workflow progression event.
*
* Can be emitted to do real time status update during a workflow execution.
*/
export interface WorkflowProgressionEvent {
/**
* The type of event, `workflow_progression`.
*/
eventType: 'workflow_progression';
/**
* Meta bound to this event
*/
meta: {
/**
* The id of the workflow this event was fired from
*/
workflowId: string;
};
/**
* A human-readable label to display for this progression event.
*/
label: string;
/**
* Optional, arbitrary data associated with this event.
*/
data?: Record<string, string>;
}
export type WorkflowEvent = WorkflowProgressionEvent;
/**
* Represent all type of events that can be fired during a workflow run
*/
export type WorkflowRunEvent = NodeEvent | WorkflowEvent;
/**
* Checks if the given workflow run event is a {@link NodeProgressionEvent}
*/
export const isNodeProgressionEvent = (event: WorkflowRunEvent): event is NodeProgressionEvent => {
return event.eventType === 'node_progression';
};
/**
* Checks if the given workflow run event is a {@link WorkflowProgressionEvent}
*/
export const isWorkflowProgressionEvent = (
event: WorkflowRunEvent
): event is WorkflowProgressionEvent => {
return event.eventType === 'workflow_progression';
};

View file

@ -0,0 +1,19 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}

View file

@ -0,0 +1,3 @@
# @kbn/wc-framework-types-server
Exposes server-side types and utilities for the wc framework.

View file

@ -0,0 +1,63 @@
/*
* 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.
*/
export { type Tool, type ToolProvider, createToolProvider } from './src/tools';
export type { ModelProvider } from './src/models';
export type { WorkflowState } from './src/state';
export type {
NodeDefinition,
BuiltInNodeDefinition,
NodeTypeDefinition,
NodeRunnerFactory,
NodeFactoryContext,
NodeFactoryServices,
NodeFactoryBaseServices,
NodeRunner,
RunNodeParams,
NodeEventReporter,
NodeProgressionReporterEvent,
CustomServicesProvider,
ScopedNodeProvider,
NodeSequence,
SequenceBranch,
NodeTypeToNodeConfigMap,
ParallelSequencesNodeConfigType,
PromptNodeConfigType,
WorkflowExecutionNodeConfigType,
ToolExecutionNodeConfigType,
LoopNodeConfigType,
IntentRecognitionNodeConfigType,
IntentRecognitionBranch,
} from './src/nodes';
export type {
BaseWorkflowDefinition,
GraphWorkflowDefinition,
FunctionWorkflowDefinition,
FunctionWorkflowHandlerParams,
WorkflowDefinition,
WorkflowDefinitionInput,
WorkflowDefinitionOutput,
WorkflowInputType,
WorkflowRunEventHandler,
WorkflowRunner,
RunWorkflowParams,
RunWorkflowOutput,
ScopedWorkflowProvider,
ScopedRunner,
ScopedRunnerRunNodeParams,
ScopedRunnerRunWorkflowParams,
ScopedRunnerRunWorkflowOutput,
} from './src/workflows';
export type { Registry, Provider, AsyncProvider } from './src/utils';
export {
WorkflowExecutionError,
isWorkflowExecutionError,
type WorkflowExecutionErrorType,
type WorkflowExecutionErrorMeta,
} from './src/errors';
export type { NodeRef, WorkflowRef, CallChainRef, CallChain } from './src/call_chain';
export type { WorkflowExecutionState } from './src/execution_state';

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../..',
roots: ['<rootDir>/x-pack/solutions/chat/packages/wc-framework-types-server'],
};

View file

@ -0,0 +1,7 @@
{
"type": "shared-common",
"id": "@kbn/wc-framework-types-server",
"owner": "@elastic/search-kibana",
"group": "chat",
"visibility": "private"
}

View file

@ -0,0 +1,6 @@
{
"name": "@kbn/wc-framework-types-server",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
export interface NodeRef {
type: 'node';
id: string;
}
export interface WorkflowRef {
type: 'workflow';
id: string;
}
export type CallChainRef = NodeRef | WorkflowRef;
export type CallChain = CallChainRef[];

View file

@ -0,0 +1,55 @@
/*
* 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 type { WorkflowExecutionState } from './execution_state';
export type WorkflowExecutionErrorType =
/**
* Configuration of the node or the workflow is invalid,
* and caused a runtime exception during execution
*/
| 'invalidConfiguration'
/**
* The input provided to the node (e.g. interpolated values)
* is invalid
*/
| 'invalidParameter'
/**
* Workflow for a given ID was not found in the workflow provider.
*/
| 'workflowNotFound'
/**
* A node type used in the workflow definition was not found.
*/
| 'nodeTypeNotFound'
/**
* No tool was found for the specified tool ID in the tool provider.
*/
| 'toolNotFound'
/**
* Default, fallback error.
*/
| 'internalError';
export interface WorkflowExecutionErrorMeta {
state?: WorkflowExecutionState;
}
export class WorkflowExecutionError extends Error {
public readonly type: WorkflowExecutionErrorType;
public readonly meta: WorkflowExecutionErrorMeta;
constructor(message: string, type: WorkflowExecutionErrorType, meta: WorkflowExecutionErrorMeta) {
super(message);
this.type = type;
this.meta = meta;
}
}
export function isWorkflowExecutionError(error: Error): error is WorkflowExecutionError {
return error instanceof WorkflowExecutionError;
}

View file

@ -0,0 +1,35 @@
/*
* 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 type { CallChain } from './call_chain';
/**
* Meta containing all the info associated with the current execution
*/
export interface WorkflowExecutionState {
/**
* The id of this workflow execution run.
*/
runId: string;
/**
* ID of the workflow that this error was thrown from.
* In case of nested workflows, it will be the ID of the lowest level workflow.
*/
workflowId: string;
/**
* ID of the root workflow, the workflow that was requested to be executed
*/
rootWorkflowId: string;
/**
* If the error occurred during a step execution, this will be the step's ID.
*/
stepId?: string;
/**
* The whole call chain for this error.
*/
callChain: CallChain;
}

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export type { ModelProvider } from './model_provider';

View file

@ -0,0 +1,20 @@
/*
* 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 type { InferenceChatModel } from '@kbn/inference-langchain';
/**
* Provider, allowing to select various models depending on the needs.
*
* For now, only exposes a single default model type.
*/
export interface ModelProvider {
/**
* Returns the default model to be used for LLM tasks.
*/
getDefaultModel: () => InferenceChatModel;
}

View file

@ -0,0 +1,65 @@
/*
* 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 { NodeType } from '@kbn/wc-framework-types-common';
import type { NodeTypeToNodeConfigMap } from './node_type_configs';
/**
* A definition for a builtIn node, bound to the corresponding configuration schema.
*/
export interface BuiltInNodeDefinition<T extends NodeType> {
/**
* Unique ID for this node, within the workflow definition
*/
id: string;
/**
* The type of node.
*/
type: T;
/**
* Optional description of what the node does in the workflow
*/
description?: string;
/**
* Specific configuration for this node's type.
*/
configuration: NodeTypeToNodeConfigMap[T];
}
type AllBuiltInNodeDefinitions = {
[K in NodeType]: BuiltInNodeDefinition<K>;
}[NodeType];
/**
* Describes the configuration structure of a node within a {@link WorkflowDefinition}.
*
* This is the **persistence** shape: what will be stored in the workflow definition.
*/
export interface CustomNodeDefinition<NodeTypeConfigType = Record<string, unknown>> {
/**
* Unique ID for this node, within the workflow definition
*/
id: string;
/**
* The type of node.
*/
type: string;
/**
* Optional description of what the node does in the workflow
*/
description?: string;
/**
* Specific configuration for this node's type.
*/
configuration: NodeTypeConfigType;
}
/**
* Describes the configuration structure of a node within a {@link WorkflowDefinition}.
*
*/
export type NodeDefinition = AllBuiltInNodeDefinitions;

View file

@ -0,0 +1,21 @@
/*
* 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 type { NodeProgressionEvent } from '@kbn/wc-framework-types-common';
/**
* Subset of the properties of a {@link NodeProgressionEvent} that needs to be specified
* by the emitter.
*/
export type NodeProgressionReporterEvent = Pick<NodeProgressionEvent, 'label' | 'data'>;
/**
* Event reporter that can be used to report real time progress, or telemetry events from a node run.
*/
export interface NodeEventReporter {
reportProgress(event: NodeProgressionReporterEvent): void;
}

View file

@ -0,0 +1,82 @@
/*
* 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 type { Logger } from '@kbn/logging';
import type { IScopedClusterClient } from '@kbn/core/server';
import type { ModelProvider } from '../models/model_provider';
import type { ToolProvider } from '../tools';
import type { ScopedWorkflowProvider, ScopedRunner } from '../workflows';
import type { NodeRunner, DefaultNodeRunnerInput } from './runner';
import type { NodeDefinition } from './definition';
import type { ScopedNodeProvider } from './internal_services';
/**
* Base set of (pre-scoped) services that will always be exposed to the node factory.
*/
export interface NodeFactoryBaseServices {
/**
* Logger scoped to this node.
*
* Note: logging from within workflows is mostly for debugging purposes.
* progression and telemetry events should be used instead for other usages.
*/
logger: Logger;
/**
* Provider exposing LLM models to be used.
*/
modelProvider: ModelProvider;
/**
* Provider exposing tools that are available in that given context (workflow/node)
*/
toolProvider: ToolProvider;
/**
* Scoped cluster client.
*/
esClusterClient: IScopedClusterClient;
/**
* Registry exposing the workflows accessible in the node's context.
*/
workflowRegistry: ScopedWorkflowProvider;
/**
* Registry exposing node types, can be used to access node type definitions.
*/
nodeRegistry: ScopedNodeProvider;
/**
* Scoped node runner, can be used to run nodes as part of a node's execution flow,
* e.g. for conditional nodes.
*/
workflowRunner: ScopedRunner;
}
/**
* Factory services, composed of the base services and additional services that can be
* injected via {@link NodeDefinition.customServicesProvider}
*/
export type NodeFactoryServices<CustomServices = {}> = CustomServices & NodeFactoryBaseServices;
/**
* Context that is exposed to a {@NodeRunnerFactory} function.
*/
export interface NodeFactoryContext<CustomServices = {}> {
/**
* The (non-interpolated) configuration bound to this node.
*/
nodeConfiguration: NodeDefinition;
/**
* Scoped services that can be used by the factory.
*/
services: NodeFactoryServices<CustomServices>;
// TODO: later we probably need accessors for the workflow's config or something.
}
/**
* Represents a factory that can return a runner for a given node type.
*/
export type NodeRunnerFactory<InputShape = DefaultNodeRunnerInput, CustomServices = {}> = (
context: NodeFactoryContext<CustomServices>
) => NodeRunner<InputShape>;

View file

@ -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.
*/
export type { NodeDefinition, BuiltInNodeDefinition } from './definition';
export type { NodeEventReporter, NodeProgressionReporterEvent } from './event_reporter';
export type {
NodeRunnerFactory,
NodeFactoryContext,
NodeFactoryServices,
NodeFactoryBaseServices,
} from './factory';
export type { NodeRunner, RunNodeParams } from './runner';
export type { NodeTypeDefinition, CustomServicesProvider } from './type_definition';
export type { ScopedNodeProvider } from './internal_services';
export type {
NodeSequence,
SequenceBranch,
NodeTypeToNodeConfigMap,
ParallelSequencesNodeConfigType,
PromptNodeConfigType,
WorkflowExecutionNodeConfigType,
ToolExecutionNodeConfigType,
LoopNodeConfigType,
IntentRecognitionNodeConfigType,
IntentRecognitionBranch,
} from './node_type_configs';

View file

@ -0,0 +1,11 @@
/*
* 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 type { Provider } from '../utils';
import type { NodeTypeDefinition } from './type_definition';
export type ScopedNodeProvider = Provider<NodeTypeDefinition>;

View file

@ -0,0 +1,124 @@
/*
* 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 { NodeType } from '@kbn/wc-framework-types-common';
import type { NodeDefinition } from './definition';
export interface NodeTypeToNodeConfigMap {
[NodeType.workflowExecution]: WorkflowExecutionNodeConfigType;
[NodeType.toolExecution]: ToolExecutionNodeConfigType;
[NodeType.prompt]: PromptNodeConfigType;
[NodeType.parallelSequences]: ParallelSequencesNodeConfigType;
[NodeType.loop]: LoopNodeConfigType;
[NodeType.intentRecognition]: IntentRecognitionNodeConfigType;
}
export type NodeSequence = NodeDefinition[];
export interface SequenceBranch {
steps: NodeSequence;
}
/**
* Config for `parallelSequences` node type.
*/
export interface ParallelSequencesNodeConfigType {
branches: SequenceBranch[];
}
/**
* Config for `prompt` node type.
*/
export interface PromptNodeConfigType {
prompt: string;
output: string;
// TODO: structuredOutput
}
/**
* Config for `toolExecution` node type.
*/
export interface ToolExecutionNodeConfigType {
toolId: string;
toolArguments: Record<string, unknown>;
parseResponse: boolean;
output: string;
}
/**
* Config for `workflowExecution` node type.
*/
export interface WorkflowExecutionNodeConfigType {
workflowId: string;
inputs: Record<string, unknown>;
output: string;
}
/**
* Represents the configuration for a `loop` node.
*/
export interface LoopNodeConfigType {
/**
* Reference of the context variable to loop over.
* Supports interpolation. If interpolated value is a list,
* will use it directly. If interpolated value is a string,
* will retrieve the corresponding entry in the current state.
*/
inputList: string;
/**
* Name of the state property to inject the current loop element into.
* Supports interpolation, but final value must be a string.
*/
itemVar: string;
/**
* The sequence of steps to execute for each element in the list.
*/
steps: NodeSequence;
/**
* If defined, will accumulate results from each loop iteration,
* by reading the `output.source` context property in the loop's state,
* and creating a `output.destination` array in the parent's state.
*/
output?: {
source: string;
destination: string;
};
}
/**
* Config for `intentRecognition` node type.
*/
export interface IntentRecognitionNodeConfigType {
/**
* The prompt explaining the LLM the criteria for its choices
*/
prompt: string;
/**
*
*/
branches: IntentRecognitionBranch[];
}
export type IntentRecognitionBranch =
| IntentRecognitionConditionBranch
| IntentRecognitionDefaultBranch;
export interface IntentRecognitionConditionBranch {
id?: string;
/**
* The condition for this branch.
*
* Will be interpolated with the intent recognition node's state.
*/
condition: string;
steps: NodeSequence;
}
export interface IntentRecognitionDefaultBranch {
default: true;
steps: NodeSequence;
}

View file

@ -0,0 +1,52 @@
/*
* 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 type { WorkflowState } from '../state';
import type { WorkflowExecutionState } from '../execution_state';
import type { NodeEventReporter } from './event_reporter';
export type DefaultNodeRunnerInput = Record<string, unknown>;
/**
* Param type for {@link NodeRunner.run}
*/
export interface RunNodeParams<Input = DefaultNodeRunnerInput> {
/**
* raw input (configuration for this node, as described in the configuration
*/
input: Input;
/**
* Global state for this run.
*
* Usually, nodes don't need to access this directly, as the node's configuration
* should be sufficient for the framework to inject the right properties,
* but the state is still exposed to the nodes during execution
*/
state: WorkflowState;
/**
* Event reporter for this run.
*/
eventReporter: NodeEventReporter;
/**
* The current workflow execute state.
* Can be used when manually throwing errors from the node run handler.
*/
executionState: WorkflowExecutionState;
}
/**
* Represents an instance of a node runner.
*/
export interface NodeRunner<Input = DefaultNodeRunnerInput> {
/**
* Run the node with the provided inputs.
*/
run: (params: RunNodeParams<Input>) => Promise<void>;
}

View file

@ -0,0 +1,46 @@
/*
* 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 type { MaybePromise } from '@kbn/utility-types';
import type { NodeRunnerFactory } from './factory';
import type { DefaultNodeRunnerInput } from './runner';
/**
* Represents the definition for a given node type.
*
* Similar to SOs, vis types and so on, this defines all the properties
* and handlers that are going to be used to manage the lifecycle of a node type.
*/
export interface NodeTypeDefinition<NodeInput = DefaultNodeRunnerInput, CustomServices = {}> {
/**
* The unique identifier for this node type (it's type)
*/
id: string;
/**
* Human-readable name for this node type
*/
name: string;
/**
* Short human-readable description for this node type.
*/
description: string;
/**
* The {@link NodeRunnerFactory} for this node type.
*/
factory: NodeRunnerFactory<NodeInput, CustomServices>;
/**
* Allows defining a handler to return arbitrary services that will be exposed to
* the {@link NodeRunnerFactory} via it's context, {@link NodeFactoryContext}.
*
* This can be used as a convenient way to pass down additional services to
* the node factory and runner, for situations where the node type might need
* to access those services during its execution.
*/
customServicesProvider?: CustomServicesProvider<CustomServices>;
}
export type CustomServicesProvider<T> = () => MaybePromise<T>;

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export type { WorkflowState } from './state';

View file

@ -0,0 +1,16 @@
/*
* 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.
*/
/**
* Represents the workflow state, that gets propagated through nodes during execution.
*/
export interface WorkflowState {
has(key: string): boolean;
get<T = unknown>(key: string): T;
getKeys(): string[];
set<T>(key: string, value: T): void;
}

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
export type { Tool } from './tool';
export type { ToolProvider } from './provider';
export { createToolProvider } from './utils';

View file

@ -0,0 +1,31 @@
/*
* 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 type { MaybePromise } from '@kbn/utility-types';
import { Tool } from './tool';
/**
* Represents a tool provider exposed to a workflow to let it call tools.
*
* Tool providers can be either sync or async, to adapt to potential remote implementations.
*/
export interface ToolProvider {
/**
* Checks if the registry contains a tool for this ID.
*/
has(id: string): MaybePromise<boolean>;
/**
* Returns a tool based on its ID
*
* Will throw if no entries are found for the given id.
*/
get(id: string): MaybePromise<Tool>;
/**
* Returns all tools that are registered in that registry.
*/
getAll(): MaybePromise<Tool[]>;
}

View file

@ -0,0 +1,27 @@
/*
* 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 { z, ZodRawShape, ZodTypeAny } from '@kbn/zod';
import { MaybePromise } from '@kbn/utility-types';
import type { ToolDescriptor } from '@kbn/wc-framework-types-common';
/**
* Represents a tool that will be available to workflows.
*/
export interface Tool<RunInput extends ZodRawShape = ZodRawShape, RunOutput = unknown>
extends ToolDescriptor {
/**
* Tool's input schema, in zod format.
*/
schema: RunInput;
/**
* Handler to call to execute the tool.
*
* Note: if the return type is not a string, it will be stringified when passed down to the LLM
*/
handler: (args: z.objectOutputType<RunInput, ZodTypeAny>) => MaybePromise<RunOutput>;
}

View file

@ -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 type { ToolProvider } from './provider';
import type { Tool } from './tool';
/**
* Utility function to create a {@link ToolProvider} from a list of tools.
*/
export const createToolProvider = (tools: Tool[]): ToolProvider => {
const toolMap = new Map<string, Tool>();
tools.forEach((tool) => {
toolMap.set(tool.id, tool);
});
return {
has: (id) => toolMap.has(id),
get: (id) => {
if (!toolMap.has(id)) {
throw new Error();
}
return toolMap.get(id)!;
},
getAll: () => [...toolMap.values()],
};
};

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export type { Provider, AsyncProvider, Registry } from './registries';

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
/**
* Generic provider interface
*/
export interface Provider<T extends { id: string }> {
has(id: string): boolean;
get(id: string): T;
getAllKeys(): string[];
getAll(): T[];
}
/**
* Generic registry interface
*/
export interface Registry<T extends { id: string }> extends Provider<T> {
register(definition: T): void;
}
/**
* Generic async provider interface
*/
export interface AsyncProvider<T extends { id: string }> {
has(id: string): Promise<boolean>;
get(id: string): Promise<T>;
getAllKeys(): Promise<string[]>;
getAll(): Promise<T[]>;
}

View file

@ -0,0 +1,101 @@
/*
* 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 type { MaybePromise } from '@kbn/utility-types';
import type { NodeDefinition } from '../nodes';
import type { WorkflowRunEventHandler } from './runner';
/**
* Describes the definition of a workflow.
*
* This is only meant to be the "pure" definition. Persistence related things (e.g. id),
* or ownerId will be on higher-level structures.
*/
export interface BaseWorkflowDefinition {
/**
* A unique ID that can be used to reference this workflow.
*/
id: string;
/**
* The name of the workflow.
*
* Should be human (and LLM) readable, e.g. "Salesforce Case Summarization".
* Will be exposed to the LLM in some situations.
*/
name: string;
/**
* A short description of what this workflow does.
* Will be exposed to the LLM in some situations (e.g. assistant orchestrator or intent detection step)
*/
description?: string;
/**
* List of inputs for this workflow.
*/
inputs: WorkflowDefinitionInput[];
/**
* List of outputs for this workflow.
*/
outputs: WorkflowDefinitionOutput[];
}
export interface GraphWorkflowDefinition extends BaseWorkflowDefinition {
/**
* Unique type identifier for graph workflows
*/
type: 'graph';
/**
* Configuration for each of the workflow's nodes.
*/
steps: NodeDefinition[];
}
/**
* Function workflows allow arbitrary function execution as workflows.
*
* Can be used to "import" a workflow in the framework.
*/
export interface FunctionWorkflowDefinition extends BaseWorkflowDefinition {
/**
* Unique type identifier for function workflows
*/
type: 'function';
/**
* The function handler that should be called to execute the workflow.
*/
handler: (params: FunctionWorkflowHandlerParams) => MaybePromise<Record<string, unknown>>;
}
/**
* Arguments for a function workflow.
*/
export interface FunctionWorkflowHandlerParams {
/**
* The inputs for the workflow
*/
inputs: Record<string, unknown>;
/**
* Event handler that can be used to send custom workflow events
*/
eventHandler: WorkflowRunEventHandler;
}
export type WorkflowDefinition = GraphWorkflowDefinition | FunctionWorkflowDefinition;
export interface WorkflowDefinitionInput {
name: string;
description?: string;
type: WorkflowInputType;
required?: boolean;
}
export type WorkflowInputType = 'string' | 'number' | 'array';
export interface WorkflowDefinitionOutput {
name: string;
description?: string;
ref: string;
}

View file

@ -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.
*/
export type {
BaseWorkflowDefinition,
GraphWorkflowDefinition,
FunctionWorkflowDefinition,
WorkflowDefinition,
WorkflowDefinitionOutput,
WorkflowDefinitionInput,
WorkflowInputType,
FunctionWorkflowHandlerParams,
} from './definition';
export type {
WorkflowRunEventHandler,
WorkflowRunner,
RunWorkflowParams,
RunWorkflowOutput,
} from './runner';
export type {
ScopedWorkflowProvider,
ScopedRunner,
ScopedRunnerRunWorkflowParams,
ScopedRunnerRunWorkflowOutput,
ScopedRunnerRunNodeParams,
} from './internal_services';

View file

@ -0,0 +1,62 @@
/*
* 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 type { Provider } from '../utils';
import type { NodeDefinition } from '../nodes';
import type { WorkflowState } from '../state';
import type { WorkflowDefinition } from './definition';
import type { RunWorkflowParams, RunWorkflowOutput } from './runner';
/**
* Params for {@link ScopedRunner.runWorkflow}
*/
export interface ScopedRunnerRunWorkflowParams {
/**
* The definition of the workflow to run.
*/
workflowDefinition: WorkflowDefinition;
/**
* The input passed to the workflow.
*/
inputs: RunWorkflowParams['inputs'];
}
/**
* Params for {@link ScopedRunner.runNode}
*/
export interface ScopedRunnerRunNodeParams {
/**
* The definition of the node to run.
*/
nodeDefinition: NodeDefinition;
/**
* The state passed to the node.
*/
state: WorkflowState;
}
export type ScopedRunnerRunWorkflowOutput = RunWorkflowOutput;
/**
* An internal runner scoped to the current workflow execution context.
* Can be used to have nodes execute workflows or node definitions as part of their execution.
* E.g. for conditional nodes, parallel nodes or other...
*
* Exposed to node execution via the {@link NodeFactoryBaseServices}.
*/
export interface ScopedRunner {
/**
* Run a workflow definition, using a context bound to the current execution flow.
*/
runWorkflow(params: ScopedRunnerRunWorkflowParams): Promise<ScopedRunnerRunWorkflowOutput>;
/**
* Run a node definition, using a context bound to the current execution flow.
*/
runNode(params: ScopedRunnerRunNodeParams): Promise<void>;
}
export type ScopedWorkflowProvider = Provider<WorkflowDefinition>;

View file

@ -0,0 +1,63 @@
/*
* 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 type { KibanaRequest } from '@kbn/core/server';
import type { WorkflowRunEvent } from '@kbn/wc-framework-types-common';
import type { ToolProvider } from '../tools';
export type WorkflowRunEventHandler = (event: WorkflowRunEvent) => void;
export interface RunWorkflowParams<Input = Record<string, unknown>> {
/**
* The ID of the workflow to run.
*/
id: string;
/**
* The inputs to execute the workflow with.
* Inputs will be validated against the defined schema.
*/
inputs: Input;
/**
* The request that initiated that run.
*/
request: KibanaRequest;
/**
* If specified, the workflow runner will use
* tools from this provider in addition to the default ones when
* running the workflow.
*
* Can be used to expose custom tools.
*/
toolProvider?: ToolProvider;
/**
* Optional event handler to handle workflow execution events.
*
* Can be used to handle progression events in real time.
*/
onEvent?: WorkflowRunEventHandler;
/**
* If specified, will use that connector as the default connector
* instead of picking the default one automatically.
*/
defaultConnectorId?: string;
}
export interface RunWorkflowOutput<Output = Record<string, unknown>> {
/**
* The runId that was bound to this run. Can be used to find events in
* tracing / telemetry or so on.
*/
runId: string;
/**
* The output from the workflow.
*/
output: Output;
}
export interface WorkflowRunner<Input = Record<string, unknown>, Output = Record<string, unknown>> {
run(options: RunWorkflowParams<Input>): Promise<RunWorkflowOutput<Output>>;
}

View file

@ -0,0 +1,26 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/inference-langchain",
"@kbn/wc-framework-types-common",
"@kbn/logging",
"@kbn/utility-types",
"@kbn/zod",
"@kbn/core",
]
}

View file

@ -1,3 +1,3 @@
# @kbn/wci-browser
Empty package generated by @kbn/generate
Contains browser-side implementation for WorkChat integrations. Uses types from `@kbn/wci-common`.

View file

@ -27,6 +27,6 @@ export const capabilityGroups = {
},
api: {
read: [apiCapabilities.useWorkchat],
all: [apiCapabilities.manageWorkchat, apiCapabilities.manageWorkchat],
all: [apiCapabilities.useWorkchat, apiCapabilities.manageWorkchat],
},
};

View file

@ -10,7 +10,7 @@
"server": true,
"browser": true,
"configPath": ["xpack", "workchatApp"],
"requiredPlugins": ["inference", "actions", "features"],
"requiredPlugins": ["inference", "actions", "features", "workchatFramework"],
"optionalPlugins": [],
"requiredBundles": ["kibanaReact"]
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { type CoreSetup, type Plugin, CoreStart, PluginInitializerContext } from '@kbn/core/public';
import type { CoreSetup, Plugin, CoreStart, PluginInitializerContext } from '@kbn/core/public';
import type {
WorkChatAppPluginSetup,
WorkChatAppPluginStart,

View file

@ -10,6 +10,7 @@ import type { ConversationService } from './conversation/conversation_service';
import type { AgentService } from './agent/agent_service';
import type { IntegrationService } from './integration/integration_service';
import type { IntegrationRegistry } from './integration/integration_registry';
export interface WorkChatServices {
chatService: ChatService;
conversationService: ConversationService;

View file

@ -36,6 +36,7 @@ export const registerFeatures = ({ features }: { features: FeaturesPluginSetup }
read: [],
},
ui: [...capabilityGroups.ui.all],
// composedOf: [{ feature: WORKCHAT_FRAMEWORK_FEATURE_ID, privileges: ['all'] }],
},
read: {
app: ['kibana', WORKCHAT_APP_ID],
@ -46,6 +47,7 @@ export const registerFeatures = ({ features }: { features: FeaturesPluginSetup }
read: [integrationTypeName, agentTypeName],
},
ui: [...capabilityGroups.ui.read],
// composedOf: [{ feature: WORKCHAT_FRAMEWORK_FEATURE_ID, privileges: ['read'] }],
},
},
});

View file

@ -8,7 +8,11 @@
import type { InferenceServerStart } from '@kbn/inference-plugin/server';
import type { WorkchatIntegrationDefinition } from '@kbn/wci-server';
import type { PluginStartContract as ActionsPluginStart } from '@kbn/actions-plugin/server';
import { FeaturesPluginSetup } from '@kbn/features-plugin/server';
import type { FeaturesPluginSetup } from '@kbn/features-plugin/server';
import {
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
} from '@kbn/workchat-framework-plugin/server';
export interface WorkChatAppPluginSetup {
integrations: {
@ -19,10 +23,12 @@ export interface WorkChatAppPluginSetup {
export interface WorkChatAppPluginStart {}
export interface WorkChatAppPluginSetupDependencies {
workchatFramework: WorkChatFrameworkPluginSetup;
features: FeaturesPluginSetup;
}
export interface WorkChatAppPluginStartDependencies {
workchatFramework: WorkChatFrameworkPluginStart;
inference: InferenceServerStart;
actions: ActionsPluginStart;
}

View file

@ -36,6 +36,7 @@
"@kbn/wci-browser",
"@kbn/features-plugin",
"@kbn/wc-genai-utils",
"@kbn/workchat-framework-plugin",
],
"exclude": [
"target/**/*",

View file

@ -0,0 +1,3 @@
# WorkChatFramework
WorkChat framework plugin

View file

@ -0,0 +1,32 @@
/*
* 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.
*/
export const WORKCHAT_FRAMEWORK_FEATURE_ID = 'workchat_framework';
export const WORKCHAT_FRAMEWORK_FEATURE_NAME = 'workchat_framework';
export const WORKCHAT_FRAMEWORK_APP_ID = 'workchat_framework';
export const uiCapabilities = {
show: 'show',
showManagement: 'showManagement',
};
export const apiCapabilities = {
useWorkchatFramework: 'workchat_framework_use',
manageWorkchatFramework: 'workchat_framework_manage',
};
// defining feature groups here because it's less error prone when adding new capabilities
export const capabilityGroups = {
ui: {
read: [uiCapabilities.show],
all: [uiCapabilities.show, uiCapabilities.showManagement],
},
api: {
read: [apiCapabilities.useWorkchatFramework],
all: [apiCapabilities.useWorkchatFramework, apiCapabilities.manageWorkchatFramework],
},
};

View file

@ -0,0 +1,10 @@
/*
* 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 type { WorkflowDefinition } from '@kbn/wc-framework-types-browser';
export type GetWorkflowResponse = WorkflowDefinition;

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../../../../..',
roots: ['<rootDir>/x-pack/solutions/chat/plugins/workchat-framework'],
testMatch: ['**/*.test.ts', '**/*.test.tsx'],
};

View file

@ -0,0 +1,17 @@
{
"type": "plugin",
"id": "@kbn/workchat-framework-plugin",
"owner": "@elastic/search-kibana",
"group": "chat",
"visibility": "private",
"description": "WorkChat framework",
"plugin": {
"id": "workchatFramework",
"server": true,
"browser": true,
"configPath": ["xpack", "workchatFramework"],
"requiredPlugins": ["inference", "actions", "features"],
"optionalPlugins": [],
"requiredBundles": ["kibanaReact"]
}
}

View file

@ -0,0 +1,11 @@
{
"name": "@kbn/workchat-framework-plugin",
"version": "1.0.0",
"license": "Elastic License 2.0",
"private": true,
"scripts": {
"build": "yarn plugin-helpers build",
"plugin-helpers": "node ../../../../../scripts/plugin_helpers",
"kbn": "node ../../../../../scripts/kbn"
}
}

View file

@ -0,0 +1,17 @@
/*
* 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.
*/
/**
* Single source of truth for all url building logic in the app.
*/
export const appPaths = {
home: '/',
workflowBuilder: {
new: () => `/workflow-builder/new`,
edit: ({ workflowId }: { workflowId: string }) => `/workflow-builder/${workflowId}/edit`,
},
};

View file

@ -0,0 +1,11 @@
/*
* 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 { createContext } from 'react';
import type { InternalServices } from '../../services/types';
export const AppServicesContext = createContext<InternalServices | undefined>(undefined);

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export { registerApp } from './register';

View file

@ -0,0 +1,57 @@
/*
* 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 React from 'react';
import ReactDOM from 'react-dom';
import { I18nProvider } from '@kbn/i18n-react';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
import { CoreStart, ScopedHistory } from '@kbn/core/public';
import { Router } from '@kbn/shared-ux-router';
import type { InternalServices } from '../services';
import type { WorkChatFrameworkPluginStartDependencies } from '../types';
import { AppServicesContext } from './context/app_services_context';
import { AppRoutes } from './routes';
export const mountApp = async ({
core,
plugins,
services,
element,
history,
}: {
core: CoreStart;
plugins: WorkChatFrameworkPluginStartDependencies;
services: InternalServices;
element: HTMLElement;
history: ScopedHistory;
}) => {
const kibanaServices = { ...core, plugins };
const queryClient = new QueryClient();
ReactDOM.render(
<KibanaRenderContextProvider {...core}>
<KibanaContextProvider services={kibanaServices}>
<I18nProvider>
<QueryClientProvider client={queryClient}>
<AppServicesContext.Provider value={services}>
<RedirectAppLinks coreStart={core}>
<Router history={history}>
<AppRoutes />
</Router>
</RedirectAppLinks>
</AppServicesContext.Provider>
</QueryClientProvider>
</I18nProvider>
</KibanaContextProvider>
</KibanaRenderContextProvider>,
element
);
return () => ReactDOM.unmountComponentAtNode(element);
};

View file

@ -0,0 +1,12 @@
/*
* 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 React from 'react';
export const HomePage: React.FC<{}> = () => {
return <div>Workflow builder</div>;
};

View file

@ -0,0 +1,16 @@
/*
* 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.
*/
/**
* Query keys for react-query
*/
export const queryKeys = {
workflows: {
all: ['workflows'] as const,
byId: (workflowId: string) => ['workflows', workflowId],
},
};

View file

@ -0,0 +1,37 @@
/*
* 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 { type CoreSetup, AppStatus, DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { WORKCHAT_FRAMEWORK_APP_ID } from '../../common/features';
import type { WorkChatFrameworkPluginStartDependencies } from '../types';
import { InternalServices } from '../services';
export const registerApp = ({
core,
getServices,
}: {
core: CoreSetup<WorkChatFrameworkPluginStartDependencies>;
getServices: () => InternalServices;
}) => {
core.application.register({
id: WORKCHAT_FRAMEWORK_APP_ID,
appRoute: `/app/${WORKCHAT_FRAMEWORK_APP_ID}`,
category: DEFAULT_APP_CATEGORIES.enterpriseSearch,
euiIconType: 'logoElasticsearch',
status: AppStatus.accessible,
title: 'Workflow builder',
updater$: undefined,
deepLinks: [],
visibleIn: ['sideNav', 'globalSearch'],
async mount({ element, history }) {
const [coreStart, startPluginDeps] = await core.getStartServices();
const services = getServices();
const { mountApp } = await import('./mount');
return mountApp({ core: coreStart, services, element, history, plugins: startPluginDeps });
},
});
};

View file

@ -0,0 +1,20 @@
/*
* 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 React from 'react';
import { Route, Routes } from '@kbn/shared-ux-router';
import { HomePage } from './pages/home';
export const AppRoutes: React.FC<{}> = () => {
return (
<Routes>
<Route path="/">
<HomePage />
</Route>
</Routes>
);
};

View file

@ -0,0 +1,25 @@
/*
* 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 { PluginInitializer, PluginInitializerContext } from '@kbn/core/public';
import { WorkChatAppPlugin } from './plugin';
import {
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
WorkChatFrameworkPluginStartDependencies,
} from './types';
export const plugin: PluginInitializer<
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
{},
WorkChatFrameworkPluginStartDependencies
> = (context: PluginInitializerContext) => {
return new WorkChatAppPlugin(context);
};
export type { WorkChatFrameworkPluginSetup, WorkChatFrameworkPluginStart } from './types';

View file

@ -0,0 +1,58 @@
/*
* 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 type { CoreSetup, Plugin, CoreStart, PluginInitializerContext } from '@kbn/core/public';
import type {
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
WorkChatFrameworkPluginSetupDependencies,
WorkChatFrameworkPluginStartDependencies,
} from './types';
import { createServices, type InternalServices } from './services';
import { registerApp } from './application';
export class WorkChatAppPlugin
implements
Plugin<
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
WorkChatFrameworkPluginSetupDependencies,
WorkChatFrameworkPluginStartDependencies
>
{
private services?: InternalServices;
constructor(context: PluginInitializerContext) {}
public setup(
core: CoreSetup<WorkChatFrameworkPluginStartDependencies, WorkChatFrameworkPluginStart>,
pluginDeps: WorkChatFrameworkPluginSetupDependencies
): WorkChatFrameworkPluginSetup {
registerApp({
core,
getServices: () => {
if (!this.services) {
throw new Error('getServices called before plugin start');
}
return this.services;
},
});
return {};
}
public start(
core: CoreStart,
pluginDeps: WorkChatFrameworkPluginStartDependencies
): WorkChatFrameworkPluginStart {
this.services = createServices({ core });
return {};
}
public stop() {}
}

View file

@ -0,0 +1,18 @@
/*
* 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 type { CoreStart } from '@kbn/core/public';
import { WorkflowService } from './workflows';
import type { InternalServices } from './types';
export const createServices = ({ core: { http } }: { core: CoreStart }): InternalServices => {
const workflowService = new WorkflowService({ http });
return {
workflowService,
};
};

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export { createServices } from './create_services';
export type { InternalServices } from './types';

View file

@ -0,0 +1,12 @@
/*
* 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 type { WorkflowService } from './workflows';
export interface InternalServices {
workflowService: WorkflowService;
}

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export { WorkflowService } from './workflow_service';

View file

@ -0,0 +1,23 @@
/*
* 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 type { HttpSetup } from '@kbn/core/public';
import type { GetWorkflowResponse } from '../../../common/http_api/workflows';
export class WorkflowService {
private readonly http: HttpSetup;
constructor({ http }: { http: HttpSetup }) {
this.http = http;
}
async get(workflowId: string) {
return await this.http.get<GetWorkflowResponse>(
`/internal/workchat-framework/workflows/${workflowId}`
);
}
}

View file

@ -0,0 +1,18 @@
/*
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface WorkChatFrameworkPluginSetup {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface WorkChatFrameworkPluginStart {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface WorkChatFrameworkPluginSetupDependencies {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface WorkChatFrameworkPluginStartDependencies {}

View file

@ -0,0 +1,20 @@
/*
* 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 { schema, TypeOf } from '@kbn/config-schema';
import { PluginConfigDescriptor } from '@kbn/core/server';
const configSchema = schema.object({
enabled: schema.boolean({ defaultValue: false }),
});
export type WorkChatFrameworkConfig = TypeOf<typeof configSchema>;
export const config: PluginConfigDescriptor<WorkChatFrameworkConfig> = {
exposeToBrowser: {},
schema: configSchema,
};

View file

@ -0,0 +1,51 @@
/*
* 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 { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
import { KibanaFeatureScope } from '@kbn/features-plugin/common';
import type { FeaturesPluginSetup } from '@kbn/features-plugin/server';
import {
WORKCHAT_FRAMEWORK_FEATURE_ID,
WORKCHAT_FRAMEWORK_FEATURE_NAME,
WORKCHAT_FRAMEWORK_APP_ID,
capabilityGroups,
} from '../common/features';
export const registerFeatures = ({ features }: { features: FeaturesPluginSetup }) => {
features.registerKibanaFeature({
id: WORKCHAT_FRAMEWORK_FEATURE_ID,
name: WORKCHAT_FRAMEWORK_FEATURE_NAME,
minimumLicense: 'enterprise',
order: 1000,
category: DEFAULT_APP_CATEGORIES.chat,
scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security],
app: ['kibana', WORKCHAT_FRAMEWORK_APP_ID],
catalogue: [WORKCHAT_FRAMEWORK_FEATURE_ID],
privileges: {
all: {
app: ['kibana', WORKCHAT_FRAMEWORK_APP_ID],
api: [...capabilityGroups.api.all],
catalogue: [WORKCHAT_FRAMEWORK_FEATURE_ID],
savedObject: {
all: [],
read: [],
},
ui: [...capabilityGroups.ui.all],
},
read: {
app: ['kibana', WORKCHAT_FRAMEWORK_APP_ID],
api: [...capabilityGroups.api.read],
catalogue: [WORKCHAT_FRAMEWORK_FEATURE_ID],
savedObject: {
all: [],
read: [],
},
ui: [...capabilityGroups.ui.read],
},
},
});
};

View file

@ -0,0 +1,17 @@
/*
* 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 { PluginInitializerContext } from '@kbn/core/server';
import { WorkChatAppPlugin } from './plugin';
export { config } from './config';
export const plugin = (initializerContext: PluginInitializerContext) => {
return new WorkChatAppPlugin(initializerContext);
};
export type { WorkChatFrameworkPluginSetup, WorkChatFrameworkPluginStart } from './types';

View file

@ -0,0 +1,112 @@
/*
* 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 type {
CoreStart,
CoreSetup,
Plugin,
PluginInitializerContext,
LoggerFactory,
} from '@kbn/core/server';
import type {
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
WorkChatFrameworkPluginSetupDependencies,
WorkChatFrameworkPluginStartDependencies,
} from './types';
import type { WorkChatFrameworkConfig } from './config';
import { registerFeatures } from './features';
import { registerTypes } from './saved_objects';
import {
createStartServices,
createSetupServices,
type InternalSetupServices,
type InternalStartServices,
} from './services';
import { registerRoutes } from './routes';
import { registerBuiltInNodeTypes, registerBuiltInTools } from './services/runner/builtin';
export class WorkChatAppPlugin
implements
Plugin<
WorkChatFrameworkPluginSetup,
WorkChatFrameworkPluginStart,
WorkChatFrameworkPluginSetupDependencies,
WorkChatFrameworkPluginStartDependencies
>
{
private readonly logger: LoggerFactory;
private readonly config: WorkChatFrameworkConfig;
private setupServices?: InternalSetupServices;
private startServices?: InternalStartServices;
constructor(context: PluginInitializerContext) {
this.logger = context.logger;
this.config = context.config.get<WorkChatFrameworkConfig>();
}
public setup(
core: CoreSetup<WorkChatFrameworkPluginStartDependencies>,
setupDeps: WorkChatFrameworkPluginSetupDependencies
): WorkChatFrameworkPluginSetup {
this.setupServices = createSetupServices();
registerTypes({ savedObjects: core.savedObjects });
registerFeatures({ features: setupDeps.features });
const router = core.http.createRouter();
registerRoutes({
core,
router,
logger: this.logger.get(),
getServices: () => this.startServices!,
});
registerBuiltInNodeTypes({
registry: this.setupServices.nodeRegistry,
});
registerBuiltInTools({
registry: this.setupServices.toolRegistry,
});
return {
tools: {
register: (tool) => {
return this.setupServices!.toolRegistry.register(tool);
},
},
workflows: {
register: (definition) => {
return this.setupServices!.workflowRegistry.register(definition);
},
},
};
}
public start(
core: CoreStart,
pluginsDependencies: WorkChatFrameworkPluginStartDependencies
): WorkChatFrameworkPluginStart {
this.startServices = createStartServices({
core,
config: this.config,
logger: this.logger,
pluginsDependencies,
setupServices: this.setupServices!,
});
return {
workflows: {
run: (args) => {
return this.startServices!.workflowRunner.run(args);
},
},
};
}
}

View file

@ -0,0 +1,13 @@
/*
* 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 type { RouteDependencies } from './types';
import { registerWorkflowsRoutes } from './workflows';
export const registerRoutes = (deps: RouteDependencies) => {
registerWorkflowsRoutes(deps);
};

View file

@ -0,0 +1,17 @@
/*
* 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 type { IRouter, Logger, CoreSetup } from '@kbn/core/server';
import type { WorkChatFrameworkPluginStartDependencies } from '../types';
import type { InternalStartServices } from '../services';
export interface RouteDependencies {
router: IRouter;
logger: Logger;
core: CoreSetup<WorkChatFrameworkPluginStartDependencies>;
getServices: () => InternalStartServices;
}

View file

@ -0,0 +1,41 @@
/*
* 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 { schema } from '@kbn/config-schema';
import { apiCapabilities } from '../../common/features';
import type { GetWorkflowResponse } from '../../common/http_api/workflows';
import type { RouteDependencies } from './types';
import { getHandlerWrapper } from './wrap_handler';
export const registerWorkflowsRoutes = ({ router, logger, getServices }: RouteDependencies) => {
const wrapHandler = getHandlerWrapper({ logger });
router.get(
{
path: '/internal/workchat-framework/workflows/{workflowId}',
security: {
authz: {
requiredPrivileges: [apiCapabilities.useWorkchatFramework],
},
},
validate: {
params: schema.object({
workflowId: schema.string(),
}),
},
},
wrapHandler(async (ctx, request, response) => {
const { workflowId } = request.params;
const { workflowService } = getServices();
const scopedService = await workflowService.asScoped({ request });
const workflow = await scopedService.get(workflowId);
return response.ok<GetWorkflowResponse>({ body: workflow });
})
);
};

View file

@ -0,0 +1,24 @@
/*
* 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 type { Logger, RequestHandler } from '@kbn/core/server';
export const getHandlerWrapper =
({ logger }: { logger: Logger }) =>
<P, Q, B>(handler: RequestHandler<P, Q, B>): RequestHandler<P, Q, B> => {
return (ctx, req, res) => {
try {
return handler(ctx, req, res);
} catch (e) {
logger.error(e);
return res.customError({
body: { message: e.message },
statusCode: e.statusCode ?? 500,
});
}
};
};

View file

@ -0,0 +1,15 @@
/*
* 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 type { SavedObjectsServiceSetup } from '@kbn/core/server';
import { workflowSoType } from './workflow';
export const registerTypes = ({ savedObjects }: { savedObjects: SavedObjectsServiceSetup }) => {
savedObjects.registerType(workflowSoType);
};
export { workflowSoType, workflowSoTypeName, type WorkflowAttributes } from './workflow';

View file

@ -0,0 +1,54 @@
/*
* 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 type { SavedObjectsType } from '@kbn/core/server';
import type {
WorkflowDefinitionInput,
WorkflowDefinitionOutput,
NodeDefinition,
} from '@kbn/wc-framework-types-server';
export const workflowSoTypeName = 'onechat_workflow' as const;
export const workflowSoType: SavedObjectsType<WorkflowAttributes> = {
name: workflowSoTypeName,
hidden: true,
namespaceType: 'multiple-isolated',
mappings: {
dynamic: false,
properties: {
workflow_id: { type: 'keyword' },
user_id: { type: 'keyword' },
categories: { type: 'keyword' },
access_control: {
properties: {
public: { type: 'boolean' },
},
},
},
},
};
export interface WorkflowAttributes {
workflow_id: string;
name: string;
description: string;
categories: string[];
access_control: {
public: boolean;
};
user_id: string;
user_name: string;
spec_version: number;
inputs: WorkflowDefinitionInput[];
outputs: WorkflowDefinitionOutput[];
steps: NodeDefinition[];
}

Some files were not shown because too many files have changed in this diff Show more