Transition the AX architecture from asynchronous event queues (Redis Streams
and the `ax-controller` worker pool) to direct, synchronous reconciliation in
`ax-server` guarded by fine-grained distributed locks.
Key changes:
- Implement per-resource locking (`lock:task`, `lock:workspace`, `lock:model`)
using Redis distributed locks (`SET NX PX` with token validation) and an
in-memory locker for testing.
- Move Substrate reconciliation directly into `ax-server` for Task, Workspace,
and Model lifecycle methods (`Create`, `Resume`, `Suspend`, `Delete`).
- Decommission `ax-controller`, `deploy/ax-controller.yaml`, and Redis Stream
event publishing/consuming interfaces.
- Simplify `ax delete` and `ax watch` in the CLI to eliminate two-phase
polling loops now that operations complete synchronously.
- Update `demo.sh`, build configurations (`Makefile`, `.ko.yaml`), and
documentation to reflect the single-binary control plane architecture.
Remove the Gateway resource across the API, controller, server, CLI,
store, and documentation.
Gateway introduced an unnecessary layer and architectural bifurcation
between Agent Substrate and AX. By removing it, AX aligns directly with
Substrate's native primitives and networking rather than maintaining an
overlapping ingress/routing abstraction.
- Reserved protobuf field 8 and removed Gateway RPCs and messages.
- Cleaned up controller reconciler, server endpoints, and store models.
- Updated CLI, documentation, and example manifests.
AX is undergoing a significant redesign, moving away from a single CLI with
an embedded Python harness toward a general-purpose orchestration layer for
agentic tasks. The repository is reorganized around three binaries: ax-server
exposes a gRPC API for submitting Task manifests, ax-controller runs as a
horizontally scaled reconciler that consumes work from Redis Streams, and
ax-task-runner executes tasks inside sandboxed workers. Task state now lives
in Redis rather than Kubernetes CRDs so the system can handle millions of
short-lived tasks without straining etcd. The legacy Python harness, ATE
client, SQL event log, and skill examples are removed, and new design,
concepts, manifest, networking, runner, and sandbox docs plus Kubernetes
deploy manifests describe the new architecture.
The docker_agent example largely duplicates remote_agent (both
implement AX's native AgentService directly via gRPC). Removing it
in favor of the simpler remote_agent example.
Fixes#132
We don't allow sub agents to use the controller to make agent handoffs anymore.
Split AgentMessage into AgentRequest and AgentResponse proto definitions.
## Summary
- Move text streaming logic in `DockerAgent` `Connect` method outside of
the `keepLooping` check.
- This ensures that intermediate text outputs (reasoning, thoughts, or
status updates) emitted by the model during tool calls (like
`activate_skill`) are correctly streamed back to the client instead of
being ignored.
So we don't accidentally promote this option. There are also rough edges
in this implementation that we don't have time to fix, e.g. the use of
kubectl.
## Summary
Add a self-contained Python sample agent
(`examples/a2a_agent/coding_agent.py`) that serves as the end-to-end
reference for AX's A2A bridge. Built on Google ADK's LlmAgent (Gemini),
exposes the agent over A2A on three transports (gRPC, JSON-RPC,
HTTP+JSON REST), and exercises HITL, streaming/polling, multi-scheme
auth, and FilePart artifacts.
## Features exercised
- HITL save-confirmation via `TASK_STATE_INPUT_REQUIRED`, mapped to
ADK's `LongRunningFunctionTool` semantics — the agent proposes a path
and waits for the user's "yes" before writing.
- Returns the saved Python source as a `text/x-python` FilePart
attachment alongside the agent's text reply; on decline, emits the
proposed code as a fenced markdown block instead.
- Optional dual-scheme auth (`--auth`): AgentCard advertises Bearer and
API key as alternatives (OR semantics); symmetric enforcement via HTTP
middleware + gRPC interceptor.
- Streaming and polling-fallback paths (`--no-streaming` disables
streaming in the AgentCard so clients exercise the polling fallback).
- Inline script metadata (`# /// script`) — runnable via `uv run`
without a separate venv.
## Run
```bash
# Gemini API key: export GOOGLE_API_KEY=...
# or Vertex AI: export GOOGLE_GENAI_USE_VERTEXAI=TRUE
# export GOOGLE_CLOUD_PROJECT=<project>
# export GOOGLE_CLOUD_LOCATION=<region>
uv run examples/a2a_agent/coding_agent.py
uv run examples/a2a_agent/coding_agent.py --no-streaming # polling fallback
uv run examples/a2a_agent/coding_agent.py --auth # enable dual-scheme auth (set CODING_AGENT_AUTH_TOKEN)
This PR introduces a standalone `DockerAgent` example and fixes an
infinite loop bug in the planner. It also addresses several code review
comments for robustness and cleanups.
- ConversationId is added in the reply agent message of the remote agent
example. Without conversation id the message gets rejected. (The ate
agent and k8s sandbox agent have it added in the previous PR).
This PR adds a new conversation_id field in AgentMessage.
Also add the conversationID to the signature of Agent.Connect and
Executor.Exec so that we can:
1. propagate conversationID from controller to sub-agent, like remote
agent, a2a agent
2. propagate conversationID to substrate worker
The conversationID is unused by anything yet. It will be picked up by
a2a agents in follow up PRs, and possibly substrate agent as well.
AX won't be doing any healthchecks itself. agent.HealthCheck is obsolete
now. We keep the AgentService.HealthCheck RPC to ensure agent
implementators provide a health check mechanism on wire for job
schedulers.
This PR adds Colab agents into AX. The main use case covered:
1. From a local python script, run it with Colab VM, optionally download
output images, and convert it to a notebook and save in Google Drive.
2. From a remote notebook in Google Drive, run it with Colab VM, get the
output in AX and optionally download output images.
Note: This is only available in gLinux for internal Google version of
Colab CLI. Expect the OSS version coming soon. Instructions at
docs/colab-agent.md.
The changes introduce a conversation log to delegate the history storage
and retrieval to AX. Instead of treating every task/execution as a new
isolated event, AX now supports conversational history.
Conversational history is implemented as a layer above the execution
log. Executions are still logged separately and with much more rich
context that enables resumption within the lifetime of an execution.
With this change, controller natively can identify an execution that is
waiting for resumption from the conversation log. Clients don't need to
know about the underlying execution identifier.
The change also removed the WIP forking capability until we stabilize
the event log schema and the concepts. We will implement it as a follow
up change.
`ExecRequest` is updated to support conversation identifier and
`last_seen_seq`. Sequence numbers will be used to be able to resume
playing from a moment client has since the last. If client connection
disappears, we will still be able to communicate the outputs during a
reconnect.
Some follow-up changes after this change is merged:
- Support for `last_seen_seq`, `seq` number in the ExecResponse.
- Implementation of forking.
- Potential schema changes to conversation_log and execution_log.
- More README updates.
- Rewrite of the trace viewer tool with the new schema once the logs are
more stable.
- Controller will introduce its own OutputHandler to emit additional
fields, e.g. `seq`.
- Remove redundancy between conversation_log and execution_log.
Interactions Content doesn't include a "role" and we introduced this
field in our own copy. Remove "role" from Content in preparation to
switch to the actual Contual message.
This change introduces AgentService.Connect RPC and replaces Process.
- Connect allows bidirectionally executing agents.
- Connect needs to be started with AgentStart and need to be followed
with AgentOutputs.
- Thought the repo, task is renamed to execution.
- SQLite schema is updated accordingly.
- agent.Task is removed because AgentStart represents the required
fields to start a new agent call.
- Instructions on README should just work.
- Remote agent connections should be established at every Process. The
connection is only active during the lifetime of an execution and need
to be closed once Process completes.
- Fix the history curation in the planner agent
- Ensure we only uppercase the last message and ignore the history.