Skip to content

Latest commit

 

History

History
455 lines (328 loc) · 20.7 KB

File metadata and controls

455 lines (328 loc) · 20.7 KB

AgentClient control-plane reference

AgentClient (io.orkes.conductor.client.AgentClient, in the conductor-client module) is the Java SDK's interface to the agent control-plane (/api/agent/*). Standard Conductor endpoints (/api/workflow/*, /api/tasks, etc.) remain on the SDK's typed clients (WorkflowClient, TaskClient, MetadataClient). Obtain an agent client with new OrkesClients(conductorClient).getAgentClient() or construct OrkesAgentClient directly.

Every request goes through the shared ConductorClient's native HTTP + auth + serialization layer. No hand-rolled HTTP. ConductorClientException is mapped to the typed AgentAPIException / AgentNotFoundException (io.orkes.conductor.client.exceptions).

Methods

Method HTTP Java input type Java return type Description
compileAgent POST /api/agent/compile AgentRequest CompileResponse Compile to Conductor workflow def — no side effects
deployAgent POST /api/agent/deploy AgentRequest StartResponse Register workflow def without starting
startAgent POST /api/agent/start AgentRequest StartResponse Compile + register + start execution
getAgentStatus GET /api/agent/{id}/status path: executionId AgentStatusResponse Poll execution status; includes HITL pending-tool
getExecution GET /api/agent/execution/{id} path: executionId Map<String,Object> Fetch the full execution tree
listExecutions GET /api/agent/executions query parameter map Map<String,Object> Search agent executions
respond POST /api/agent/{id}/respond RespondBody void Resume a paused HITL task
cancelAgent DELETE /api/agent/{id}/cancel path: executionId; optional reason query void Immediately cancel/terminate an execution
stopAgent POST /api/agent/{id}/stop path: executionId void Gracefully stop after the current iteration
signalAgent POST /api/agent/{id}/signal path: executionId; message body void Inject persistent context
streamSse GET /api/agent/stream/{id} path: executionId; optional last event ID SseClient Open the resumable SSE event stream

AgentRequest

Input to compileAgent, deployAgent, and startAgent (io.orkes.conductor.client.model.agent.AgentRequest). A pure transport DTO: the agent definition arrives pre-serialized as a JSON-ready map — domain serialization is owned by conductor-client-ai (AgentRuntime.agentRequest(agent) calls AgentConfigSerializer.serialize(agent) and resolves the Framework discriminator before building the request).

// Already-deployed agent — version is optional
AgentRequest.deployedAgent("researcher", 3)
    .prompt("Summarize the release risks")
    .build()

// Native agent — AgentRuntime passes the serialized agent map
AgentRequest.nativeAgent(serializedAgent).build()

// Framework-backed agent — framework wire name + serialized raw config
AgentRequest.frameworkAgent("openai", serializedAgent).build()
AgentRequest.frameworkAgent("langchain", serializedAgent).build()

// Framework skill reference instead of rawConfig
AgentRequest.frameworkAgent("skill", null)
    .model("anthropic/claude-sonnet-4-6")
    .skillRef(Map.of("name", "code-review", "version", 2))
    .build()

// With execution fields (for /start only)
AgentRequest.nativeAgent(serializedAgent)
    .prompt("What is the capital of France?")
    .sessionId("session-abc")
    .runId("a1b2c3...")           // per-execution domain UUID for stateful agents
    .staticPlan(plan.toJson())    // pre-serialized map, written as "static_plan"
    .idempotencyKey("question-123")
    .build()

Wire output (mutually exclusive shapes, fixed at build time):

Factory JSON emitted
deployedAgent(name, version) "name": name, "version": version (version omitted when null)
nativeAgent(config) "agentConfig": config
frameworkAgent(framework, config) "framework": framework, "rawConfig": config
frameworkAgent(framework, null).skillRef(ref) "framework": framework, "skillRef": ref

Field mapping to server StartRequest:

AgentRequest field Java type JSON key Server StartRequest field Used by
name String "name" name deployed agents
version Integer "version" version deployed agents (optional)
agentConfig Object (map) "agentConfig" (native path) agentConfig native agents
framework String "framework" (framework path) framework framework agents
rawConfig Object (map) "rawConfig" (framework path) rawConfig framework agents
model String "model" model optional model override
skillRef Map<String,Object> "skillRef" skillRef framework skill agents
prompt String "prompt" prompt start only
sessionId String "sessionId" sessionId start (stateful)
runId String "runId" runId start (stateful isolation)
staticPlan Object (map) "static_plan" (AgentRuntime calls plan.toJson()) staticPlan (@JsonProperty("static_plan")) start (PLAN_EXECUTE)
media List<String> "media" media start (multi-modal)
context Map<String,Object> "context" context start
idempotencyKey String "idempotencyKey" idempotencyKey start
credentials List<String> "credentials" credentials compile / start
timeoutSeconds Integer "timeoutSeconds" timeoutSeconds compile / start

Null fields are never written — the class is annotated @JsonInclude(NON_NULL). The three request forms are mutually exclusive: use deployed name/version, inline native agentConfig, or framework framework plus rawConfig/skillRef.

Framework wire values:

Enum constant Wire value
Framework.OPENAI "openai"
Framework.GOOGLE_ADK "google_adk"
Framework.LANGCHAIN "langchain"
Framework.LANGGRAPH "langgraph"
Framework.SKILL "skill"
Framework.VERCEL_AI "vercel_ai"
Framework.CLAUDE_AGENT_SDK "claude_agent_sdk"

AgentRuntime resolves agent.getFramework()Framework via Framework.of(String) (returns Optional.empty() for unrecognised strings, routing them through the native path).

staticPlan is serialized as "static_plan".


RespondBody

Input to respond. Provides factory methods for the three common patterns; arbitrary extra fields are flattened to the top level via @JsonAnyGetter.

RespondBody.approve()                  // { "approved": true }
RespondBody.approve("Looks good")      // { "approved": true, "reason": "Looks good" }
RespondBody.reject("Needs review")     // { "approved": false, "reason": "Needs review" }
RespondBody.of(Map.of("selected", "writer"))  // { "selected": "writer" }  ← MANUAL strategy

Used by AgentHandle:

AgentHandle method RespondBody factory Wire JSON
handle.approve() RespondBody.approve() { "approved": true }
handle.approve(comment) RespondBody.approve(comment) { "approved": true, "reason": "..." }
handle.reject(reason) RespondBody.reject(reason) { "approved": false, "reason": "..." }
handle.respond(map) RespondBody.of(map) the map at the top level

compileAgent

Compile an agent into a Conductor workflow definition. No workflow is registered or executed.

Used by AgentRuntime.plan(agent).

HTTP: POST /api/agent/compile

Request body — AgentRequest

// AgentRuntime builds this via agentRequest(agent), serializing the agent first:
AgentRequest.nativeAgent(AGENT_SERIALIZER.serialize(agent)).build()
// or, for framework agents — the resolved framework's wire name:
AgentRequest.frameworkAgent(fw.wireValue(), AGENT_SERIALIZER.serialize(agent)).build()

Native agent wire shape (the map produced by AgentConfigSerializer.serialize(agent)):

{ "agentConfig": { "name": "my_agent", "model": "anthropic/claude-sonnet-4-6", "strategy": "handoff", ... } }

Framework agent wire shape:

{ "framework": "openai", "rawConfig": { "name": "my_agent", "model": "anthropic/claude-sonnet-4-6", "tools": [...] } }

Response — CompileResponse

{ "workflowDef": { "name": "my_agent", "version": 1, "tasks": [...] }, "requiredWorkers": ["my_tool_a"] }
Field Getter Type Description
workflowDef getWorkflowDef() Map<String,Object> Full Conductor workflow definition.
requiredWorkers getRequiredWorkers() List<String> Task type names the SDK must register local workers for.

How the SDK uses it: AgentRuntime.plan(agent) returns the CompileResponse directly.


deployAgent

Compile and register the workflow definition on the server without starting an execution. Idempotent.

Used by AgentRuntime.deploy(Agent...).

HTTP: POST /api/agent/deploy

Request body — AgentRequest

Same as compileAgent — agent definition only, no prompt.

Response — StartResponse

{ "agentName": "my_agent", "requiredWorkers": ["my_tool_a"] }
Field Getter Type Description
agentName getAgentName() String The registered workflow name on the server.
requiredWorkers getRequiredWorkers() List<String> Task type names the SDK must have workers running for.
executionId getExecutionId() String Always null for deploy — no execution was started.

How the SDK uses it: AgentRuntime.deploy() reads resp.getAgentName() and wraps it in DeploymentInfo.


startAgent

Compile, register, and start a workflow execution in one call.

Used by AgentRuntime.startAsync(agent, prompt, plan).

HTTP: POST /api/agent/start

Request body — AgentRequest

Start an already-deployed agent without resending its definition:

StartResponse response = client.startAgent(
    AgentRequest.deployedAgent("researcher", 3)
        .prompt("What changed in the latest release?")
        .build());
{
  "name": "researcher",
  "version": 3,
  "prompt": "What changed in the latest release?"
}

Inline definitions remain supported:

{
  "agentConfig": { ... },
  "prompt": "What is the capital of France?",
  "sessionId": "session-abc",
  "runId": "a1b2c3d4e5f6...",
  "static_plan": { "steps": [...] },
  "idempotencyKey": "question-123"
}

The idempotency key is optional. Callers that retry the same logical start should reuse the same stable value; the client does not generate one.

Response — StartResponse

{ "executionId": "a3f92b1c-8e4d-4b7a-9c2e-1d5f3a8e6b02", "agentName": "my_agent", "requiredWorkers": ["my_tool_a"] }
Field Getter Type Description
executionId getExecutionId() String Conductor workflow ID. @JsonAlias handles legacy keys (workflowId, id, correlationId).
agentName getAgentName() String The registered workflow name.
requiredWorkers getRequiredWorkers() List<String> Task type names the SDK must have workers polling before the agent can progress.

How the SDK uses it: AgentRuntime.startAsync() reads response.getExecutionId() and passes it to new AgentHandle(executionId, agentClient, workflowClient).


getAgentStatus

Poll the current status of a running or completed execution.

Used by AgentHandle.waitForResult() and AgentHandle.waitUntilWaiting().

HTTP: GET /api/agent/{executionId}/status

Response — AgentStatusResponse

{ "executionId": "...", "status": "COMPLETED", "startTime": 1710000000000, "endTime": 1710000005000, "isComplete": true, "isRunning": false, "output": { ... } }

HITL paused:

{ "status": "RUNNING", "isWaiting": true, "pendingTool": { "taskRefName": "...", "tool_name": "...", "parameters": { ... } } }

AgentStatusResponse fields:

JSON field Getter Type Source Description
executionId getExecutionId() String path param
status getStatus() String workflow.getStatus().name() RUNNING, COMPLETED, FAILED, TERMINATED, TIMED_OUT, PAUSED
startTime getStartTime() Long workflow start timestamp Epoch milliseconds; nullable until supplied by the server
endTime getEndTime() Long workflow end timestamp Epoch milliseconds; nullable while execution is active
isComplete isComplete() boolean workflow.getStatus().isTerminal() true for all terminal statuses
isRunning isRunning() boolean status == RUNNING
output getOutput() Map<String,Object> workflow.getOutput() Only present when isComplete() == true
reasonForIncompletion getReasonForIncompletion() String workflow.getReasonForIncompletion() Only present on non-COMPLETED terminal status
isWaiting isWaiting() boolean HUMAN task IN_PROGRESS true when a HITL task is paused
pendingTool getPendingTool() PendingTool HUMAN task inputData Only when isWaiting() == true

PendingTool fields:

JSON field Getter Type Description
taskRefName getTaskRefName() String Conductor task reference name.
tool_name getToolName() String Logical tool name shown to the human.
parameters getParameters() Map<String,Object> Args the agent passed to the tool.
response_schema getResponseSchema() Object JSON Schema the response must conform to (optional).
response_ui_schema getResponseUiSchema() Object UI rendering hints (optional).

respond

Resume a paused HITL execution.

Used by AgentHandle.approve(), .reject(), .respond(Map) and AgentStream.approve(), .reject().

HTTP: POST /api/agent/{executionId}/respond

Request body — RespondBody

{ "approved": true }
{ "approved": false, "reason": "Needs review" }
{ "selected": "writer" }

Response

void — returns nothing. Throws AgentAPIException if no pending HUMAN task exists.


cancelAgent

Immediately cancel an agent execution. This is distinct from graceful stopping: cancellation terminates now and may record an operator reason.

client.cancelAgent(executionId, "Superseded by a newer request");

HTTP: DELETE /api/agent/{executionId}/cancel?reason=Superseded%20by%20a%20newer%20request

The reason query parameter is omitted when the Java argument is null, empty, or blank. HTTP 404 maps to AgentNotFoundException; other HTTP failures map to AgentAPIException through the normal client transport.


stopAgent

Request a graceful deterministic stop after the current agent iteration finishes. Unlike cancellation, this preserves the current iteration and does not take a reason.

client.stopAgent(executionId);

HTTP: POST /api/agent/{executionId}/stop

Use stopAgent when the current iteration should finish cleanly; use cancelAgent when work must terminate immediately.


signalAgent

Inject a durable text message into a running agent's context. This is an agent-control-plane signal, not a response to a pending human approval; use respond for a HUMAN task.

Fragment — obtain client as shown in the control-plane overview.

client.signalAgent(executionId, "Customer supplied order number 12345");

HTTP: POST /api/agent/{executionId}/signal

The body is the message accepted by the agent control plane. The method returns void; AgentNotFoundException represents a missing execution and AgentAPIException represents another server failure. Do not put credentials or sensitive raw customer data in a signal.


streamSse

Open the resumable server-sent event stream for an agent execution. AgentRuntime.stream(...) uses this method; direct users must close the returned SseClient.

Fragment — obtain client as shown in the control-plane overview.

import java.util.Map;

try (SseClient stream = client.streamSse(executionId, null)) {
    Map<String, Object> event;
    while ((event = stream.nextEvent()) != null) {
        System.out.println(event);
    }
}

HTTP: GET /api/agent/stream/{executionId}

Pass the last received event ID as the second argument to resume after a reconnect. The client reconnects mid-stream with Last-Event-ID; if the server rejects streaming altogether it throws SSEUnavailableException. Fall back to getAgentStatus polling in that case. Treat streamed content as potentially sensitive and redact it before logging.


WorkflowClient usage

Raw workflow data (GET /api/workflow/{id}) is fetched via the standard Conductor WorkflowClient — not AgentClient. AgentClient owns only /api/agent/*.

WorkflowClient.getWorkflow(id, true) is called inside AgentHandle.buildResult() once, after getAgentStatus returns terminal, to walk the typed Workflow/Task objects and compute:

  • Token usageLLM_CHAT_COMPLETE task outputData: promptTokens, completionTokens, tokenUsedAgentResult.getTokenUsage()
  • Tool calls — worker tasks whose referenceTaskName starts with call_AgentResult.getToolCalls()

Fires automatically inside run() / waitForResult(). Callers never invoke it directly.


AgentConfig (request field)

The agent definition serialized under the agentConfig key by AgentConfigSerializer.

Field Type Description
name String Agent/workflow name.
model String "provider/model" e.g. "anthropic/claude-sonnet-4-6".
instructions String | Object System prompt or PromptTemplateRef.
tools List<ToolConfig> Tool definitions.
agents List<AgentConfig> Sub-agents (for multi-agent strategies).
strategy String "handoff" (default), "sequential", "parallel", "router", "swarm", "round_robin", "random", "plan_execute", "manual".
router AgentConfig | WorkerRef For "router" strategy.
guardrails List<GuardrailConfig> Input/output guardrails.
maxTurns int Default 100.
maxTokens Integer LLM max_tokens.
temperature Double LLM temperature.
timeoutSeconds int Execution timeout.
credentials List<String> Credential names injected at runtime.
outputType OutputTypeConfig Structured output definition.
termination TerminationConfig Early termination condition.
handoffs List<HandoffConfig> Swarm handoff triggers.
callbacks List<CallbackConfig> Before/after model callbacks.
codeExecution CodeExecutionConfig Local code execution settings.
cliConfig CliConfig CLI command execution settings.
planner AgentConfig PLAN_EXECUTE: agent that produces the plan.
fallback AgentConfig PLAN_EXECUTE: agent used when the plan fails.
plannerContext List<Map> PLAN_EXECUTE: text/URL context appended to the planner's prompt.
synthesize Boolean Append a synthesis step after parallel sub-agents.
includeContents String "none" = fresh context; absent = inherit parent context.
baseUrl String Per-agent LLM provider base URL override.
metadata Map<String,Object> Arbitrary metadata stored with the workflow definition.
framework String Framework ID — set by SDK bridges, not by callers directly.

ToolConfig

Field Type Default Description
name String Tool name shown to the LLM.
description String Tool description.
inputSchema Map<String,Object> JSON Schema for tool parameters.
outputSchema Map<String,Object> JSON Schema for tool return value.
toolType String "worker" "worker", "http", "mcp", "human", "generate_image", "generate_audio", "generate_pdf", "rag_search", "pull_workflow_messages".
approvalRequired boolean false Pause for human approval before executing.
timeoutSeconds Integer Per-tool execution timeout.
maxCalls Integer Maximum invocations per run.
config Map<String,Object> Type-specific config: url/method/headers for HTTP; server_url for MCP.
guardrails List<GuardrailConfig> Tool-level guardrails.
stateful boolean false Register worker under a per-execution domain (prevents cross-instance task stealing).