-
Notifications
You must be signed in to change notification settings - Fork 1
Development manual
Accordion
is an automated task framework. You can combine multiple actions to achieve an efficient automation task, just like the IFTTT
simple and straightforward, quickly improving the efficiency of your system.
Create your own project and use Maven
or Gradle
to import the accordion framework.
For the latest version, check out GitHub Release or search the Maven repository.
<dependency>
<groupId>chat.octet</groupId>
<artifactId>accordion</artifactId>
<version>LAST_RELEASE_VERSION</version>
</dependency>
implementation group: 'chat.octet', name: 'accordion', version: 'LAST_RELEASE_VERSION'
Create a configuration template for an action, here we use a custom script
to output Hello world
.
ActionConfig myAction = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.SCRIPT.name())
.actionName("My action")
.actionDesc("My first action example")
.actionParams(ScriptParameter.builder().script("println('Hello world')").build())
.build();
Create the accordion score AccordionPlan
, which is a complete execution plan that includes the execution actions for each step. Then create an Accordion
to play the score.
AccordionPlan plan = AccordionPlan.of().start(myAction);
try (Accordion accordion = new Accordion(plan)) {
accordion.play(true);
System.out.println("Accordion plan:\n" + accordion.verbose());
}
The completed output is as follows. The verbose
method can be used to print the execution link and the execution status of each action.
Hello world
... ...
Accordion plan:
🅞───⨀ ✅ My action (ACT-DEM9W7UDPC)
The following is an introduction to the main functions of this project. You can selectively read according to your needs, which will help you quickly understand the technical features and usage methods of the accordion framework.
AccordionPlan
is an Execution Plan (DAG) consisting of an Execution Chain and an Action. The execution plan starts with a starting action and then connects other actions through the next
method to form an execution chain.
Note
- The execution chain connects each action, which in the DAG is the
Edge
, and the action is the specificNode
. - The execution of each action depends on the preceding action. If the preceding action fails, the following action will not be executed.
AccordionPlan API
/**
* Add a start action.
*
* @param actionConfig Action config
* @return AccordionPlan
*/
public AccordionPlan start(ActionConfig actionConfig);
/**
* Add a next action.
*
* @param previousAction Previous action
* @param nextAction Next action
* @return AccordionPlan
*/
public AccordionPlan next(ActionConfig previousAction, ActionConfig nextAction);
/**
* Add one or more next actions.
*
* @param previousAction Previous action
* @param nextActions One or more next actions
* @return AccordionPlan
*/
public AccordionPlan next(ActionConfig previousAction, ActionConfig... nextActions);
/**
* Reset the plan status.
*/
public void reset();
/**
* Export the plan to JSON.
*
* @return String
*/
public String exportToJsonConfig();
/**
* Import the plan from JSON.
*
* @param accordionConfigJson Accordion config JSON.
* @return AccordionPlan
*/
public AccordionPlan importConfig(String accordionConfigJson);
/**
* Import the plan from AccordionConfig.
*
* @param accordionConfig Accordion config.
* @return AccordionPlan
*/
public AccordionPlan importConfig(AccordionConfig accordionConfig);
Example
Here a complex execution plan is used for demo, as shown in the following figure, which includes a total of 10 actions, each connected through the next
method.
Example of execution plan:
// ... ...
AccordionPlan plan = AccordionPlan.of()
.next(a, b, c, r, w)
.next(b, d)
.next(c, d)
.next(d, e, g, f)
.next(e, h)
.next(f, h)
.next(g, h);
try (Accordion accordion = new Accordion(plan)) {
accordion.play(true);
System.out.println("Accordion plan:\n" + accordion.verbose());
}
Output of execution plan:
Accordion plan:
🅞───⨀ ✅ A (ACT-M43B62QK56)
├───⨀ ✅ B (ACT-HBT8E98ZJP)
├───⨀ ✅ C (ACT-7239Z51LKX)
├───⨀ ✅ R (ACT-5VR1Y3WMBP)
└───⨀ ✅ W (ACT-T39P7JFIVL)
└───⨀ ✅ D (ACT-XUM24TLIBI)
├───⨀ ✅ E (ACT-0KSSQYF52E)
├───⨀ ✅ G (ACT-XU3OXGBZ5Y)
└───⨀ ✅ F (ACT-56Q2VNG5B4)
└───⨀ ✅ H (ACT-LERLLYDHQN)
Import & Export accordion plan
After creating an execution plan, you can export it as a JSON
for persistence storage or import it into another execution plan.
accordion plan json example
{
"id": "ACR-MDESSISDQB",
"name": "Default accordion name",
"desc": "Default accordion desc",
"graph_config": {
"actions": [
{
"id": "ACT-BKFR133GZ0",
"action_type": "SCRIPT",
"action_name": "My action",
"action_desc": "My first action example",
"action_params": {
"script_id": "script-dyk9obhc63",
"script": "1+1",
"debug": false
},
"action_output": [
{
"name": "number",
"data_type": "LONG",
"desc": "Calc result"
}
]
},
{
"id": "ACT-OLH1M13ZIR",
"action_type": "CONDITION",
"action_name": "Condition action",
"action_desc": "Condition action example",
"action_params": {
"expression": "(number == 2)",
"debug": false
}
}
],
"edges": [
{
"previous_action": "ACT-BKFR133GZ0",
"next_action": "ACT-OLH1M13ZIR"
}
]
},
"updatetime": "2024-01-09 12:51:43"
}
Action is an execution unit that can do many things. Each action has three stages: input
, execution
, and output
.
-
Input
- The input parameters of an action can be the output result of the previous action or the event message. In development, we do not need to declare,
AbstractAction
will be automatically processed.
- The input parameters of an action can be the output result of the previous action or the event message. In development, we do not need to declare,
-
Execution
- This is the execution module for actions, where you can implement your business functions. You can refer to the code for preset actions for details.
-
Output
- The output parameters of the action need to be specified in the action configuration template as
actionOutput
.
- The output parameters of the action need to be specified in the action configuration template as
-
Status
- ⚪️
NORMAL
Default state 🅾️ ERROR
Execution error occurred- ✅
SUCCESS
Execution completed - 🟡
SKIP
Execution skipped, for example: when an error occurs in the execution of an action, the next action will be skipped.
- ⚪️
The following is a list of preset basic actions that you can expand as needed.
chat.octet.accordion.action.api.ApiAction
ApiAction
Supports calling third-party Restful APIs. supports requests and responses in JSON and XML data formats, and also supports the use of proxy services.
By default, the timeout for requesting an API is 5 seconds, and you can adjust it according to the actual situation.
Note
All actions use build mode to create object instances, including parameter templates for actions.
ActionConfig action = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.API.name())
.actionName("API")
.actionDesc("An api request action")
.actionParams(
ApiParameter.builder()
.url("https://127.0.0.1:8080/api/query")
.method(HttpMethod.GET)
.build()
)
.build();
- Action Parameters
Parameter | Required | Description |
---|---|---|
url | Y | Request url, http://127.0.0.1/api |
method | Y | Request methods, GET/POST/PUT... |
headers | N | Request header parameter list {"args": "value"} |
request | N | Request parameter list {"args": "value"} |
form | N | Request form parameter list {"args": "value"} |
body | N | Request body, supports JSON or XML |
timeout | N | Request timeout time (milliseconds), default: 5000 ms |
responseDataFormat | N | Response data format, supports JSON or XML |
retryOnConnectionFailure | N | Retry the request when an error occurs |
proxyType | N | Proxy type: DIRECT/HTTP/SOCKS |
proxyServerAddress | N | Proxy server address 127.0.0.1 |
proxyServerPort | N | Proxy server port 8080 |
- Action Output Parameters
According to the return value of the request, specify the required output parameters.
For example, if the response data of the request contains the status
field, then we can use status
as the output parameter for subsequent actions.
chat.octet.accordion.action.base.ConditionAction
ConditionAction
is similar to the if
in Java, used to control the execution process.
When the conditional judgment is not true, the execution will be interrupted.
Condition condition = new Condition("age", ConditionOperator.GT, 18)
.and("age", ConditionOperator.LT, 30);
String expression = ConditionBuilder.getInstance().build(condition);
ActionConfig action = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.CONDITION.name())
.actionName("Condition example")
.actionDesc("A condition action example")
.actionParams(
ConditionParameter.builder().expression(expression).build()
)
.build();
- Conditional expressions
There are two ways to use conditional expressions. The first is to write the expression directly, and the second is to create it using Condition
.
Example 1:
Condition condition = new Condition("age", ConditionOperator.GT, 18)
.and("age", ConditionOperator.LT, 30);
String expression = ConditionBuilder.getInstance().build(condition);
Example 2:
(age > 18) and (age < 30)
Conditional expressions can be evaluated using common combinations of logical operators.
such as:
# Evaluate expressions
1+1==2
# Conditional expressions
(a/b>1) or (a/b==0)
# Complex multi-conditional expressions
((a/b>1) or (a/b==0)) and (a==x)
In conditional expressions, we can use dynamic variables
. In the above example, parameters a
, b
, and x
will be replaced with actual values for calculation.
Warning
Missing dynamic variable values will be replaced with null
, which will result in the calculation conditions not being true.
- Action Parameters
Parameter | Required | Description |
---|---|---|
expression | Y | Conditional expressions |
- Action Output Parameters
After the conditional action is executed, it will return either true
or false
.
chat.octet.accordion.action.base.SwitchAction
SwitchAction
is a combination of multiple sets of conditions used to control multiple different execution chains, suitable for execution scenarios of multiple independent tasks.
SwitchParameter switchParameter = SwitchParameter.builder().build().addBranch(
SwitchParameter.Branch.builder().name("Go A").actionId(a.getId()).expression("2==1").build(),
SwitchParameter.Branch.builder().name("Go B").actionId(b.getId()).expression("1+1>1").build(),
SwitchParameter.Branch.builder().name("Go C").actionId(c.getId()).expression("1==1").build()
);
ActionConfig switchAction = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.SWITCH.name())
.actionName("Switch action")
.actionDesc("A switch action example")
.actionParams(switchParameter)
.build();
Note
In the above example, only the B and C branches will be executed.
- Action Parameters
Parameter | Required | Description |
---|---|---|
branches | Y | Branch List [...] |
name | Y | Branch name |
actionId | Y | Action ID for branch execution |
expression | Y | Conditional expressions |
negation | Y | Conditional reversal: true / false |
- Action Output Parameters
After the SwitchAction is executed, a list of objects containing the branch name and execution result will be returned.
chat.octet.accordion.action.eamil.EmailAction
EmailAction
Supports sending emails to multiple email addresses.
By default, the content format of the email is in HTML format, and email attachments are not currently supported.
Warning
Please strictly check the content of your email to ensure that it does not contain script injections such as js
, which are often intercepted by the email system.
ActionConfig emailAction = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.EMAIL.name())
.actionName("Email action")
.actionDesc("A email notify action")
.actionParams(
EmailParameter.builder()
.subject("A testing email")
.from("accordion@octet.pro")
.to("test@octet.pro,other@octet.pro")
.cc("manager@octet.pro")
.content("<p>Testing from <h1>Accordion</h1></p>")
.server("smtp.examples.com")
.username("ACCOUNT")
.password("PASS")
.build()
)
.build();
- Action Parameters
Parameter | Required | Description |
---|---|---|
server | Y | Email server address 127.0.0.1
|
smtpPort | Y | Email server port,default: 25
|
ssl | N | Use SSL, default: false |
tls | N | Use TLS, default: false |
username | N | Sender account |
password | N | Sender password |
subject | Y | Email subject |
from | Y | Email sender |
to | Y | Email recipient, Using "," dividing multiple parameters |
cc | N | Email carbon copy, Using "," dividing multiple parameters |
content | Y | Email content |
timeout | N | Connection timeout, default: 5000 ms |
debug | N | Debug mode, default: false |
- Action Output Parameters
Email action has no output parameters.
chat.octet.accordion.action.script.ScriptAction
ScriptAction
support Java
language syntax, used to implement complex task scenarios.
Note
-
Java
andlambda
expression -
Debug mode
Easy to track issues -
Dynamic variables
For example:num = x + y
-
Functions
For example:Mathlib
,String processing
, etc
Implement using the com.googlecode.aviator
framework. For more syntax rules, please refer to the aviator user manual.
Important
By default, custom scripts disable some language features to ensure system security.**
ActionConfig scriptAction = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.SCRIPT.name())
.actionName("Script action")
.actionDesc("A script action example")
.actionParams(
ScriptParameter.builder().script("println('Hello world')").build()
)
.build();
- Action Parameters
Parameter | Required | Description |
---|---|---|
scriptId | N | Script id, Automatically generated by default |
script | Y | Script code snippets |
debug | N | Debug mode, default: false |
- Action Output Parameters
Without specifying output parameters, custom actions will use the default output parameters ACTION_SCRIPT_RESULT
, of type String
, is used to save the result of script execution.
Parameter | DataType | Description |
---|---|---|
ACTION_SCRIPT_RESULT | String | Default output parameter |
chat.octet.accordion.action.shell.ShellAction
Support executing custom commands or scripts, such as bash
, cmd
, powershell
.
ActionConfig action = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.SHELL.name())
.actionName("Shell action")
.actionParams(
ShellParameter.builder().shell("echo 'hello world'").build()
)
.build();
- Action Parameters
Parameter | Required | Description |
---|---|---|
type | N | Shell language type, default: bash |
shell | Y | Shell code snippets |
timeout | N | Execution timeout, default: 60000 ms |
- Action Output Parameters
You can specify an output parameter or leave it blank.
chat.octet.accordion.action.llama.LlamaAction
Implemented using llama-Java
, supports automatic inference in chat mode and completion mode.
ActionConfig action = ActionConfig.builder()
.id(CommonUtils.randomString("ACT").toUpperCase())
.actionType(ActionType.LLAMA.name())
.actionName("llama action")
.actionParams(
LlamaParameter.builder().modelParameter(
ModelParameter.builder().modelPath("/llama-java/models/model-7b-q6_k.gguf").build()
).generateParameter(
GenerateParameter.builder().verbosePrompt(true).build()
).system("You're Kitty Jamie, and your answers and actions are the same as those of a kitten.")
.build()
)
.build();
- Action Parameters
Parameter | Required | Description |
---|---|---|
modelParameter | Y | Llama model parameters |
generateParameter | N | Llama generate parameters. Use default values when not specified |
chatMode | N | Use chat mode (default: true), Otherwise it will be in completion mode |
system | N | System prompt text |
memory | N | Use chat memory (default: false), Only available in chat mode |
Note
For the complete parameters of modelParameter
and generateParameter
, please refer to llama-java
Documents.
- Action Output Parameters
Parameter | DataType | Description |
---|---|---|
LLAMA_OUTPUT | String | model generation text |
In addition to preset actions, you can create your own custom actions, which can be implemented as follows:
- Implement custom actions
public class MyAction extends AbstractAction {
public MyAction(ActionConfig actionConfig) {
super(actionConfig);
}
@Override
public ExecuteResult execute() throws ActionException {
ExecuteResult executeResult = new ExecuteResult();
try {
//YOUR CODE...
} catch (Exception e) {
setExecuteThrowable(new ActionException(e.getMessage(), e));
}
return executeResult;
}
}
Tip
- All actions inherit
AbstractAction
and implement theexecute
method, initializing the required parameters in the constructor. -
execute
method defaults to usingtry-catch
to handle exceptions, and you can also choose to throw an exception. - If you need to pass output parameters, please write them to
ExecuteResult
.
- Register custom actions
Custom actions require registration to be used, and ActionType
is globally unique. You can define a special name to identify it.
ActionRegister.getInstance().register("MyAction", MyAction.class.getName());
- unregister custom actions
For unnecessary actions, you can remove them through the unregister
method.
ActionRegister.getInstance().unregister("MyAction");
Event message
is a data source, and in some scenarios, we need to provide feedback on event messages sent from upstream and perform a series of complex actions.
Tip
- In streaming computing scenarios, we can perform real-time computation and processing on consumed event messages.
- In monitoring scenarios, we can alert for outliers and perform specific operations.
Example
chat.octet.accordion.examples.MessageExample
Throughout the entire task execution process, we can use Action output parameters
or Action session
to pass parameter values.
- Action output parameters
Only used between actions, the output parameter of the previous action will be passed as the input parameter of the next action by default.
For example, requesting the return result field of a certain interface can be used to determine the condition of the next action.
- Action session
Globally available, Action session
is initialized at the beginning of task execution, which stores the status and messages of the execution chain. You can store the parameters that need to be passed globally in the session.
Important
Parameter naming convention
Use clear and easy to understand parameter names as much as possible to avoid duplicate parameter names that may cause parameters to be overwritten.
Example
chat.octet.accordion.examples.SimpleExample
Supports data types chat.octet.accordion.core.enums.DataType
During the parameter transfer process, parameter type conversion will be automatically performed, and String
will be used uniformly for parameters without specified data types.
Reference Framework
In this project, I used okhtp3
to implement lightweight HTTP requests and aviator
to implement advanced scripting language functionality.
aviator
okhttp3