-
Notifications
You must be signed in to change notification settings - Fork 542
feat: add declarative workflow subagents (Sequential, Parallel, Loop) #1743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jsonmp-k8
wants to merge
7
commits into
kagent-dev:main
Choose a base branch
from
jsonmp-k8:feat/workflow-subagents
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ab30992
feat: add declarative workflow subagents (Sequential, Parallel, Loop)
jsonmp-k8 ad9c2e7
fix: resolve F821 lint errors for BaseAgent type annotation
jsonmp-k8 8415421
fix: address copilot review comments on workflow subagents
jsonmp-k8 9729c77
style: fix ruff formatting for long method signatures
jsonmp-k8 e268ccb
chore: sync Helm CRD templates with generated manifests
jsonmp-k8 7a761e8
fix: add approval callbacks to Go sub-agents and validate name pattern
jsonmp-k8 3d895a0
Merge branch 'main' into feat/workflow-subagents
EItanya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| # EP-991: Declarative Workflow Subagents | ||
|
|
||
| - Issue: [#991](https://github.com/kagent-dev/kagent/issues/991) | ||
|
|
||
| ## Background | ||
|
|
||
| Google ADK provides three workflow agent primitives — `SequentialAgent`, `ParallelAgent`, and `LoopAgent` — that deterministically orchestrate in-process sub-agents. kagent currently supports agent-to-agent delegation via A2A tool references, but this is LLM-driven (the model decides when and whether to call sub-agents). There is no way to declare deterministic multi-agent workflows in YAML. | ||
|
|
||
| This EP adds a `workflow` field to the `DeclarativeAgentSpec` CRD that lets users declare Sequential, Parallel, and Loop orchestration patterns. Sub-agents are defined inline within the parent agent's CRD and run in-process within the same pod, sharing session state. | ||
|
|
||
| ## Motivation | ||
|
|
||
| Users building multi-agent systems need deterministic orchestration patterns: | ||
| - **Sequential**: Run agents in a fixed order (e.g., writer → editor → publisher) | ||
| - **Parallel**: Run agents concurrently and merge results (e.g., research multiple topics simultaneously) | ||
| - **Loop**: Iterate until a condition is met (e.g., write → critique → refine cycles) | ||
|
|
||
| Today, users must either rely on the LLM to coordinate agents (non-deterministic) or write custom BYO agents in code. Declarative workflow support brings these patterns to YAML-only users and ensures reliable execution order. | ||
|
|
||
| ### Goals | ||
|
|
||
| 1. Support `Sequential`, `Parallel`, and `Loop` workflow types via CRD configuration | ||
| 2. Sub-agents run in-process within a single pod, sharing session state | ||
| 3. Each sub-agent can have its own system message, model config, and MCP tools | ||
| 4. Loop workflows support `maxIterations` and exit-on-escalation | ||
| 5. Both Python and Go runtimes support workflow agents | ||
|
|
||
| ### Non-Goals | ||
|
|
||
| 1. Remote sub-agents (separate pods communicating via A2A within a workflow) | ||
| 2. Nested workflows (a sub-agent that is itself a workflow) | ||
| 3. Conditional branching or DAG-based orchestration beyond what ADK provides | ||
| 4. UI visualization of workflow topology | ||
|
|
||
| ## Implementation | ||
|
|
||
| ### 1. CRD Types (`go/api/v1alpha2/agent_types.go`) | ||
|
|
||
| New types added to the agent CRD: | ||
|
|
||
| ```go | ||
| // +kubebuilder:validation:Enum=Sequential;Parallel;Loop | ||
| type WorkflowType string | ||
|
|
||
| type WorkflowSpec struct { | ||
| Type WorkflowType `json:"type"` | ||
| SubAgents []InlineAgentSpec `json:"subAgents"` | ||
| MaxIterations *int `json:"maxIterations,omitempty"` // Loop only | ||
| } | ||
|
|
||
| type InlineAgentSpec struct { | ||
| Name string `json:"name"` | ||
| Description string `json:"description,omitempty"` | ||
| SystemMessage string `json:"systemMessage"` | ||
| ModelConfig string `json:"modelConfig,omitempty"` // inherits parent if unset | ||
| Tools []*Tool `json:"tools,omitempty"` // MCP tools only | ||
| } | ||
| ``` | ||
|
|
||
| The `Workflow` field is added to `DeclarativeAgentSpec` with CEL validation rules: | ||
| - `workflow` is mutually exclusive with `systemMessage`, `systemMessageFrom`, and `tools` | ||
| - `workflow` is mutually exclusive with `memory`, `context`, and `executeCodeBlocks` | ||
| - `maxIterations` is only valid for `Loop` type; when unset, the loop runs indefinitely until a sub-agent escalates | ||
|
|
||
| ### 2. ADK Config Types (`go/api/adk/types.go`) | ||
|
|
||
| JSON-serializable types passed to both Python and Go runtimes: | ||
|
|
||
| ```go | ||
| type WorkflowAgentConfig struct { | ||
| Type string `json:"type"` // "sequential", "parallel", "loop" | ||
| SubAgents []SubAgentConfig `json:"sub_agents"` | ||
| MaxIterations *int `json:"max_iterations,omitempty"` | ||
| } | ||
|
|
||
| type SubAgentConfig struct { | ||
| Name string `json:"name"` | ||
| Description string `json:"description,omitempty"` | ||
| Instruction string `json:"instruction"` | ||
| Model Model `json:"model"` | ||
| HttpTools []HttpMcpServerConfig `json:"http_tools,omitempty"` | ||
| SseTools []SseMcpServerConfig `json:"sse_tools,omitempty"` | ||
| } | ||
| ``` | ||
|
|
||
| The `AgentConfig` struct gets a new `Workflow *WorkflowAgentConfig` field. | ||
|
|
||
| ### 3. Translator Changes | ||
|
|
||
| The translator's `translateInlineAgent` method branches when `Workflow` is set, calling a new `translateWorkflowAgent` method that: | ||
|
|
||
| 1. Resolves the default model config (used by sub-agents without their own) | ||
| 2. For each sub-agent: resolves its model (own or inherited), translates MCP tools | ||
| 3. Returns an `AgentConfig` with the `Workflow` field populated | ||
|
|
||
| The `translateMCPServerTarget` method is refactored to support writing tool configs to `SubAgentConfig` in addition to `AgentConfig`. | ||
|
|
||
| Validation rules enforced by the translator: | ||
| - Sub-agent names must be unique within a workflow | ||
| - Agent-as-tool references are not allowed within workflow sub-agents | ||
| - `maxIterations` only meaningful for Loop type | ||
|
|
||
| ### 4. Python Runtime (`python/packages/kagent-adk/src/kagent/adk/types.py`) | ||
|
|
||
| The `AgentConfig.to_agent()` method is refactored: | ||
| - Existing logic moves to `_build_llm_agent()` | ||
| - New `_build_workflow_agent()` constructs in-process sub-agents and wraps them in the appropriate ADK workflow agent | ||
|
|
||
| ```python | ||
| from google.adk.agents import SequentialAgent, ParallelAgent, LoopAgent | ||
|
|
||
| def _build_workflow_agent(self, name, sts_integration): | ||
| sub_agents = [self._build_sub_agent(cfg, sts_integration) for cfg in self.workflow.sub_agents] | ||
| match self.workflow.type: | ||
| case "sequential": return SequentialAgent(name=name, sub_agents=sub_agents, ...) | ||
| case "parallel": return ParallelAgent(name=name, sub_agents=sub_agents, ...) | ||
| case "loop": return LoopAgent(name=name, sub_agents=sub_agents, max_iterations=...) | ||
| ``` | ||
|
|
||
| ### 5. Go Runtime (`go/adk/pkg/agent/agent.go`) | ||
|
|
||
| New `CreateWorkflowAgent()` function creates sub-agents via `llmagent.New()` and wraps them in the appropriate workflow agent from `google.golang.org/adk/agent/workflowagents/`. | ||
|
|
||
| The runner adapter (`go/adk/pkg/runner/adapter.go`) routes to `CreateWorkflowAgent()` when `agentConfig.Workflow != nil`. | ||
|
|
||
| ### Example: Sequential Workflow | ||
|
|
||
| ```yaml | ||
| apiVersion: kagent.dev/v1alpha2 | ||
| kind: Agent | ||
| metadata: | ||
| name: writer-critic | ||
| spec: | ||
| type: Declarative | ||
| description: Generates content then reviews it | ||
| declarative: | ||
| runtime: python | ||
| modelConfig: default-model-config | ||
| workflow: | ||
| type: Sequential | ||
| subAgents: | ||
| - name: writer | ||
| description: Writes creative content | ||
| systemMessage: | | ||
| You are a creative writer. Write a compelling paragraph about the given topic. | ||
| - name: critic | ||
| description: Reviews and improves content | ||
| systemMessage: | | ||
| You are a writing critic. Review the previous content and provide improvements. | ||
| ``` | ||
|
|
||
| ### Example: Loop Workflow | ||
|
|
||
| ```yaml | ||
| apiVersion: kagent.dev/v1alpha2 | ||
| kind: Agent | ||
| metadata: | ||
| name: iterative-refiner | ||
| spec: | ||
| type: Declarative | ||
| description: Iteratively refines content through write-critique cycles | ||
| declarative: | ||
| modelConfig: default-model-config | ||
| workflow: | ||
| type: Loop | ||
| maxIterations: 5 | ||
| subAgents: | ||
| - name: writer | ||
| systemMessage: Write or refine content based on feedback. | ||
| - name: critic | ||
| systemMessage: Critique the content. If satisfactory, escalate to stop the loop. | ||
| ``` | ||
|
|
||
| ### Test Plan | ||
|
|
||
| 1. **Translator golden tests**: Input YAML + expected output JSON for sequential, parallel, and loop workflows | ||
| 2. **Python unit tests**: Verify `to_agent()` returns correct workflow agent type with correct sub-agent count and configuration | ||
| 3. **Go unit tests**: Verify `CreateWorkflowAgent()` for all three workflow types | ||
| 4. **CRD validation**: Verify CEL rules reject invalid combinations (workflow + systemMessage, maxIterations on non-Loop) | ||
|
|
||
| ## Alternatives | ||
|
|
||
| **Remote sub-agents via A2A**: Each sub-agent as a separate Agent CR and pod. Rejected because ADK workflow agents require in-process sub-agents sharing session state. Remote A2A adds network latency and breaks session state sharing. The existing agent-as-tool pattern already covers the remote case. | ||
|
|
||
| **Workflow as a separate CRD**: A dedicated `Workflow` resource type that references Agent CRs. Rejected for the same reason — ADK workflow agents need in-process sub-agents, not separate pods. | ||
|
|
||
| ## Open Questions | ||
|
|
||
| 1. Should sub-agents within a workflow be allowed to reference remote agents (other Agent CRs) as tools? Currently prohibited for simplicity; could be added later since the pod already has network access. | ||
| 2. Should nested workflows (a sub-agent that is itself a workflow) be supported? Deferred to a future EP. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.