Engineering research / adk java

ADK Java 1.12.0: Experimental Workflow Graphs Where Every Agent Is a Node, a Gemini Context Cache Manager, Injectable Clocks and Schedulers, and Two Ordering Fixes

ADK Java 1.12.0 (14 October 2026), read from its commits: experimental Workflow, Node and Edge types with every agent now a node, a context cache manager that finally creates Gemini caches, injectable schedulers, a switch against config-supplied stdio MCP servers, and two ordering fixes.

By Sandeep Belgavi · Published 2026-10-25 · Prepared 2026-10-19

Recent development · Practical technical guide · 19 October 2026

ADK Java 1.12.0 (14 October 2026), read from its commits: experimental Workflow, Node and Edge types with every agent now a node, a context cache manager that finally creates Gemini caches, injectable schedulers, a switch against config-supplied stdio MCP servers, and two ordering fixes.

What shipped and when

ADK Java 1.12.0 was published on 14 October 2026, twelve days after 1.11.0. The release notes list fifteen features and nine fixes. Three groups matter for someone running agents on the framework: a set of experimental workflow graph types that the whole agent hierarchy now plugs into, a working implementation of Gemini context caching, and a handful of injection points and fixes that affect testability and ordering. A builder for workflow edges landed on the main branch on 16 October, after the release, and is covered here because it shows where the graph API is going. Everything below was checked against the commits rather than the summary lines.

Workflow graphs: every agent is now a node

The largest change is structural. A new package, com.google.adk.workflow, defines a Node interface with a name, a description, and experimental members: whether a resumed node reruns from scratch (rerunOnResume), whether it stays re-triggerable until it produces an output or a route (waitForOutput), a NodeConfig with a retry policy and execution timeout, and optional input, output and state schemas. BaseNode is the framework's abstract implementation; subclasses implement runNode and the framework turns each emission into an Event. The commit that makes this matter is short: BaseAgent now extends BaseNode, so every LlmAgent, SequentialAgent and ParallelAgent is a workflow node, running through its usual runAsync lifecycle including callbacks when used as one.

Around Node sit the graph types. Edge is a record of a source node, a target node and a list of routes; an edge with no routes is unconditional. Start is a singleton node with the reserved name __START__ that every graph begins at. JoinNode requires all of its predecessors and passes its input through unchanged. Workflow itself extends BaseNode, holds the edges, an optional maxConcurrency of at least one, and builds a Graph from the edges; unlike other nodes it reruns from scratch when resumed unless told otherwise. The Event type gained output and nodeInfo fields, and EventActions gained route, an optional list of routes where an empty list is a routing decision that selects nothing and an absent value means no decision was made. Every one of these types is annotated Experimental, and Workflow.runNode currently fails with the message that running a workflow is not supported yet. In other words, 1.12.0 ships the data model and the invariants; the runner is still to come.

The edges builder that arrived two days later

The commit of 16 October adds EdgesBuilder, a fluent way to declare the edges that Workflow.Builder.edges accepts. Chains start at a node or at Start, continue with then or chain, fan out by passing several targets to then, join a group with joinTo on a JoinNode, and end with a routing map that maps route names to targets with an otherwise fallback. The javadoc example reads as a triage workflow: classify, then categorise, then route billing to a billing node and everything else to a summariser. Nodes are identified by instance, so each must be created once. The builder does not change what a Workflow can do today; it fixes the authoring shape before the runner exists, which is a reasonable order for an API marked experimental.

From the commit of 2026-10-16 on the main branch, after the 1.12.0 release. Not compiled here.

// Shape from the EdgesBuilder javadoc; Workflow execution is not yet supported in 1.12.0.
Workflow support = Workflow.builder()
    .name("support_triage")
    .edges(g -> {
        g.fromStart().chain(classify, category).route(r -> {
            r.on("billing").then(billing);
            r.otherwise(summarize);
        });
        g.from(billing).then(summarize);
    })
    .build();

Context caching that actually caches

ADK Java has had a ContextCacheConfig since 1.11, but issue 1530 reported that setting it did nothing. Commit 68914c5 fixes that: when a request carries a cache config, Gemini.generateContent now routes it through a new GeminiContextCacheManager. The manager computes a fingerprint over the system instruction, the tools and the leading contents, where the cacheable prefix is everything before the last run of user contents. It reuses the existing cache while it is valid, and otherwise deletes it and creates a new one once the prefix has been seen to be stable across requests. It honours the model minimums, 2,048 tokens for Gemini 2.5 and 4,096 for Gemini 3, estimating tokens from characters when a count is not available, and it records cache metadata on the request, response and event.

The config record is also stricter. cacheIntervals, the number of invocations that reuse a cache before it is refreshed, must be from 1 to 100 and defaults to 10; ttl must be a whole number of seconds and defaults to 30 minutes; minTokens, the prompt token count below which no cache is created, must not be negative; and a new createHttpOptions sets the HTTP options of the cache-creation call, with the rule that a failed creation sends the request uncached rather than failing it. The old maxInvocations accessor is deprecated in favour of cacheIntervals, the name ADK Python uses. The release includes a context caching sample whose agent pads its instruction past the minimum and uses a one-minute TTL, the shortest Vertex AI accepts according to the sample's comment, so that the demo can show a cache expiring and being recreated.

Config shape from the 1.12.0 sources. Values are examples; the Gemini 3 minimum is 4,096 tokens.

App app = App.builder()
    .name("support_app")
    .rootAgent(agent)
    .contextCacheConfig(new ContextCacheConfig(
        /* cacheIntervals= */ 10, Duration.ofMinutes(30), /* minTokens= */ 4096))
    .build();

Injection points: scheduler, time and ids

Two features exist for people who test or host agents rather than write them. An injectable scheduler replaces the hard-coded RxJava IO scheduler wherever ADK leaves the caller's thread: ParallelAgent sub-agents, parallel tool execution, and the live send loop. It is set on the RunConfig and read from the InvocationContext, with a per-agent scheduler on ParallelAgent taking precedence; the default remains Schedulers.io. The commit message names the motivation: an embedding application could not cap the fan-out, run it on an existing worker pool, or keep every task on a dispatcher it controls, which a durable-execution host must. The companion feature adds injectable time and UUID providers for timestamps and ids, so that tests can produce deterministic events. The durable execution guide explains why a host needs exactly these two controls.

A switch for config-supplied MCP servers

McpToolset.fromConfig accepts stdio server parameters from an agent config, and those parameters are a command and arguments that the stdio transport launches as a local process while tools are resolved on the first turn, before any model is contacted. Agent configs are shared as bundles, templates and registry entries, so a config can start a process its operator never reviewed. 1.12.0 adds a switch: the system property adk.mcp.allowConfigStdioServers set to false, or McpToolset.setAllowConfigStdioServers(false) at startup, makes loading such a config fail with a ConfigurationException that explains why. The default is unchanged, allow, so existing deployments keep working; remote SSE transports are unaffected. Applications that load configs they did not write should flip it.

Two ordering fixes worth reading

FixWhat went wrongWhat changed
Transfer target ran before the transfer event was persistedThe target agent could build its request from a session that did not yet contain the transfer eventfollowTransfer now awaits a persist barrier for the event and only then subscribes the target, deferred so it runs on the append thread
Approved tool confirmations under a ParallelAgentA function response that answers a call made on a parallel branch ran under the wrong branch, so the confirmation was not appliedThe runner restores the branch of the call being answered, and for other routing the agent’s latest branch, matching ADK Python
Unconvertible remote A2A partA single part the converter did not understand failed the whole turnThe part is skipped with the rest delivered
MCP tool input schemas in chat completionsSchemas were not sent to chat-completions style backendsThey are sent
Vertex AI session reloadsEvent fields were lost on reloadFields are preserved

The first two are the kind of bug that only shows under load or in multi-agent trees, and both commits add tests that reproduce the race. If you run transfers between agents or confirmations inside a ParallelAgent, 1.12.0 is worth taking for these alone.

Practical implications and verification

  • Do not build on Workflow yet. The types are experimental and execution is explicitly unsupported in this release; design against them, do not ship.
  • Re-test caching costs. If you set ContextCacheConfig before, caching was not happening; after upgrading, caches will be created and billed. Set minTokens above the model minimum and watch the cache metadata on events.
  • Pin the scheduler in hosted runtimes. Set RunConfig.scheduler to the pool you control if you host ADK inside a workflow engine or a bounded executor.
  • Flip the MCP switch in any service that loads third-party agent configs.
  • Verify with the sources. Upgrade the google-adk artifact to 1.12.0, run your transfer and parallel confirmation tests, and read the release notes linked below before relying on any line of this summary.

Sources and scope

Checked against these sources on 19 October 2026. Event: google/adk-java v1.12.0 release, 14 October 2026; recheck it before acting. Examples and figures are illustrative, not measurements.

Treat the workflow graph types as experimental data model only, re-test caching costs now that caches are created, pin the scheduler in hosted runtimes, and reject config-supplied stdio MCP servers.