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
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,11 @@ public void shouldGetAgentState() {

// After completion, query agent state
var state = agentClient.getState();
assertThat(state).isNotNull();
assertThat(state.goal()).isNotNull();
assertThat(state.phase()).isEqualTo("PHASE_STOPPED");
assertThat(state.paused()).isFalse();
assertThat(state.totalTokenUsage()).isNotNull();
assertThat(state.currentTask()).isEmpty();
assertThat(state.pendingTaskIds()).isEmpty();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
package akka.javasdk.agent.autonomous;

import akka.annotation.DoNotInherit;
import java.util.List;
import java.util.Optional;

/**
* Summary of an autonomous agent's current state.
Expand All @@ -14,17 +16,29 @@
@DoNotInherit
public final class AgentState {

/** Information about a task: its id and name. */
public record TaskInfo(String taskId, String taskName) {}

private final String phase;
private final boolean paused;
private final String goal;
private final AutonomousAgent.TokenUsage totalTokenUsage;
private final Optional<TaskInfo> currentTask;
private final List<String> pendingTaskIds;

public AgentState(
String phase, boolean paused, String goal, AutonomousAgent.TokenUsage totalTokenUsage) {
String phase,
boolean paused,
String goal,
AutonomousAgent.TokenUsage totalTokenUsage,
Optional<TaskInfo> currentTask,
List<String> pendingTaskIds) {
this.phase = phase;
this.paused = paused;
this.goal = goal;
this.totalTokenUsage = totalTokenUsage;
this.currentTask = currentTask;
this.pendingTaskIds = pendingTaskIds;
}

/** The current phase of the agent (e.g. "idle", "running", "stopped"). */
Expand All @@ -46,4 +60,14 @@ public String goal() {
public AutonomousAgent.TokenUsage totalTokenUsage() {
return totalTokenUsage;
}

/** The task currently being worked on, if any. */
public Optional<TaskInfo> currentTask() {
return currentTask;
}

/** The ids of tasks that are pending (queued but not yet started). */
public List<String> pendingTaskIds() {
return pendingTaskIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import java.util.concurrent.CompletionStage

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.jdk.CollectionConverters._
import scala.jdk.FutureConverters._
import scala.jdk.OptionConverters._

import akka.Done
import akka.NotUsed
Expand Down Expand Up @@ -112,7 +114,9 @@ private[javasdk] final class AutonomousAgentClientImpl(
spiState.phase,
spiState.paused,
spiState.goal,
new AutonomousAgent.TokenUsage(spiState.totalInputTokens, spiState.totalOutputTokens))
new AutonomousAgent.TokenUsage(spiState.totalInputTokens, spiState.totalOutputTokens),
spiState.currentTask.map(t => new AgentState.TaskInfo(t.taskId, t.taskName)).toJava,
spiState.pendingTaskIds.asJava)
}
.asJava
}
Expand Down
51 changes: 43 additions & 8 deletions docs/src/modules/sdk/pages/autonomous-agents.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

The developer configures a *definition* — instructions, tools, coordination capabilities, and execution constraints — and the LLM drives the execution. The agent iterates: call the LLM, execute tools, check task status, repeat — until all tasks are complete or the iteration limit is reached. The execution is durable, surviving restarts and failures.

A key strength of the Autonomous Agent is its coordination capabilities. Multiple agents can work together — delegating subtasks to specialist workers, handing off work to peers, or collaborating as teams with shared task lists and messaging. These coordination patterns are built into the component model: the developer declares which patterns an agent participates in, and the framework provides the corresponding tools to the LLM automatically. This means multi-agent systems can be assembled from focused, single-purpose agents without writing orchestration code.

Check failure on line 15 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 15, "column": 121}}}, "severity": "ERROR"}

## <a href="about:blank#_when_to_use"></a> When to use an autonomous agent

Expand Down Expand Up @@ -389,6 +389,45 @@
.stop();
```

### Pause and resume

A running agent can be paused and later resumed. While paused, the agent stops iterating — it will not start new LLM calls or process queued tasks. Tasks already assigned remain in the queue and are processed when the agent resumes.

```java
// Pause the agent
componentClient
.forAutonomousAgent(ReportAgent.class, agentInstanceId)
.pause();

// Resume the agent
componentClient
.forAutonomousAgent(ReportAgent.class, agentInstanceId)
.resume();
```

Async variants `pauseAsync()` and `resumeAsync()` return `CompletionStage<Done>`.

### Agent state

Query the current state of an agent instance with `getState()`. The returned `AgentState` provides a snapshot of the agent's execution status.

```java
var state = componentClient
.forAutonomousAgent(ReportAgent.class, agentInstanceId)
.getState();

state.phase(); // execution phase, e.g. "PHASE_RUNNING", "PHASE_STOPPED"
state.paused(); // whether the agent is paused
state.goal(); // the agent's current goal
state.totalTokenUsage(); // cumulative token usage (inputTokens, outputTokens)
state.currentTask(); // Optional<TaskInfo> — the task currently being worked on
state.pendingTaskIds(); // List<String> — IDs of tasks queued but not yet started
```

The `currentTask()` returns an `Optional<AgentState.TaskInfo>` containing the `taskId` and `taskName` of the task the agent is actively processing. When the agent is idle or between tasks, it is empty.

The async variant `getStateAsync()` returns `CompletionStage<AgentState>`.

### Querying task results

Task results are typed based on the task definition's `resultConformsTo` type.
Expand All @@ -407,14 +446,10 @@
Subscribe to lifecycle notifications for an agent instance to observe its execution progress in real time. Notifications are published by the runtime — not by user code — as the agent moves through its execution loop.

```java
import akka.javasdk.agent.autonomous.Notification;

var agentClient = componentClient
.forAutonomousAgent(QuestionAnswerer.class, agentInstanceId);

var notifications = new ArrayList<Notification>();
agentClient.notificationStream()
.runForeach(notifications::add, materializer);
componentClient
.forAutonomousAgent(QuestionAnswerer.class, agentInstanceId)
.notificationStream()
.runForeach(System.out::println, materializer);
```

The notification stream emits the following event types:
Expand All @@ -437,7 +472,7 @@

LLMs perform best with focused context. As tasks grow more complex, a single agent's context becomes diluted — too much information, too many concerns, competing objectives. Multi-agent patterns address this by scoping context so that each agent can operate with clarity.

The coordination pattern shapes system behaviour — not just efficiency, but coherence, predictability, error propagation, and the kinds of solutions a system can discover. Parallelism provides a second motivation — when work can be decomposed into independent subtasks, multiple agents can run simultaneously for direct speedup or greater thoroughness. Multi-agent patterns also enable model specialisation — using a smaller, faster model for triage, a stronger model for complex reasoning, or a model fine-tuned for a specific domain. Each agent can use the model best suited for its responsibilities.

Check failure on line 475 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 475, "column": 261}}}, "severity": "ERROR"}

Four patterns cover the design space. Each has a distinct model for how context is scoped and flows between agents, a corresponding single-agent approach, and an analogy to established concurrency models. In practice, these patterns are conceptual tools for understanding the design space — real systems often blend them.

Expand All @@ -455,15 +490,15 @@

*Context flow:* Forward. Each agent receives context from the previous stage (accumulated, summarised, or transformed), adds its contribution, and passes it on.

*Behaviour:* The simplest multi-agent pattern, and the most coherent, with a single thread of reasoning throughout. But this creates path dependency: early decisions constrain later ones, and errors compound rather than correct. The sequence order matters — research-then-plan produces different results than plan-then-research. Real workflows are often graphs rather than linear chains, which is where sequential composes with delegative.

Check failure on line 493 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'delegative'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'delegative'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 493, "column": 429}}}, "severity": "ERROR"}

*When to use:* Workflow processes with clear stages and specialisation at each stage. Better for refinement, where each stage improves on the last, than exploration. The linear sequence is easy to trace and interpret.

*Example:* A triage agent receives a customer request, determines the category, and hands off control to the appropriate specialist agent. The specialist now owns the interaction.

### Delegative (fan-out / fan-in)

Check failure on line 499 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'Delegative'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'Delegative'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 499, "column": 5}}}, "severity": "ERROR"}

A coordinator assigns subtasks to workers. Workers operate in isolated contexts. Results flow back for synthesis.

Check failure on line 501 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 501, "column": 23}}}, "severity": "ERROR"}

*Group:* Hierarchy — coordinator and workers.

Expand All @@ -471,13 +506,13 @@

*Concurrency model analogy:* Fork/join, futures — the coordinator fans out work and collects results.

*Parallelism:* High — subtasks can run simultaneously.

Check failure on line 509 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 509, "column": 23}}}, "severity": "ERROR"}

*Context flow:* Partitioned. Each worker sees only its slice. Workers are deliberately isolated from each other. The coordinator sees the original task and the results that come back, but not the internal reasoning of each worker.

*Behaviour:* Context isolation is the defining feature. Each worker gets a focused context and can go deep on its subproblem without distraction or influence from the others. But isolation also means no cross-pollination. The responsibility for coherence falls entirely on the coordinator — it needs to perform well at both decomposition and synthesis. A variant is competitive delegation, where the coordinator assigns the same task to multiple workers and the best result is selected. At large scale, with many agents and statistical selection, this blurs into the emergent pattern.

*When to use:* Tasks that decompose into distinct subtasks benefiting from isolated, focused contexts, or when independent perspectives are needed. Good for parallel execution to reduce latency, or broad exploration with many workers generating independent attempts.

Check failure on line 515 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 515, "column": 51}}}, "severity": "ERROR"}

*Example:* A research coordinator delegates fact-gathering to a researcher and trend analysis to an analyst. Both work in parallel with isolated contexts. The coordinator synthesises their findings into a brief.

Expand All @@ -497,13 +532,13 @@

*Behaviour:* The strength of this pattern is mutual awareness — agents can build on, question, and correct each other. Debate can surface better answers than any single agent would find. But shared context also enables groupthink: agents can converge on ideas too early, reinforce each other's biases, or defer to whichever agent communicates first or most confidently. The more interdependent the collaboration, the more it resembles a single agent rather than multiple agents working in parallel.

*When to use:* Interdependent subtasks where agents need to see each other's work, or when quality benefits from debate or review between peers. Good for error-catching through challenge, or when different expertise needs to be actively integrated — not just combined afterward.

Check failure on line 535 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'subtasks'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'subtasks'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 535, "column": 31}}}, "severity": "ERROR"}

*Example:* A team lead decomposes a project into tasks. Developer agents claim tasks from a shared list, work on them independently, and message peers when coordination is needed. The lead monitors progress and disbands the team when done.

### Emergent (swarm)

Many agents operate in parallel with minimal individual context, following simple rules. Complex behaviour arises through stigmergy — modifying a shared environment that influences other agents.

Check failure on line 541 in docs/src/modules/sdk/pages/autonomous-agents.html.md

View workflow job for this annotation

GitHub Actions / Vale style checking

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'stigmergy'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'stigmergy'?", "location": {"path": "docs/src/modules/sdk/pages/autonomous-agents.html.md", "range": {"start": {"line": 541, "column": 123}}}, "severity": "ERROR"}

*Group:* Swarm — independent action, collective effect.

Expand Down
2 changes: 1 addition & 1 deletion project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ object Dependencies {
val ProtocolVersionMajor = 1
val ProtocolVersionMinor = 1
}
val AkkaRuntimeVersion = sys.props.getOrElse("akka-runtime.version", "1.5.46-81-7b5cc192-SNAPSHOT")
val AkkaRuntimeVersion = sys.props.getOrElse("akka-runtime.version", "1.6.0-M1")
// NOTE: embedded SDK should have the AkkaVersion aligned, when updating RuntimeVersion, make sure to check
// if AkkaVersion and AkkaHttpVersion are aligned
// for prod code, they are marked as Provided, but testkit still requires the alignment
Expand Down
2 changes: 1 addition & 1 deletion samples/autonomous-agent-playground/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.akka</groupId>
<artifactId>akka-javasdk-parent</artifactId>
<version>3.5.16-74-e2fd6353-dev-SNAPSHOT</version>
<version>3.6.0-M1</version>
</parent>

<groupId>demo</groupId>
Expand Down
Loading