Replies: 2 comments 3 replies
-
|
Thanks for the proposal. I understand the motivation for providing a unified invocation API for internal and external agents. However, I think the current From the user's perspective, an external agent is a black-box invocation target, so This is not only an internal implementation difference. To understand the behavior of Therefore, the proposal unifies the invocation shape, but does not fully unify the user-facing semantics. From this perspective, the shared abstraction seems closer to a
Under this model, the authoring experience remains different where it should be. For an external agent, its integration can provide a custom This would preserve a unified API for callers without exposing |
Beta Was this translation helpful? Give feedback.
-
|
The SubagentInvoker / CallProtocol split above also gives durable execution a place to define a critical external-agent contract. Caching a completed Result handles replay after the local completion record exists. It does not cover the crash window where an external agent accepted or completed a side effect, but Flink failed before checkpointing the result. Re-running the HTTP callable can duplicate work. I would require each invocation protocol to define:
Internal agents can implement that protocol through scoped events; external integrations can map it to HTTP, A2A, or another transport. The caller still receives one SubagentInvoker API, but durability claims remain honest per protocol. If an integration cannot reconcile an unknown outcome, fail closed and surface it instead of automatically repeating the call. We use the same distinction in Better Agent when recovering native Claude, Codex, and Gemini runs: durable run identity and reconciliation are separate from the provider transport. I maintain the project; it is source-available and free for non-commercial use, while commercial use requires separate permission: https://github.com/ofekron/better-agent AI-assistance disclosure: this comment was drafted by Codex under the maintainer’s authorization and reviewed in Better Agent. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
[Feature] Sub-agent Resource for Flink Agents
Motivation
As discussed in #660, there are scenarios where a Flink Agent needs to call external agents — for example, delegating a subtask to a remote LLM agent service or a third-party agent platform. Currently, users can only do this by manually writing remote calls inside actions, which means they miss out on durable execution, checkpoint recovery, and tool call integration.
Beyond external agent calls, several related scenarios have emerged:
These scenarios also create demand for internal sub-agents — the ability to register a Flink Agents
Agentas a sub-agent of anotherAgent, with proper context isolation and execution semantics.This proposal introduces
AGENTas a first-class resource type in Flink Agents, supporting both internal and external sub-agents with a unified API.Goals
AGENTresource type: Sub-agents can be registered viaaddResource(name, AGENT, ...)and accessed viactx.getResource(name, AGENT), usable by both Actions and ChatModel.The proposed changes have been initially validated with a POC (mainly on java api). The overall design still has room for discussion — feedback and suggestions are welcome.
Proposed Interface
1. Resource Type
2. Subagent Interface
Subagentis the common interface for all sub-agents. Both external (SubagentSetup) and internal sub-agents implement it.SubagentSetupis the abstract base for external sub-agents, implementingSubagent:3. Registration
Internal and external sub-agents are registered identically, only via
addResource, not via annotation:4. Calling
5. Implementing External Sub-agent
Execution Process
1. Compilation
Both internal and external sub-agents compile to
SerializableResourceProviderin the plan JSON, ensuring cross-language interoperability:Both paths produce
SerializableResourceProvider, resulting in a uniform plan JSON representation with no runtime difference.Additionally, the compiler registers built-in sub-agents: if
CHAT_MODELis available,ReActAgentis automatically registered as"general-purpose". This registration runs after all user-declared resources are extracted, ensuring decorator-declaredCHAT_MODELis ready.2. Execution Model
The default
call()implementation executes theDurableCallablereturned byasAsyncCallableviadurableExecuteAsync, leveraging the durable execution mechanism for state recording and recovery.Parallel calls: users manually split — call
asAsyncCallablefor each sub-agent, then pass allDurableCallables todurableExecuteAllAsync(to be introduced in an upcoming discussion).call()returnsResult; sub-agent implementations should intercept internal exceptions and populate Result, without directly exposing them to the caller.tool_call_actionconstructs success/errorToolResponseEventbased on Result, without try/catch.3. ChatModel Integration
Sub-agents are exposed to the LLM as tools (Subagent as Tool pattern).
tool_call_actionchecks resource type — TOOL resources go totool.call(), AGENT resources go tosubagent.call(ctx, prompt).ToolResponseEvent.LLM APIs (OpenAI, Ollama, etc.) only have tool/function call concepts — there is no "agent call". Sub-agents are exposed as tools with a single
promptparameter. Thetool_call_actionalready holdsctxas an action parameter, which is passed directly tosubagent.call(ctx, prompt).Internal Sub-agent Design Preview
Internal sub-agent compilation — registering
Agentinstances as sub-agents — will be discussed in a future proposal. The resource model and calling API are already designed to accommodate it.1. Compilation
The sub-agent's
Agentis compiled into an independentAgentPlan(childPlan), wrapped asInternalSubagentSetup(childPlan, scope). The child plan inherits the parent plan'sAgentConfiguration. Circular references are detected at compile time.scopeis the sub-agent's resource name, used for event routing.2. Invocation
Calling a sub-agent emits a
SubagentCallEvent. During async execution, the coroutine yields, and the AEO processes the event in a subsequent mailbox cycle, scheduling the sub-agent's internal actions. Only the event sending timing is modified forSubagentCallEventto support this execution model —asAsyncCallablesendsSubagentCallEventon the mailbox thread, anddurableExecuteAsyncblocks on the worker thread waiting for the result.3. Scope-based Execution
SubagentCallEventis converted toInputEventwithin the sub-agent's scheduling scope. Intermediate events are dispatched only within that scope — they do not leak to the parent agent or other sub-agents. The resultOutputEventis intercepted and returned to the caller. When all pending events are processed and no actions are running (quiesce), the call completes automatically.4. Isolation
SubagentRunnerContextprovides isolated context:AgentPlan's definitions, fully independent from parent.AgentConfiguration.Nested sub-agents are supported recursively via parent resource cache fallback.
5. Fault Tolerance
Design Discussion
1. Internal vs External Capability Parity
External and internal sub-agents provide identical user-facing API (registration,
call(),asAsyncCallable()). However, the underlying implementations differ significantly — external sub-agents are black-box calls (HTTP/gRPC), while internal sub-agents are framework-internal plan nesting execution.SubagentRunnerContextdurableExecuteAllAsyncdurableExecuteAsyncworker pool2. Introducing
SubagentCompatibleMarkerWhen an
Agentis registered as a sub-agent, it runs in an isolatedSubagentRunnerContext, meaning certain capabilities are restricted, such as the inability to write to memory. Not all Agents can correctly accommodate these constraints.To ensure registration correctness, we propose a
SubagentCompatiblemarker (interface / annotation / yaml field) that an Agent declares to indicate it is safe to run as a sub-agent. The framework validates this marker at compile time: when an unmarkedAgentis registered as a sub-agent, compilation fails fast.This provides an explicit contract: Agent authors must evaluate and declare compatibility with sub-agent constraints (e.g., no dependency on writing to parent memory, no reliance on cross-scope events), avoiding hard-to-debug behavioral anomalies at runtime.
We need to evaluate what capability restrictions sub-agents have, to confirm whether this marker is necessary.
To Be Refined
call()currently does not provide timeout or cancellation. Further investigation of requirements is needed to refine the design.tool_call_actiondispatch chain, need further clarification.SubagentSetupimplementation helpers for gRPC, A2A (Agent-to-Agent) protocol, etc., to reduce the cost of integrating external agents.Beta Was this translation helpful? Give feedback.
All reactions