chore: import upstream snapshot with attribution
Validate YAML Workflows / Validate YAML Configuration Files (push) Has been cancelled
Validate YAML Workflows / Validate YAML Configuration Files (push) Has been cancelled
This commit is contained in:
Executable
+186
@@ -0,0 +1,186 @@
|
||||
# Agent Node
|
||||
|
||||
The Agent node is the most fundamental node type in the DevAll platform, used to invoke Large Language Models (LLMs) for text generation, conversation, reasoning, and other tasks. It supports multiple model providers (OpenAI, Gemini, etc.) and can be configured with advanced features like tool calling, chain-of-thought, and memory.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `provider` | string | Yes | `openai` | Model provider name, e.g., `openai`, `gemini` |
|
||||
| `name` | string | Yes | - | Model name, e.g., `gpt-4o`, `gemini-2.0-flash-001` |
|
||||
| `role` | text | No | - | System prompt |
|
||||
| `base_url` | string | No | Provider default | API endpoint URL, supports `${VAR}` placeholders |
|
||||
| `api_key` | string | No | - | API key, recommend using environment variable `${API_KEY}` |
|
||||
| `params` | dict | No | `{}` | Model call parameters (temperature, top_p, etc.) |
|
||||
| `tooling` | object | No | - | Tool calling configuration, see [Tooling Module](../modules/tooling/README.md) |
|
||||
| `thinking` | object | No | - | Chain-of-thought configuration, e.g., chain-of-thought, reflection |
|
||||
| `memories` | list | No | `[]` | Memory binding configuration, see [Memory Module](../modules/memory.md) |
|
||||
| `skills` | object | No | - | Agent Skills discovery and built-in skill activation/file-read tools |
|
||||
| `retry` | object | No | - | Automatic retry strategy configuration |
|
||||
|
||||
### Retry Strategy Configuration (retry)
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `enabled` | bool | `true` | Whether to enable automatic retry |
|
||||
| `max_attempts` | int | `5` | Maximum number of attempts (including first attempt) |
|
||||
| `min_wait_seconds` | float | `1.0` | Minimum backoff wait time |
|
||||
| `max_wait_seconds` | float | `6.0` | Maximum backoff wait time |
|
||||
| `retry_on_status_codes` | list[int] | `[408,409,425,429,500,502,503,504]` | HTTP status codes that trigger retry |
|
||||
|
||||
### Agent Skills Configuration (skills)
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `enabled` | bool | `false` | Enable Agent Skills discovery for this node |
|
||||
| `allow` | list[object] | `[]` | Optional allowlist of skills from the project-level `.agents/skills/` directory; each entry uses `name` |
|
||||
|
||||
### Agent Skills Notes
|
||||
|
||||
- Skills are discovered from the fixed project-level `.agents/skills/` directory.
|
||||
- The runtime exposes two built-in skill tools: `activate_skill` and `read_skill_file`.
|
||||
- `read_skill_file` only works after the relevant skill has been activated.
|
||||
- Skill `SKILL.md` frontmatter may include optional `allowed-tools` using the Agent Skills spec format, for example `allowed-tools: execute_code`.
|
||||
- If a selected skill requires tools that are not bound on the node, that skill is skipped at runtime.
|
||||
- If no compatible skills remain, the agent is explicitly instructed not to claim skill usage.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Text generation**: Writing, translation, summarization, Q&A, etc.
|
||||
- **Intelligent conversation**: Multi-turn dialogue, customer service bots
|
||||
- **Tool calling**: Enable the model to call external APIs or execute functions
|
||||
- **Complex reasoning**: Use with thinking configuration for deep thought
|
||||
- **Knowledge retrieval**: Use with memories to implement RAG patterns
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Writer
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
base_url: ${BASE_URL}
|
||||
api_key: ${API_KEY}
|
||||
name: gpt-4o
|
||||
role: |
|
||||
You are a professional technical documentation writer. Please answer questions in clear and concise language.
|
||||
params:
|
||||
temperature: 0.7
|
||||
max_tokens: 2000
|
||||
```
|
||||
|
||||
### Configuring Tool Calling
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Assistant
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
tooling:
|
||||
type: function # Tool type: function, mcp_remote, mcp_local
|
||||
config:
|
||||
tools: # List of function tools from functions/function_calling/ directory
|
||||
- name: describe_available_files
|
||||
- name: load_file
|
||||
timeout: 20 # Optional: execution timeout (seconds)
|
||||
```
|
||||
|
||||
### Configuring MCP Tools (Remote HTTP)
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: MCP Agent
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
tooling:
|
||||
type: mcp_remote
|
||||
config:
|
||||
server: http://localhost:8080/mcp # MCP server endpoint
|
||||
headers: # Optional: custom request headers
|
||||
Authorization: Bearer ${MCP_TOKEN}
|
||||
timeout: 30 # Optional: request timeout (seconds)
|
||||
```
|
||||
|
||||
### Configuring MCP Tools (Local stdio)
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Local MCP Agent
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
tooling:
|
||||
type: mcp_local
|
||||
config:
|
||||
command: uvx # Launch command
|
||||
args: ["mcp-server-sqlite", "--db-path", "data.db"]
|
||||
cwd: ${WORKSPACE} # Optional, usually not needed
|
||||
env: # Optional, usually not needed
|
||||
DEBUG: "true"
|
||||
startup_timeout: 10 # Optional: startup timeout (seconds)
|
||||
```
|
||||
|
||||
### Gemini Multimodal Configuration
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Vision Agent
|
||||
type: agent
|
||||
config:
|
||||
provider: gemini
|
||||
base_url: https://generativelanguage.googleapis.com
|
||||
api_key: ${GEMINI_API_KEY}
|
||||
name: gemini-2.5-flash-image
|
||||
role: You need to generate corresponding image content based on user input.
|
||||
```
|
||||
|
||||
### Configuring Retry Strategy
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Robust Agent
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
retry: # Retry is enabled by default, you can customize it
|
||||
enabled: true
|
||||
max_attempts: 3
|
||||
min_wait_seconds: 2.0
|
||||
max_wait_seconds: 10.0
|
||||
```
|
||||
|
||||
### Configuring Agent Skills
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Skilled Agent
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
skills:
|
||||
enabled: true
|
||||
allow:
|
||||
- name: python-scratchpad
|
||||
- name: rest-api-caller
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Tooling Module Configuration](../modules/tooling/README.md)
|
||||
- [Memory Module Configuration](../modules/memory.md)
|
||||
- [Workflow Authoring Guide](../workflow_authoring.md)
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
# Human Node
|
||||
|
||||
The Human node is used to introduce human interaction during workflow execution, allowing users to view the current state and provide input through the Web UI. This node blocks workflow execution until the user submits a response.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `description` | text | No | - | Task description displayed to the user, explaining the operation that requires human completion |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Blocking Wait Mechanism
|
||||
|
||||
When the workflow reaches a Human node:
|
||||
1. The workflow pauses, waiting for human input
|
||||
2. The Web UI displays the current context and task description
|
||||
3. The user enters a response in the interface
|
||||
4. The workflow continues execution, passing the user input to downstream nodes
|
||||
|
||||
### Web UI Interaction
|
||||
|
||||
- Human nodes are presented as a conversation in the Launch interface
|
||||
- Users can view previous execution history
|
||||
- Supports attachment uploads (e.g., files, images)
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Review and confirmation**: Have humans review LLM output before continuing
|
||||
- **Modification suggestions**: Collect user suggestions for modifying generated content
|
||||
- **Critical decisions**: Points where human judgment is needed to continue
|
||||
- **Data supplementation**: When additional information from the user is needed
|
||||
- **Quality control**: Introduce human quality checks at critical nodes
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Human Reviewer
|
||||
type: human
|
||||
config:
|
||||
description: Please review the above content. If satisfied, enter ACCEPT; otherwise, enter your modification suggestions.
|
||||
```
|
||||
|
||||
### Human-Machine Collaboration Loop
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Article Writer
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
role: You are a professional writer who writes articles based on user requirements.
|
||||
|
||||
- id: Human Reviewer
|
||||
type: human
|
||||
config:
|
||||
description: |
|
||||
Please review the article:
|
||||
- If satisfied with the result, enter ACCEPT to end the process
|
||||
- Otherwise, enter modification suggestions to continue iterating
|
||||
|
||||
edges:
|
||||
- from: Article Writer
|
||||
to: Human Reviewer
|
||||
- from: Human Reviewer
|
||||
to: Article Writer
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [ACCEPT]
|
||||
case_sensitive: false
|
||||
```
|
||||
|
||||
### Multi-Stage Review
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Draft Generator
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
- id: Content Review
|
||||
type: human
|
||||
config:
|
||||
description: Please review content accuracy. Enter APPROVED or modification suggestions.
|
||||
|
||||
- id: Final Reviewer
|
||||
type: human
|
||||
config:
|
||||
description: Final confirmation. Enter PUBLISH to publish or REJECT to reject.
|
||||
|
||||
edges:
|
||||
- from: Draft Generator
|
||||
to: Content Review
|
||||
- from: Content Review
|
||||
to: Final Reviewer
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [APPROVED]
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Clearly explain expected operations and keywords in the `description`
|
||||
- Use conditional edges with keywords to implement flow control
|
||||
- Consider adding timeout mechanisms to avoid infinite workflow waiting
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
# Literal Node
|
||||
|
||||
The Literal node is used to output fixed text content. When the node is triggered, it ignores all inputs and directly outputs a predefined message.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `content` | text | Yes | - | Fixed text content to output, cannot be empty |
|
||||
| `role` | string | No | `user` | Message role: `user` or `assistant` |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Fixed Output
|
||||
|
||||
Characteristics of the Literal node:
|
||||
- **Ignores input**: Regardless of what upstream content is passed in, it does not affect the output
|
||||
- **Fixed content**: Outputs the same `content` every time it executes
|
||||
- **Role marking**: Output message carries the specified role identifier
|
||||
|
||||
### Message Role
|
||||
|
||||
- `user`: Indicates this is a message sent by the user
|
||||
- `assistant`: Indicates this is a message sent by the assistant (AI)
|
||||
|
||||
The role setting affects how downstream nodes process the message.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Fixed prompt injection**: Inject fixed instructions or context into the workflow
|
||||
- **Testing and debugging**: Use fixed input to test downstream nodes
|
||||
- **Default responses**: Return fixed messages under specific conditions
|
||||
- **Process initialization**: Serve as the starting point of a workflow to provide initial content
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Welcome Message
|
||||
type: literal
|
||||
config:
|
||||
content: |
|
||||
Welcome to the intelligent assistant! Please describe your needs.
|
||||
role: assistant
|
||||
```
|
||||
|
||||
### Injecting Fixed Context
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Context Injector
|
||||
type: literal
|
||||
config:
|
||||
content: |
|
||||
Please note the following rules:
|
||||
1. Answers must be concise and clear
|
||||
2. Reply in English
|
||||
3. If uncertain, please state so
|
||||
role: user
|
||||
|
||||
- id: Assistant
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
edges:
|
||||
- from: Context Injector
|
||||
to: Assistant
|
||||
```
|
||||
|
||||
### Fixed Responses in Conditional Branches
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Classifier
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: Determine user intent, reply with KNOWN or UNKNOWN
|
||||
|
||||
- id: Known Response
|
||||
type: literal
|
||||
config:
|
||||
content: I can help you complete this task.
|
||||
role: assistant
|
||||
|
||||
- id: Unknown Response
|
||||
type: literal
|
||||
config:
|
||||
content: Sorry, I cannot understand your request. Please describe it in a different way.
|
||||
role: assistant
|
||||
|
||||
edges:
|
||||
- from: Classifier
|
||||
to: Known Response
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [KNOWN]
|
||||
- from: Classifier
|
||||
to: Unknown Response
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [UNKNOWN]
|
||||
```
|
||||
|
||||
### Testing Purposes
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Test Input
|
||||
type: literal
|
||||
config:
|
||||
content: |
|
||||
This is a test text for verifying downstream processing logic.
|
||||
Contains multiple lines.
|
||||
role: user
|
||||
|
||||
- id: Processor
|
||||
type: python
|
||||
config:
|
||||
timeout_seconds: 30
|
||||
|
||||
edges:
|
||||
- from: Test Input
|
||||
to: Processor
|
||||
|
||||
start: [Test Input]
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The `content` field cannot be an empty string
|
||||
- Use YAML multi-line string syntax `|` for writing long text
|
||||
- Choose the correct `role` to ensure downstream nodes process the message correctly
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
# Loop Counter Node
|
||||
|
||||
The Loop Counter node is a loop control node used to limit the number of iterations of a loop in a workflow. Through a counting mechanism, it suppresses output before reaching the preset limit, and only releases the message to trigger outgoing edges when the limit is reached, thereby terminating the loop.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `max_iterations` | int | Yes | `10` | Maximum number of loop iterations, must be ≥ 1 |
|
||||
| `reset_on_emit` | bool | No | `true` | Whether to reset the counter after reaching the limit |
|
||||
| `message` | text | No | - | Message content to send to downstream when limit is reached |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### How It Works
|
||||
|
||||
The Loop Counter node maintains an internal counter with the following behavior:
|
||||
|
||||
1. **Each time it is triggered**: Counter +1
|
||||
2. **Counter < `max_iterations`**: **No output is produced**, outgoing edges are not triggered
|
||||
3. **Counter = `max_iterations`**: Output message is produced, triggering outgoing edges
|
||||
|
||||
This "suppress-release" mechanism allows the Loop Counter to precisely control when a loop terminates.
|
||||
|
||||
### Topological Structure Requirements
|
||||
|
||||
The Loop Counter node has special placement requirements in the graph structure:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
▼ │
|
||||
Agent ──► Human ─────► Loop Counter ──┬──┘
|
||||
▲ │ │
|
||||
└─────────┘ ▼
|
||||
End Node (outside loop)
|
||||
```
|
||||
|
||||
> **Important**: Since Loop Counter **produces no output until the limit is reached**:
|
||||
> - **Human must connect to both Agent and Loop Counter**: This way the "continue loop" edge is handled by Human → Agent, while Loop Counter only handles counting
|
||||
> - **Loop Counter must connect to Agent (inside loop)**: So it's recognized as an in-loop node, avoiding premature loop termination
|
||||
> - **Loop Counter must connect to End Node (outside loop)**: When the limit is reached, trigger the out-of-loop node to terminate the entire loop execution
|
||||
|
||||
### Counter State
|
||||
|
||||
- Counter state persists throughout the entire workflow execution
|
||||
- When `reset_on_emit: true`, the counter resets to 0 after reaching the limit
|
||||
- When `reset_on_emit: false`, the counter continues accumulating after reaching the limit, outputting on every subsequent trigger
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Preventing infinite loops**: Set a safety limit for human-machine interaction loops
|
||||
- **Iteration control**: Limit the maximum number of self-improvement iterations for an Agent
|
||||
- **Timeout protection**: Serve as a "circuit breaker" for process execution
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Iteration Guard
|
||||
type: loop_counter
|
||||
config:
|
||||
max_iterations: 5
|
||||
reset_on_emit: true
|
||||
message: Maximum iteration count reached, process terminated.
|
||||
```
|
||||
|
||||
### Human-Machine Interaction Loop Protection
|
||||
|
||||
This is the most typical use case for Loop Counter:
|
||||
|
||||
```yaml
|
||||
graph:
|
||||
id: review_loop
|
||||
description: Review loop with iteration limit
|
||||
|
||||
nodes:
|
||||
- id: Writer
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: Improve articles based on user feedback
|
||||
|
||||
- id: Reviewer
|
||||
type: human
|
||||
config:
|
||||
description: |
|
||||
Review the article, enter ACCEPT to accept or provide modification suggestions.
|
||||
|
||||
- id: Loop Guard
|
||||
type: loop_counter
|
||||
config:
|
||||
max_iterations: 3
|
||||
message: Maximum modification count (3 times) reached, process automatically ended.
|
||||
|
||||
- id: Final Output
|
||||
type: passthrough
|
||||
config: {}
|
||||
|
||||
edges:
|
||||
# Main loop: Writer -> Reviewer
|
||||
- from: Writer
|
||||
to: Reviewer
|
||||
|
||||
# Condition 1: User enters ACCEPT -> End
|
||||
- from: Reviewer
|
||||
to: Final Output
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [ACCEPT]
|
||||
|
||||
# Condition 2: User enters modification suggestions -> Trigger both Writer to continue loop AND Loop Guard to count
|
||||
- from: Reviewer
|
||||
to: Writer
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [ACCEPT]
|
||||
|
||||
- from: Reviewer
|
||||
to: Loop Guard
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [ACCEPT]
|
||||
|
||||
# Loop Guard connects to Writer (keeps it inside the loop)
|
||||
- from: Loop Guard
|
||||
to: Writer
|
||||
|
||||
# When Loop Guard reaches limit: Trigger Final Output to end the process
|
||||
- from: Loop Guard
|
||||
to: Final Output
|
||||
|
||||
start: [Writer]
|
||||
end: [Final Output]
|
||||
```
|
||||
|
||||
**Execution Flow Explanation**:
|
||||
1. User first enters modification suggestions → Triggers both Writer (continue loop) and Loop Guard (count 1, no output)
|
||||
2. User enters modification suggestions again → Triggers both Writer (continue loop) and Loop Guard (count 2, no output)
|
||||
3. User enters modification suggestions for the third time → Writer continues execution, Loop Guard count 3 reaches limit, outputs message triggering Final Output, terminating the loop
|
||||
4. Or at any time user enters ACCEPT → Goes directly to Final Output to end
|
||||
|
||||
## Notes
|
||||
|
||||
- `max_iterations` must be a positive integer (≥ 1)
|
||||
- Loop Counter **produces no output until the limit is reached**, outgoing edges will not trigger
|
||||
- Ensure Loop Counter connects to both in-loop and out-of-loop nodes
|
||||
- The `message` field is optional, default message is `"Loop limit reached (N)"`
|
||||
@@ -0,0 +1,159 @@
|
||||
# Loop Timer Node
|
||||
|
||||
The Loop Timer node is a loop control node used to limit the duration of a loop in a workflow. Through a time-tracking mechanism, it suppresses output before reaching the preset time limit, and only releases the message to trigger outgoing edges when the time limit is reached, thereby terminating the loop.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `max_duration` | float | Yes | `60.0` | Maximum loop duration, must be > 0 |
|
||||
| `duration_unit` | string | Yes | `"seconds"` | Time unit: "seconds", "minutes", or "hours" |
|
||||
| `reset_on_emit` | bool | No | `true` | Whether to reset the timer after reaching the limit |
|
||||
| `message` | text | No | - | Message content to send to downstream when time limit is reached |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### How It Works
|
||||
|
||||
The Loop Timer node maintains an internal timer with the following behavior:
|
||||
|
||||
1. **On first trigger**: Timer starts tracking elapsed time
|
||||
2. **Elapsed time < `max_duration`**: **No output is produced**, outgoing edges are not triggered
|
||||
3. **Elapsed time >= `max_duration`**: Output message is produced, triggering outgoing edges
|
||||
|
||||
This "suppress-release" mechanism allows the Loop Timer to precisely control when a loop terminates based on time rather than iteration count.
|
||||
|
||||
### Topological Structure Requirements
|
||||
|
||||
The Loop Timer node has special placement requirements in the graph structure:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐
|
||||
▼ │
|
||||
Agent ──► Human ─────► Loop Timer ──┬──┘
|
||||
▲ │ │
|
||||
└─────────┘ ▼
|
||||
End Node (outside loop)
|
||||
```
|
||||
|
||||
> **Important**: Since Loop Timer **produces no output until the time limit is reached**:
|
||||
> - **Human must connect to both Agent and Loop Timer**: This way the "continue loop" edge is handled by Human → Agent, while Loop Timer only handles time tracking
|
||||
> - **Loop Timer must connect to Agent (inside loop)**: So it's recognized as an in-loop node, avoiding premature loop termination
|
||||
> - **Loop Timer must connect to End Node (outside loop)**: When the time limit is reached, trigger the out-of-loop node to terminate the entire loop execution
|
||||
|
||||
### Timer State
|
||||
|
||||
- Timer state persists throughout the entire workflow execution
|
||||
- Timer starts on the first trigger to the Loop Timer node
|
||||
- When `reset_on_emit: true`, the timer resets after reaching the limit
|
||||
- When `reset_on_emit: false`, the timer continues running after reaching the limit, outputting on every subsequent trigger
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Time-based constraints**: Enforce time limits for loops (e.g., "review must complete within 5 minutes")
|
||||
- **Timeout protection**: Serve as a "circuit breaker" to prevent runaway processes
|
||||
- **Variable iteration time**: When each loop iteration takes unpredictable time, but total duration must be bounded
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Time Guard
|
||||
type: loop_timer
|
||||
config:
|
||||
max_duration: 5
|
||||
duration_unit: minutes
|
||||
reset_on_emit: true
|
||||
message: Time limit reached (5 minutes), process terminated.
|
||||
```
|
||||
|
||||
### Time-Limited Review Loop
|
||||
|
||||
This is the most typical use case for Loop Timer:
|
||||
|
||||
```yaml
|
||||
graph:
|
||||
id: timed_review_loop
|
||||
description: Review loop with 5-minute time limit
|
||||
|
||||
nodes:
|
||||
- id: Writer
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: Improve articles based on user feedback
|
||||
|
||||
- id: Reviewer
|
||||
type: human
|
||||
config:
|
||||
description: |
|
||||
Review the article, enter ACCEPT to accept or provide modification suggestions.
|
||||
|
||||
- id: Loop Gate
|
||||
type: loop_timer
|
||||
config:
|
||||
max_duration: 5
|
||||
duration_unit: minutes
|
||||
message: Time limit (5 minutes) reached, process automatically ended.
|
||||
|
||||
- id: Final Output
|
||||
type: passthrough
|
||||
config: {}
|
||||
|
||||
edges:
|
||||
# Main loop: Writer -> Reviewer
|
||||
- from: Writer
|
||||
to: Reviewer
|
||||
|
||||
# Condition 1: User enters ACCEPT -> End
|
||||
- from: Reviewer
|
||||
to: Final Output
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [ACCEPT]
|
||||
|
||||
# Condition 2: User enters modification suggestions -> Trigger both Writer to continue loop AND Loop Gate to track time
|
||||
- from: Reviewer
|
||||
to: Writer
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [ACCEPT]
|
||||
|
||||
- from: Reviewer
|
||||
to: Loop Gate
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [ACCEPT]
|
||||
|
||||
# Loop Gate connects to Writer (keeps it inside the loop)
|
||||
- from: Loop Gate
|
||||
to: Writer
|
||||
|
||||
# When Loop Gate reaches time limit: Trigger Final Output to end the process
|
||||
- from: Loop Gate
|
||||
to: Final Output
|
||||
|
||||
start: [Writer]
|
||||
end: [Final Output]
|
||||
```
|
||||
|
||||
**Execution Flow Explanation**:
|
||||
1. User first enters modification suggestions → Triggers both Writer (continue loop) and Loop Gate (track time, no output)
|
||||
2. User enters modification suggestions again → Triggers both Writer (continue loop) and Loop Gate (track time, no output)
|
||||
3. After 5 minutes of elapsed time → Loop Gate outputs message triggering Final Output, terminating the loop
|
||||
4. Or at any time user enters ACCEPT → Goes directly to Final Output to end
|
||||
|
||||
## Notes
|
||||
|
||||
- `max_duration` must be a positive number (> 0)
|
||||
- `duration_unit` must be one of: "seconds", "minutes", "hours"
|
||||
- Loop Timer **produces no output until the time limit is reached**, outgoing edges will not trigger
|
||||
- Ensure Loop Timer connects to both in-loop and out-of-loop nodes
|
||||
- The `message` field is optional, default message is `"Time limit reached (N units)"`
|
||||
- Timer starts on the first trigger to the Loop Timer node
|
||||
Executable
+206
@@ -0,0 +1,206 @@
|
||||
# Passthrough Node
|
||||
|
||||
The Passthrough node is the simplest node type. It performs no operations and passes received messages to downstream nodes. By default, it only passes the **last message**. It is primarily used for graph structure "wire management" optimization and context control.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `only_last_message` | bool | No | `true` | Whether to pass only the last message. Set to `false` to pass all messages. |
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```yaml
|
||||
config: {} # Uses default configuration, only passes the last message
|
||||
```
|
||||
|
||||
### Pass All Messages
|
||||
|
||||
```yaml
|
||||
config:
|
||||
only_last_message: false # Pass all received messages
|
||||
```
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Pass-through Behavior
|
||||
|
||||
- Receives all messages passed from upstream
|
||||
- **By default, only passes the last message** (`only_last_message: true`)
|
||||
- When `only_last_message: false`, passes all messages
|
||||
- Does not perform any content processing or transformation
|
||||
|
||||
### Graph Structure Optimization
|
||||
|
||||
The core value of the Passthrough node is not in data processing, but in **graph structure optimization** ("wire management"):
|
||||
- Makes complex edge connections clearer
|
||||
- Centrally manages outgoing edge configurations (such as `keep_message`)
|
||||
- Serves as a logical dividing point, improving workflow readability
|
||||
|
||||
## Key Uses
|
||||
|
||||
### 1. As an Entry Node to Preserve Initial Context
|
||||
|
||||
Using Passthrough as the workflow entry node, combined with the `keep_message: true` edge configuration, ensures that the user's initial task is always preserved in the context and won't be overwritten by subsequent node outputs:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Task Keeper
|
||||
type: passthrough
|
||||
config: {}
|
||||
|
||||
- id: Worker A
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
- id: Worker B
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
edges:
|
||||
# Distribute tasks from entry, preserving original message
|
||||
- from: Task Keeper
|
||||
to: Worker A
|
||||
keep_message: true # Preserve initial task context
|
||||
|
||||
- from: Task Keeper
|
||||
to: Worker B
|
||||
keep_message: true
|
||||
|
||||
start: [Task Keeper]
|
||||
```
|
||||
|
||||
**Effect**: Both Worker A and Worker B can see the user's original input, not just the output from the previous node.
|
||||
|
||||
### 2. Filtering Redundant Output in Loops
|
||||
|
||||
In workflows containing loops, nodes within the loop may produce a large amount of intermediate output. Passing all outputs to subsequent nodes would cause context bloat. Using a Passthrough node allows you to **pass only the final result of the loop**:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Iterative Improver
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: Continuously improve output based on feedback
|
||||
|
||||
- id: Evaluator
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: |
|
||||
Evaluate output quality, reply GOOD or provide improvement suggestions
|
||||
|
||||
- id: Result Filter
|
||||
type: passthrough
|
||||
config: {}
|
||||
|
||||
- id: Final Processor
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: Post-process the final result
|
||||
|
||||
edges:
|
||||
- from: Iterative Improver
|
||||
to: Evaluator
|
||||
|
||||
# Loop: Return to improvement node when evaluation fails
|
||||
- from: Evaluator
|
||||
to: Iterative Improver
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
none: [GOOD]
|
||||
|
||||
# Loop ends: Filter through Passthrough, only pass the last message
|
||||
- from: Evaluator
|
||||
to: Result Filter
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [GOOD]
|
||||
|
||||
- from: Result Filter
|
||||
to: Final Processor
|
||||
|
||||
start: [Iterative Improver]
|
||||
end: [Final Processor]
|
||||
```
|
||||
|
||||
**Effect**: Regardless of how many loop iterations occur, `Final Processor` will only receive the last output from `Evaluator` (the one indicating quality passed), not all intermediate results.
|
||||
|
||||
## Other Uses
|
||||
|
||||
- **Placeholder**: Reserve node positions during design phase
|
||||
- **Conditional branching**: Implement routing logic with conditional edges
|
||||
- **Debugging observation point**: Insert nodes for easy observation in the workflow
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Router
|
||||
type: passthrough
|
||||
config: {}
|
||||
```
|
||||
|
||||
### Conditional Routing
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Classifier
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: |
|
||||
Classify input content, reply TECHNICAL or BUSINESS
|
||||
|
||||
- id: Router
|
||||
type: passthrough
|
||||
config: {}
|
||||
|
||||
- id: Tech Handler
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
- id: Biz Handler
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
edges:
|
||||
- from: Classifier
|
||||
to: Router
|
||||
- from: Router
|
||||
to: Tech Handler
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [TECHNICAL]
|
||||
- from: Router
|
||||
to: Biz Handler
|
||||
condition:
|
||||
type: keyword
|
||||
config:
|
||||
any: [BUSINESS]
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use meaningful node IDs that describe their topological role (e.g., `Task Keeper`, `Result Filter`)
|
||||
- When used as an entry node, configure outgoing edges with `keep_message: true` to preserve context
|
||||
- Use after loops to filter out redundant intermediate output
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
# Python Node
|
||||
|
||||
The Python node is used to execute Python scripts or inline code within workflows, implementing custom data processing, API calls, file operations, and other logic. Scripts are executed in the shared `code_workspace/` directory and can access workflow context data.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `interpreter` | string | No | Current Python | Python interpreter path |
|
||||
| `args` | list[str] | No | `[]` | Startup arguments appended to the interpreter |
|
||||
| `env` | dict[str, str] | No | `{}` | Additional environment variables, overrides system defaults |
|
||||
| `timeout_seconds` | int | No | `60` | Script execution timeout (seconds) |
|
||||
| `encoding` | string | No | `utf-8` | Encoding for parsing stdout/stderr |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Code Workspace
|
||||
|
||||
Python scripts are executed within the `code_workspace/` directory:
|
||||
- Scripts can read and write files in this directory
|
||||
- Multiple Python nodes share the same workspace
|
||||
- The workspace persists for the duration of a single workflow execution
|
||||
|
||||
### Input/Output
|
||||
|
||||
- **Input**: Outputs from upstream nodes are passed as environment variables or standard input
|
||||
- **Output**: The script's stdout output will be passed as a Message to downstream nodes
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Data processing**: Parse JSON/XML, data transformation, formatting
|
||||
- **API calls**: Call third-party services, fetch external data
|
||||
- **File operations**: Read/write files, generate reports
|
||||
- **Complex calculations**: Mathematical operations, algorithm implementations
|
||||
- **Glue logic**: Custom logic connecting different nodes
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Data Processor
|
||||
type: python
|
||||
config:
|
||||
timeout_seconds: 120
|
||||
env:
|
||||
key: value
|
||||
```
|
||||
|
||||
### Specifying Interpreter and Arguments
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Script Runner
|
||||
type: python
|
||||
config:
|
||||
interpreter: /usr/bin/python3.11
|
||||
timeout_seconds: 300
|
||||
encoding: utf-8
|
||||
```
|
||||
|
||||
### Typical Workflow Example
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: LLM Generator
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
api_key: ${API_KEY}
|
||||
role: You need to generate executable Python code based on user input. The code should be wrapped in ```python ```.
|
||||
|
||||
- id: Result Parser
|
||||
type: python
|
||||
config:
|
||||
timeout_seconds: 30
|
||||
|
||||
edges:
|
||||
- from: LLM Generator
|
||||
to: Result Parser
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Ensure script files are placed in the `code_workspace/` directory
|
||||
- Long-running scripts should have an appropriately increased `timeout_seconds`
|
||||
- Use `env` to pass additional environment variables, accessible in scripts via `os.getenv`
|
||||
Executable
+138
@@ -0,0 +1,138 @@
|
||||
# Subgraph Node
|
||||
|
||||
The Subgraph node allows embedding another workflow graph into the current workflow, enabling process reuse and modular design. Subgraphs can come from external YAML files or be defined inline in the configuration.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `type` | string | Yes | - | Subgraph source type: `file` or `config` |
|
||||
| `config` | object | Yes | - | Contains different configurations depending on `type` |
|
||||
|
||||
### File Type Configuration
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `path` | string | Yes | Subgraph file path (relative to `yaml_instance/` or absolute path) |
|
||||
|
||||
### Config Type Configuration
|
||||
|
||||
Inline definition of the complete subgraph structure, containing the same fields as the top-level `graph`:
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `id` | string | Yes | Subgraph identifier |
|
||||
| `description` | string | No | Subgraph description |
|
||||
| `log_level` | string | No | Log level (DEBUG/INFO) |
|
||||
| `nodes` | list | Yes | Node list |
|
||||
| `edges` | list | No | Edge list |
|
||||
| `start` | list | No | Entry node list |
|
||||
| `end` | list | No | Exit node list |
|
||||
| `memory` | list | No | Memory definitions specific to the subgraph |
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Modular Reuse
|
||||
|
||||
Extract commonly used process fragments into independent YAML files that can be reused by multiple workflows:
|
||||
- Example: Package an "article polishing" process as a subgraph
|
||||
- Different main workflows can call this subgraph
|
||||
|
||||
### Variable Inheritance
|
||||
|
||||
Subgraphs inherit `vars` variable definitions from the parent graph, supporting cross-level variable passing.
|
||||
|
||||
### Execution Isolation
|
||||
|
||||
Subgraphs execute as independent units with their own:
|
||||
- Node namespace
|
||||
- Log level configuration
|
||||
- Memory definitions (optional)
|
||||
|
||||
## When to Use
|
||||
|
||||
- **Process reuse**: Multiple workflows sharing the same sub-processes
|
||||
- **Modular design**: Breaking complex processes into manageable smaller units
|
||||
- **Team collaboration**: Different teams maintaining different subgraph modules
|
||||
|
||||
## Examples
|
||||
|
||||
### Referencing External File
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Review Process
|
||||
type: subgraph
|
||||
config:
|
||||
type: file
|
||||
config:
|
||||
path: common/review_flow.yaml
|
||||
```
|
||||
|
||||
### Inline Subgraph Definition
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Translation Unit
|
||||
type: subgraph
|
||||
config:
|
||||
type: config
|
||||
config:
|
||||
id: translation_subgraph
|
||||
description: Multi-language translation subprocess
|
||||
nodes:
|
||||
- id: Translator
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: You are a professional translator who translates content to the target language.
|
||||
- id: Proofreader
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
role: You are a proofreading expert who checks and polishes translated content.
|
||||
edges:
|
||||
- from: Translator
|
||||
to: Proofreader
|
||||
start: [Translator]
|
||||
end: [Proofreader]
|
||||
```
|
||||
|
||||
### Combining Multiple Subgraphs
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- id: Input Handler
|
||||
type: agent
|
||||
config:
|
||||
provider: openai
|
||||
name: gpt-4o
|
||||
|
||||
- id: Analysis Module
|
||||
type: subgraph
|
||||
config:
|
||||
type: file
|
||||
config:
|
||||
path: modules/analysis.yaml
|
||||
|
||||
- id: Report Module
|
||||
type: subgraph
|
||||
config:
|
||||
type: file
|
||||
config:
|
||||
path: modules/report_gen.yaml
|
||||
|
||||
edges:
|
||||
- from: Input Handler
|
||||
to: Analysis Module
|
||||
- from: Analysis Module
|
||||
to: Report Module
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Subgraph file paths support relative paths (based on `yaml_instance/`) and absolute paths
|
||||
- Avoid circular nesting (A references B, B references A)
|
||||
- The subgraph's `start` and `end` nodes determine how data flows in and out, which decides how the subgraph processes messages from the parent graph and which node's final output is returned to the parent graph
|
||||
Reference in New Issue
Block a user