Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions docs/docs/section-2/step-02.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ This is where `AgenticScope` comes in.
- A **shared context** that keeps track throughout a workflow execution.
- Contains a **map** of key-value pairs that agents can read from and write to: the _state_.
- This state is automatically populated with **inputs** from the workflow method signature.
- This state is automatically updated with **outputs** from each agent using their `outputName`.
- This state is automatically updated with **outputs** from each agent using their `outputKey`.

**How It Works:**

Expand All @@ -74,8 +74,8 @@ graph LR
B -->|Extract| E[Workflow Result]
```

When an agent completes, its result is stored in the `AgenticScope`'s state using the `outputName` specified in the `@Agent` annotation.
The next agent in the workflow can access this value as an input parameter using the name specified in the `outputName` annotation.
When an agent completes, its result is stored in the `AgenticScope`'s state using the `outputKey` specified in the `@Agent` annotation.
The next agent in the workflow can access this value as an input parameter using the name specified in the `outputKey` annotation.

---

Expand Down Expand Up @@ -187,11 +187,11 @@ Provides all the context needed:
- **Previous condition**: `{carCondition}` — allows the agent to understand changes
- Feedback from multiple sources: `{rentalFeedback}`, `{carWashFeedback}`

### `@Agent` with `outputName`
Notice the new **`outputName` parameter**:
### `@Agent` with `outputKey`
Notice the new **`outputKey` parameter**:

```java
@Agent(outputName = "carCondition", ...)
@Agent(outputKey = "carCondition", ...)
```

This tells the framework to store the agent's result in the `AgenticScope`'s state under the key `"carCondition"`.
Expand Down Expand Up @@ -224,7 +224,7 @@ This simple record combines the results from both agents in our workflow.

## Step 3: Update the CarWashAgent

The `CarWashAgent` needs to specify an `outputName` so its result can be accessed by the workflow.
The `CarWashAgent` needs to specify an `outputKey` so its result can be accessed by the workflow.

Update `src/main/java/com/carmanagement/agentic/agents/CarWashAgent.java`:

Expand All @@ -234,7 +234,7 @@ Update `src/main/java/com/carmanagement/agentic/agents/CarWashAgent.java`:

**Key change:**

In the `@Agent` annotation, adds `outputName = "carWashAgentResult"` to the `@Agent` annotation. This stores the agent's response in the `AgenticScope`'s state, making it available to subsequent agents and the workflow output method.
In the `@Agent` annotation, adds `outputKey = "carWashAgentResult"` to the `@Agent` annotation. This stores the agent's response in the `AgenticScope`'s state, making it available to subsequent agents and the workflow output method.

---

Expand Down Expand Up @@ -272,15 +272,15 @@ This annotation defines a **sequence workflow**:

```java
@SequenceAgent(
outputName = "carConditions",
outputKey = "carConditions",
subAgents = {
@SubAgent(type = CarWashAgent.class, outputName = "carWashAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputName = "carCondition")
@SubAgent(type = CarWashAgent.class, outputKey = "carWashAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputKey = "carCondition")
}
)
```

- **`outputName`**: Where to store the final workflow result in `AgenticScope`'s state
- **`outputKey`**: Where to store the final workflow result in `AgenticScope`'s state
- **`subAgents`**: The list of agents to execute in order
- Agent 1: `CarWashAgent`: determines if washing is needed
- Agent 2: `CarConditionFeedbackAgent`: updates the car condition
Expand Down Expand Up @@ -319,7 +319,7 @@ static CarConditions output(String carCondition, String carWashAgentResult) {

**How it works:**

1. The method parameters (`carCondition`, `carWashAgentResult`) are automatically extracted from the `AgenticScope` by matching their names with the `outputName` values from the agents
1. The method parameters (`carCondition`, `carWashAgentResult`) are automatically extracted from the `AgenticScope` by matching their names with the `outputKey` values from the agents
2. The method processes these values (in this case, checking if a car wash is required)
3. Returns a `CarConditions` object combining both results

Expand Down Expand Up @@ -473,7 +473,7 @@ sequenceDiagram

1. All workflow inputs are stored in `AgenticScope`'s state
2. Each agent reads what it needs from the scope's state
3. Each agent writes its result back to the scope's state using its `outputName`
3. Each agent writes its result back to the scope's state using its `outputKey`
4. The `@Output` method extracts specific values from the scope to build the final result

---
Expand Down Expand Up @@ -550,8 +550,8 @@ How does the condition agent synthesize feedback from multiple sources?
??? warning "Workflow not updating car condition"
Check that:

- The `CarWashAgent` has `outputName = "carWashAgentResult"`
- The `CarConditionFeedbackAgent` has `outputName = "carCondition"`
- The `CarWashAgent` has `outputKey = "carWashAgentResult"`
- The `CarConditionFeedbackAgent` has `outputKey = "carCondition"`
- The `@Output` method parameter names match these output names exactly

??? warning "UI not showing Condition column"
Expand Down
30 changes: 15 additions & 15 deletions docs/docs/section-2/step-03.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ In `src/main/java/com/carmanagement/agentic/agents`, create `MaintenanceFeedback

- **System message**: Focuses on mechanical issues, performance problems, and maintenance needs
- **Specific output format**: Returns "MAINTENANCE_NOT_REQUIRED" when no maintenance is needed (for easy conditional checking)
- **outputName**: `"maintenanceRequest"` — stores the result in AgenticScope's state
- **outputKey**: `"maintenanceRequest"` — stores the result in AgenticScope's state
- **Three feedback sources**: Analyzes rental, car wash, AND maintenance feedback

### Step 2: Create the CarWashFeedbackAgent
Expand All @@ -203,7 +203,7 @@ In `src/main/java/com/carmanagement/agentic/agents`, create `CarWashFeedbackAgen

- **System message**: Focuses on cleanliness issues — dirt, stains, smells
- **Specific output format**: Returns "CARWASH_NOT_REQUIRED" when no washing is needed
- **outputName**: `"carWashRequest"` — stores the result in AgenticScope's state
- **outputKey**: `"carWashRequest"` — stores the result in AgenticScope's state
- **Same inputs**: Also analyzes all three feedback sources

---
Expand All @@ -226,10 +226,10 @@ In `src/main/java/com/carmanagement/agentic/workflow`, create `FeedbackWorkflow.

```java
@ParallelAgent(
outputName = "feedbackResult",
outputKey = "feedbackResult",
subAgents = {
@SubAgent(type = CarWashFeedbackAgent.class, outputName = "carWashRequest"),
@SubAgent(type = MaintenanceFeedbackAgent.class, outputName = "maintenanceRequest")
@SubAgent(type = CarWashFeedbackAgent.class, outputKey = "carWashRequest"),
@SubAgent(type = MaintenanceFeedbackAgent.class, outputKey = "maintenanceRequest")
}
)
```
Expand All @@ -238,7 +238,7 @@ This defines a **parallel workflow**:

- Both agents execute **concurrently**
- Improves performance, no waiting for one to finish before the other starts
- Each agent has its own `outputName` to store results independently
- Each agent has its own `outputKey` to store results independently

!!! note "Why Parallel Here?"
The two feedback agents analyze different aspects (cleaning vs. maintenance) and don't depend on each other.
Expand Down Expand Up @@ -304,10 +304,10 @@ In `src/main/java/com/carmanagement/agentic/workflow`, create `ActionWorkflow.ja

```java
@ConditionalAgent(
outputName = "actionResult",
outputKey = "actionResult",
subAgents = {
@SubAgent(type = MaintenanceAgent.class, outputName = "actionResult"),
@SubAgent(type = CarWashAgent.class, outputName = "actionResult")
@SubAgent(type = MaintenanceAgent.class, outputKey = "actionResult"),
@SubAgent(type = CarWashAgent.class, outputKey = "actionResult")
}
)
```
Expand Down Expand Up @@ -443,10 +443,10 @@ Update `src/main/java/com/carmanagement/agentic/workflow/CarProcessingWorkflow.j
#### The Sequence

```java
@SequenceAgent(outputName = "carProcessingAgentResult", subAgents = {
@SubAgent(type = FeedbackWorkflow.class, outputName = "carProcessingAgentResult"),
@SubAgent(type = ActionWorkflow.class, outputName = "carProcessingAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputName = "carProcessingAgentResult")
@SequenceAgent(outputKey = "carProcessingAgentResult", subAgents = {
@SubAgent(type = FeedbackWorkflow.class, outputKey = "feedbackResult"),
@SubAgent(type = ActionWorkflow.class, outputKey = "actionResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputKey = "carCondition")
})
```

Expand Down Expand Up @@ -689,7 +689,7 @@ Add logging to each agent and workflow to print when they start and finish. Obse

??? warning "Conditional workflow always/never executing certain agents"
- Verify your `@ActivationCondition` methods are correctly named
- Check that parameter names match the `outputName` values exactly
- Check that parameter names match the `outputKey` values exactly
- Add logging to the condition methods to see what values they're receiving

??? warning "Error: Cannot find symbol 'RequiredAction'"
Expand All @@ -699,7 +699,7 @@ Add logging to each agent and workflow to print when they start and finish. Obse
- Updated `CarConditions` to use it

??? warning "Agents getting wrong input values"
Remember that parameter names must match the `outputName` from previous agents or workflow inputs. Check for typos!
Remember that parameter names must match the `outputKey` from previous agents or workflow inputs. Check for typos!

---

Expand Down
10 changes: 5 additions & 5 deletions docs/docs/section-2/step-04.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ In `src/main/java/com/carmanagement/agentic/agents`, create `DispositionFeedback

- **System message**: Focuses on economic viability (is the car worth repairing?)
- **Specific output format**: Returns `"DISPOSITION_NOT_REQUIRED"` when the car is repairable
- **outputName**: `"dispositionRequest"` (stores the analysis in AgenticScope's state)
- **outputKey**: `"dispositionRequest"` (stores the analysis in AgenticScope's state)
- **Three feedback sources**: Analyzes rental, car wash, and maintenance feedback

**Decision Criteria:**
Expand Down Expand Up @@ -297,15 +297,15 @@ In `src/main/java/com/carmanagement/agentic/agents`, create `DispositionAgent.ja
```java
@A2AClientAgent(
a2aServerUrl = "http://localhost:8888",
outputName = "dispositionAgentResult",
outputKey = "dispositionAgentResult",
description = "Car disposition specialist. Recommends how to dispose of a car (scrap, sell, donate)."
)
```

This annotation transforms the method into an **A2A client**:

- **`a2aServerUrl`**: The URL of the remote A2A server
- **`outputName`**: Where to store the result in AgenticScope's state
- **`outputKey`**: Where to store the result in AgenticScope's state
- **`description`**: Describes the agent's purpose (helps with agent discovery)

#### The Method Signature
Expand Down Expand Up @@ -355,7 +355,7 @@ Update `src/main/java/com/carmanagement/agentic/workflow/FeedbackWorkflow.java`:
Added `DispositionFeedbackAgent` to the parallel workflow:

```java
@SubAgent(type = DispositionFeedbackAgent.class, outputName = "dispositionRequest")
@SubAgent(type = DispositionFeedbackAgent.class, outputKey = "dispositionRequest")
```

Now **three agents run concurrently**:
Expand All @@ -381,7 +381,7 @@ Update `src/main/java/com/carmanagement/agentic/workflow/ActionWorkflow.java`:
#### Added DispositionAgent to SubAgents

```java
@SubAgent(type = DispositionAgent.class, outputName = "actionResult")
@SubAgent(type = DispositionAgent.class, outputKey = "actionResult")
```

#### Added Activation Condition
Expand Down
2 changes: 1 addition & 1 deletion section-2/step-02/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<quarkus.platform.version>3.29.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.4</surefire-plugin.version>
<quarkus-langchain4j.version>1.3.1</quarkus-langchain4j.version>
<quarkus-langchain4j.version>1.4.1</quarkus-langchain4j.version>
</properties>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface CarConditionFeedbackAgent {
Rental Feedback: {rentalFeedback}
Car Wash Feedback: {carWashFeedback}
""")
@Agent(outputName = "carCondition",
@Agent(outputKey = "carCondition",
description = "Car condition analyzer. Determines the current condition of a car based on feedback.")
String analyzeForCondition(
String carMake,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ call the provided tool and recommend appropriate car wash services (exterior was
Rental Feedback: {rentalFeedback}
Car Wash Feedback: {carWashFeedback}
""")
@Agent(outputName = "carWashAgentResult",
@Agent(outputKey = "carWashAgentResult",
description = "Car wash specialist. Determines what car wash services are needed.")
@ToolBox(CarWashTool.class)
String processCarWash(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public interface CarProcessingWorkflow {
/**
* Processes a car return by running feedback analysis and then appropriate actions.
*/
@SequenceAgent(outputName = "carConditions", subAgents = {
@SubAgent(type = CarWashAgent.class, outputName = "carWashAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputName = "carCondition")
@SequenceAgent(outputKey = "carConditions", subAgents = {
@SubAgent(type = CarWashAgent.class, outputKey = "carWashAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputKey = "carCondition")
})
CarConditions processCarReturn(
String carMake,
Expand Down
2 changes: 1 addition & 1 deletion section-2/step-03/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<quarkus.platform.version>3.29.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.4</surefire-plugin.version>
<quarkus-langchain4j.version>1.3.1</quarkus-langchain4j.version>
<quarkus-langchain4j.version>1.4.1</quarkus-langchain4j.version>
</properties>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Always provide a very short (no more than 200 characters) condition description,
Maintenance Recommendation: {maintenanceRequest}
""")
@Agent(description = "Car condition analyzer. Determines the current condition of a car based on feedback.",
outputName = "carCondition")
outputKey = "carCondition")
String analyzeForCondition(
String carMake,
String carModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ call the provided tool and recommend appropriate car wash services (exterior was
{carWashRequest}
""")
@Agent(description = "Car wash specialist. Determines what car wash services are needed.",
outputName = "carWashAgentResult")
outputKey = "carWashAgentResult")
@ToolBox(CarWashTool.class)
String processCarWash(
String carMake,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Be specific about what type of car wash is needed (exterior, interior, detailing
Maintenance Feedback: {maintenanceFeedback}
""")
@Agent(description = "Car wash analyzer. Using feedback, determines if a car wash is needed.",
outputName = "carWashRequest")
outputKey = "carWashRequest")
String analyzeForCarWash(
String carMake,
String carModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface MaintenanceAgent {
{maintenanceRequest}
""")
@Agent(description = "Car maintenance specialist. Using car information and request, determines what maintenance services are needed.",
outputName = "maintenanceAgentResult")
outputKey = "maintenanceAgentResult")
@ToolBox(MaintenanceTool.class)
String processMaintenance(
String carMake,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Be specific about what type of maintenance is needed (oil change, tire rotation,
Maintenance Feedback: {maintenanceFeedback}
""")
@Agent(description = "Car maintenance analyzer. Using feedback, determines if a car needs maintenance.",
outputName = "maintenanceRequest")
outputKey = "maintenanceRequest")
String analyzeForMaintenance(
String carMake,
String carModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public interface ActionWorkflow {
/**
* Runs the appropriate action agent based on the feedback analysis.
*/
@ConditionalAgent(outputName = "actionResult", subAgents = {
@SubAgent(type = MaintenanceAgent.class, outputName = "actionResult"),
@SubAgent(type = CarWashAgent.class, outputName = "actionResult")
@ConditionalAgent(outputKey = "actionResult", subAgents = {
@SubAgent(type = MaintenanceAgent.class, outputKey = "actionResult"),
@SubAgent(type = CarWashAgent.class, outputKey = "actionResult")
})
String processAction(
String carMake,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ public interface CarProcessingWorkflow {
/**
* Processes a car return by running feedback analysis and then appropriate actions.
*/
@SequenceAgent(outputName = "carProcessingAgentResult", subAgents = {
@SubAgent(type = FeedbackWorkflow.class, outputName = "carProcessingAgentResult"),
@SubAgent(type = ActionWorkflow.class, outputName = "carProcessingAgentResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputName = "carProcessingAgentResult")
@SequenceAgent(outputKey = "carProcessingAgentResult", subAgents = {
@SubAgent(type = FeedbackWorkflow.class, outputKey = "feedbackResult"),
@SubAgent(type = ActionWorkflow.class, outputKey = "actionResult"),
@SubAgent(type = CarConditionFeedbackAgent.class, outputKey = "carCondition")
})
CarConditions processCarReturn(
String carMake,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ public interface FeedbackWorkflow {
/**
* Runs multiple feedback agents in parallel to analyze different aspects of car feedback.
*/
@Agent(outputName = "feedbackResult")
@ParallelAgent(outputName = "feedbackResult", subAgents = {
@SubAgent(type = CarWashFeedbackAgent.class, outputName = "carWashRequest"),
@SubAgent(type = MaintenanceFeedbackAgent.class, outputName = "maintenanceRequest")
@ParallelAgent(outputKey = "feedbackResult", subAgents = {
@SubAgent(type = CarWashFeedbackAgent.class, outputKey = "carWashRequest"),
@SubAgent(type = MaintenanceFeedbackAgent.class, outputKey = "maintenanceRequest")
})
String analyzeFeedback(
String carMake,
Expand Down
8 changes: 7 additions & 1 deletion section-2/step-04/multi-agent-system/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
<quarkus.platform.version>3.29.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.5.4</surefire-plugin.version>
<quarkus-langchain4j.version>1.3.1</quarkus-langchain4j.version>
<quarkus-langchain4j.version>1.4.1</quarkus-langchain4j.version>
<langchain4j.version>1.6.0</langchain4j.version>
<langchain4j-beta.version>1.8.0-beta15</langchain4j-beta.version>
<a2a.version>0.3.0.Beta1</a2a.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -62,6 +63,11 @@
<artifactId>langchain4j-agentic-a2a</artifactId>
<version>${langchain4j-beta.version}</version>
</dependency>
<dependency>
<groupId>io.github.a2asdk</groupId>
<artifactId>a2a-java-sdk-reference-jsonrpc</artifactId>
<version>${a2a.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
Expand Down
Loading