Agent Spec specification (version 25.4.1)#
Language specification#
This document outlines the language specification for the Open Agent Specification, abbreviated as Agent Spec.
This specification defines the foundational parts that compose the language, including the expected format and the respective semantic.
The class definition in the following sections is outlined via Python below for ease of comprehension. This structure can be serialized into JSON, YAML, or other formats. The respective serialization is also called Agent Spec configuration (or representation).
Warning
Agent Spec serialized specifications are not supposed to contain executable code. Users should adopt security measures in their serialization and deserialization code when using formats that support such a functionality (e.g., using safe loading and dumping with YAML).
Base Component
#
The base of Agent Spec is a Component
, which by itself can be used to
describe any instance of any type, guaranteeing flexibility to adapt to future changes.
Note that Agent Spec does not need to encapsulate the implementation for code it describes; it simply needs to be able to express enough information to instantiate a uniquely-identifiable object of a specific type with a specific set of property values.
class Component:
# All components have a set of fixed common properties
id: str # Unique identifier for the component. Typically generated from component type plus a unique token.
type: str # Concrete type specifier for this component. Can be (but is not required to be) a class name.
name: str # Name of the component, if applicable
description: Optional[str] # Description of the component, if applicable
metadata: Optional[Dictionary[str, Any]] # Additional metadata that could be used for extra information
The metadata
field contains all the additional information that
could be useful in different usages of the component. For example, GUIs will
require to include some information about the components (e.g., position
coordinates, size, color, notes, …), so that they will be able to
visualise them properly even after an export-import process. Metadata is
optional, and empty by default.
Not all the building blocks of Agent Spec are necessarily Components
.
Some other convenient classes can be defined in order to more easily
describe the configurations of the agents (e.g., JSONSchemaValue
, LlmGenerationConfig
).
Those classes do not have to align to the interface of a Component.
Symbolic references (configuration components)#
When a component wishes to reference another component entity (e.g., as a property value), there is a simple symbolic syntax to accomplish this: an object with a single property “$component_ref” whose value is the id of the referenced component. This type of relationship is applicable to any component.
{"$component_ref": "{COMPONENT_ID}"}
Note that a subcomponent reused in multiple parts of a complex nested component (for example, a ClientTool used in both an AgentNode and a ToolNode as part of a flow) must be defined using a component reference. If two components in an Agent Spec configuration use the same id, the configuration will be considered invalid.
Input/output schemas#
Components might need some input data in order to perform their task, and expose some output as a result of their work.
These inputs and outputs must be declared and described in the exported configuration, so that users, developers, and other components of the Agent as well, are aware of what is exposed by component that require inputs, or provide outputs. We call these input and output descriptions as input/output schemas, and we add a subclass of Component called ComponentWithIO that adds them to the base Component class.
class ComponentWithIO(Component):
inputs: List[JSONSchemaValue]
outputs: List[JSONSchemaValue]
Note that we do not add input/output schemas directly to the base Component class, as there are a few cases where they do not really apply (e.g., LlmConfig, edges, see their definition in the next sections).
Input and output properties#
Input and output schemas are used to define which values the different components accept as input, or provide as output. We call these values “properties”.
The term “properties” comes from JSON schema: indeed, in order to specify all the inputs and outputs, we rely on this widely adopted and consolidated standard.
In particular, we ask to specify a list of JSON schemas definitions, one for each input and output property. For more information about JSON schema definition, please check the official website at https://json-schema.org/understanding-json-schema.
In order for the schema to be valid, we require to specify some attributes:
title: the name of the property
type: the type of the property, following the type system described below
Additionally, users can specify:
default: the default value of this property
description: a textual description for the property
These are the minimal attributes (or annotations, in JSON Schema terminology) that must be supported to ensure compatibility with Agent Spec.
Type system#
We rely on the typing system defined by the JSON schema standard (see https://json-schema.org/understanding-json-schema/reference/type).
At its core, JSON Schema defines the following basic types:
These types have analogs in most programming languages, though they may go by different names.
Note that some types (array, object) require additional annotations with respect to the ones listed in the previous section. Please refer to their JSON schema definition for more information.
Type compatibility rules#
To connect a component’s output to another component’s input, the output type must be compatible with the input type.
Specifically, the output type should be a subtype of the input type.
For instance, an output of type number
can connect to an input of type [number, null]
,
but an output of type string
cannot connect to an input of type number
.
In order to further simplify input-output connections, we define some simple type compatibility rules that are accepted by Agent Spec.
Every type can be converted to string.
Numeric types (i.e.,
integer
andnumber
) can be converted to each other. Note that this conversion could cause the loss of decimals.The Boolean type can be converted to numeric ones and vice-versa. The convention for the conversion is the one adopted by most programming languages: 0 refers to
false
, while any other number refers totrue
.
These rules apply recursively in complex types:
To the types of the elements of an
array
;To the types of the
properties
of anobject
.
Inputs and outputs of nested components#
In case of nested components (e.g., using an agent inside a flow, or a flow inside another flow, or even just a step in a flow), the wrapping component is supposed to expose a (sub)set of the inputs/outputs provided by the inner components, united to, potentially, additional inputs/outputs it generates itself.
We require to replicate the JSON schema of each value in the inputs/outputs lists of every component that exposes it, i.e., if a wrapper component exposes some inputs and outputs of some of its internal components, it will have to include them in its inputs/outputs lists as well.
This makes the representation of the components a bit more verbose, but more clear and readable. Parsers of the representation are required to ensure the consistency of the input/output schemas defined in it.
In the example above we have that the wrapper Flow Component (see sections below for more details about flows) requires two inputs that coincide with two of the inputs exposed by the Node components in it (see sections below for more details about nodes), and exposes one output among those exposed by the inner nodes, plus an additional one it computes itself. This corresponds to the following code definition.
Input output schema example
# String with "input_1_default" as default value
input_1 = StringType(title="Input_1", default="input_1_default")
# Dictionary with string keys and integers as values, default set to empty dictionary
input_2 = ObjectType(title="Input_2", properties={}, additional_properties=NumberType(), default={})
# Nullable string, default value set to null
input_3 = StringType(title="Input_3", nullable=True, default=None)
output_1 = StringType(title="Output_1")
output_2 = BooleanType(title="Output_2", default=True)
output_3 = ArrayType(title="Output_3", items=ArrayType(items=NumberType()), default=[[1], [2], [3]])
# Note that we envision a fluent-classes way of defining inputs and outputs
# These classes get serialized to their respective JSON schema equivalent
# VLlmConfig is a subclass of Component, we will define it more in detail later
# This Component does not have input/output schemas, the default should be an empty list
vllm = VllmConfig(name="LLama 3.1 8b", model_id="llama3.1-8b-instruct", url="url.to.my.llm.com/hostedllm:12345")
# Node is a subclass of Component, we will define it more in detail later
node_1 = StartNode(name="Node 1", input_values=[input_1, input_2, input_3])
node_2 = LLMNode(name="Node 2", llm=vllm, ...)
node_3 = EndNode(name="Node 3", output_values=[output_1, output_2, output_3])
# Flow is a subclass of Component, we will define it more in detail later
flow = Flow(nodes=[node_1, node_2, node_3], ..., inputs=[input_1, input_2], outputs=[output_2, output_3])
The presence of the inputs and outputs in the representation of every component does not imply that they always have to be explicitly defined by users.
Indeed, they could be automatically and dynamically generated by the components (e.g., inputs and outputs inferred from a prompt of an LLMNode).
Validation of specified inputs/outputs#
Some inputs and outputs schema are automatically generated by components based on their configuration. However, to improve the clarity and readability of Agent Spec, descriptions of all inputs and outputs should always be explicitly included in the representation.
As a consequence, when a representation is read and imported by a runtime, or an SDK, the inputs and outputs configuration of each component must be validated against the one generated by its configuration (if any).
Note that the input/output schema could be a specialization of the one generated automatically by the component (e.g., an additional description is added, a more precise type is defined, …).
For this reason, we do not enforce the generated I/O schemas to be perfectly equal to the one reported in the configuration, but we require that:
The set of input and output property names are equivalent
The type of each property in the generated I/O schemas can be casted to the type of the corresponding property reported in the configuration.
If these two requirements are not met, the Agent Spec configuration should be considered invalid.
Specifying inputs through placeholders#
Some Components might infer inputs from special parts of their
attributes. For example, some nodes (e.g., the LLMNode) extract inputs
from a property called prompt_template
, so that its value can be
adapted based on previous computations.
We let users define placeholders in some attributes, by simply wrapping the name of the property among a double set of curly brackets. The node will automatically infer the inputs by interpreting those configurations, and the actual value of the input/output will be replaced at execution time. Whether an attribute accepts placeholders depends on the definition of the component itself.
For example, setting the prompt_template configuration of an LLMNode to “You are a great assistant. Please help the user with this request: {{request}}” will generate an input called “request” of type string.
We do not require the support for complex types and collections like lists (array) and dictionaries (object) in placeholders: placeholders are typically transformed in inputs of type string, unless differently specified by the definition of the Component. In general, dictionaries and lists should be used directly in inputs and outputs with a matching type definition. The latter could also be used as input to the MapNode (see definition below), which applies the same flow to all the elements in the list and collects the output.
In the future, we will consider adding support for complex types (e.g., for loops over lists, dictionary access) through templating, for example by adopting a subset of the functionalities available in a common standard like jinja.
Component families#
The base Component
type is extended by several component families
which represent groups of elements that are commonly used in agentic
systems, such as (but not limited to) LLMs and Tools.
Describing these component families with specific types achieves the following goals :
Type safety + Usage hints for GUIs
Example: if a component’s property is expecting an LLM, only allow LLM’s to be connected to it.
Static analysis + validation
Examples: if a component is a ``Flow``, it must have a start node. If a component is an Agent, it must have an LLM.
Ease of programmatic use
Component families each have corresponding class definitions in the Agent Spec SDK. This allows consumers (agent execution environments, editing GUIs) to utilise concrete classes, rather than having to implicitly understand which type has which properties.
Component Family |
Notes |
Example |
---|---|---|
Agentic Component |
A top-level, interactive entity that can receive messages and produce
messages. |
|
Agent |
An agent is an interactive entity that can converse and use tools. |
|
Remote Agent |
An |
|
Flow |
An execution graph with a fixed layout, potentially containing branches and loops. |
A workflow with multiple, well known and well defined approval actions to be pursued based on some condition |
Node (flow) |
A Flow consists of a series of Node instances. There is a “standard library” of nodes for things such as executing a prompt with a LLM, branching, etc. |
|
Relations / edges (flow) |
Flow of control and I/O (data) are defined by explicit relationships in Agent Spec. |
|
LLM (config) |
The configuration needed to reach out to an LLM |
|
Tool |
A procedural function that can be made available to an Agent |
|
Agentic Components#
An Agentic Component represents anything you can “talk” to – i.e. an entity
that consumes a conversation (or other structured context), performs some work,
and returns a result that can be rendered as messages or structured data. It also represents
the entry point for interactions with the agentic system. It extends from ComponentWithIO
and can have inputs
and outputs.
Three concrete kinds are currently defined:
Flow
– a self-contained execution graph (described later in the document).Agent
– an in-process, conversational entity that can reason, call tools, and maintain state.RemoteAgent
– a conversational entity that is defined remotely and invoked through an RPC or REST call.
Agent#
The Agent
is the top-level construct that holds shared resources such
as conversation memory and tools. It also represents the entry point
for interactions with the agentic system.
class Agent(ComponentWithIO):
prompt_template: str
llm_configuration: LlmConfig
tools: List[Tool]
Its main goal is to fill the values for all the properties defined in
the outputs
attribute, with or without any interaction with the user.
It’s important to have a separate definition for Agents as components, so that the same Agent can be reused several times, e.g., in different flows, without replicating its definition multiple times.
Note that we do not require to define any output parser for an Agent. Outputs (including their types, descriptions, …) are defined at representation level, and the Agent will fill their values either directly, or through tools. If a special output format is required, users can specify a tool to fit the requirement.
It is also not required to specify the presence of tools in the prompt_template
.
Agent Spec assumes that the list of available tools, including their description, parameters, etc.
is handled by the runtime implementation, that should inform the agent’s LLM of their existence.
This Component will be expanded as more functionalities will be added to Agent Spec (e.g., memory, planners, …).
LLM#
LLMs are used in agents, as well as flow nodes that need one.
In order to make them usable, we need to let users specify all the details needed to configure the LLM, like the connection details, the generation parameters, etc.
We define a new Component called LlmConfig that contains all the details:
class LlmConfig(Component):
default_generation_parameters: Optional[Dict[str, Any]]
We require only to specify the default generation parameters that should be used by default when prompting the LLM. These parameters are specified as a dictionary of parameter names and respective values. The names are strings, while values can be of any type compatible with the JSON schema standard.
Note
The extra parameters should never include sensitive information. Make sure the extra parameter values are validated either by the runtime if supported, or explicitly before importing the configuration into the runtime.
Null value is equivalent to an empty dictionary, i.e., no default generation parameter is specified. Specific extensions of LlmConfig for the most common models are provided as well.
OpenAI Compatible LLMs#
This class of LLMs groups all the LLMs that are compatible with the OpenAI chat completions APIs.
class OpenAiCompatibleConfig(LlmConfig):
model_id: str
url: str
Based on this class of LLMs, we provide two main implementations.
vLLM#
Used to indicate all the LLMs deployed through vLLM.
class VllmConfig(OpenAiCompatibleConfig):
pass
Ollama#
Used to indicate all the LLMs deployed through Ollama.
class OllamaConfig(OpenAiCompatibleConfig):
pass
OpenAI#
This class of LLMs refers to the models offered by OpenAI.
class OpenAiConfig(LlmConfig):
model_id: str
OCI GenAI#
This class of LLMs refers to the models offered by Oracle GenAI.
OCI models require to specify the authentication method to be used when accessing the models.
Therefore, besides the attributes required to select the model to use, the OciGenAiConfig
contains
the authentication information as part of the LlmConfig
.
The serving_mode
parameter determines whether the model is served on-demand or in a dedicated capacity.
On-demand serving is suitable for variable workloads, while dedicated serving provides consistent performance
for high-throughput applications.
The provider
parameter specifies the underlying model provider, META for Llama models or COHERE for cohere
models. When None
, it is automatically detected based on the model_id
. When the serving_mode
is DEDICATED
the model_id
does not indicate what provider
should be used so the user has to specify it manually,
knowing what model it is.
class OciGenAiConfig(LlmConfig):
model_id: str
compartment_id: str
serving_mode: Literal["ON_DEMAND", "DEDICATED"] = "ON_DEMAND"
provider: Optional[Literal["META", "GROK", "COHERE", "OTHER"]] = None
client_config: OciClientConfig
Note
The authentication components must not contain any sensitive information about the authentication, like secrets, API keys, passwords, etc. Users must not include this information anywhere, as exported Agent Spec configurations should never include sensitive data.
OCI Client Configuration#
The OciClientConfig
contains all the settings needed to perform the authentication to use OCI services.
This object is used by the OciGenAiConfig
in order to access the Gen AI services of OCI and perform LLM calls.
This client configuration is also used by other components that require access to the OCI services (e.g., the
OciAgent
presented later in this document).
More information about how to perform authentication in OCI is available on the
Oracle website.
class OciClientConfig(Component):
service_endpoint: str
auth_type: Literal["SECURITY_TOKEN", "INSTANCE_PRINCIPAL", "RESOURCE_PRINCIPAL", "API_KEY"]
Based on the type of authentication the user wants to adopt, different specifications of the OciClientConfig
are defined. In the following sections we show what client extensions are available and their specific parameters.
OciClientConfigWithSecurityToken#
Client configuration that should be used if users want to use authentication through security token.
class OciClientConfigWithSecurityToken(OciClientConfig):
auth_profile: str
auth_file_location: str
auth_type: Literal["SECURITY_TOKEN"] = "SECURITY_TOKEN"
OciClientConfigWithApiKey#
Client configuration that should be used if users want to use authentication with API key.
class OciClientConfigWithApiKey(OciClientConfig):
auth_profile: str
auth_file_location: str
auth_type: Literal["API_KEY"] = "API_KEY"
OciClientConfigWithInstancePrincipal#
Client configuration that should be used if users want to use instance principal authentication.
class OciClientConfigWithInstancePrincipal(OciClientConfig):
auth_type: Literal["INSTANCE_PRINCIPAL"] = "INSTANCE_PRINCIPAL"
OciClientConfigWithResourcePrincipal#
Client configuration that should be used if users want to use resource principal authentication.
class OciClientConfigWithResourcePrincipal(OciClientConfig):
auth_type: Literal["RESOURCE_PRINCIPAL"] = "RESOURCE_PRINCIPAL"
Tools#
A tool is a procedural function or a flow that can be made available to an Agent to execute. In a flexible Agent context, the Agent can decide to call a tool based on its signature and description. In a flow context, a node would need to be configured to call a specific tool.
Where the actual tool functionality is actually executed or run depends on the type of the tool:
ServerTools are executed in the same runtime environment that the Agent is being executed in. The definitions of these tools therefore must be available to the Agent’s environment. It is expected that this type of tool will be very limited in number, and relatively general in functionality (e.g., human-in-the-loop).
ClientTools are not executed by the executor, the client must execute the tool and provide the results back to the executor (similar to OpenAI’s function calling model)
RemoteTools are run in an external environment, but triggered by an RPC or REST call from the Agent executor.
MCPTools interact with Model Context Protocol (MCP) servers to support remote tool execution.
Agent Spec is not supposed to provide an implementation of how these types of tools should work, but provide their representation, so that they can be correctly interpreted and ported across platforms and languages.
That said, as previously argued, a tool is a function that is called providing some parameters (i.e., inputs), performs some transformation, and returns some values (i.e, outputs). Of course the function has a name, and a description that can be used by an LLM in order to understand when it’s relevant to perform a task. Therefore, we can define a Tool as a simple extension of ComponentWithIO.
We let tools specify multiple outputs. In this case, the expected return value of the tool is a dictionary where each entry corresponds to an element specified in the outputs. The key of the dictionary entry must match the name of the property specified in the outputs. The runtime will parse the dictionary in order to extract the different outputs and bind them correctly.
While ServerTool and ClientTool do not require specific additional parameters, the RemoteTool requires to include also the details needed to perform the remote call to the tool.
class Tool(ComponentWithIO):
pass
class ClientTool(Tool):
pass
class ServerTool(Tool):
pass
class RemoteTool(Tool):
# Basic parameters needed for a remote API call
url: str
http_method: str
api_spec_uri: Optional[str]
data: Dict[str, Any]
query_params: Dict[str, Any]
headers: Dict[str, Any]
class MCPTool(Tool):
client_transport: ClientTransport
An important security aspect of Agent Spec is the exclusion of arbitrary code from the agent representation. The representation contains a complete description of the tool—its attributes, inputs, outputs, and related metadata—but does not embed executable code.
Remote Tools#
One common way to make tools available to agents, is to make them available under the for of REST APIs that the agent can call when the tool has to be executed.
Compared to ServerTools and ClientTools, these tools require more information to be specified, in order to perform the actual request.
We add the same parameters as the APINode (see the Nodes library in the Flows - Nodes section below), in order to perform a complete REST call in the right manner.
Note that, similarly to the APINode, we allow users to use placeholders (as described in section 5.3.4) in all the string attributes of the RemoteTool (i.e., url, http_method, api_spec_uri, and in the dict values of data, query_params, and headers).
MCP Tools#
MCP Tools are a specialized type of tool that connects to servers implementing
the Model Context Protocol (MCP). They extend the base Tool
with transport
configurations for secure, remote execution.
Like other tools, MCP Tools define inputs, outputs, and metadata but include a
client_transport
for managing connections (e.g., via SSE or Streamable HTTP
with mTLS) (details about the client transport can be found in
the MCP section below).
class MCPTool(Tool):
client_transport: ClientTransport
MCP Tools follow the same security principles as other tools: no arbitrary code is embedded in the representation. Execution occurs remotely via the specified transport, with the runtime handling session management and data relay.
For example, an MCP Tool might use an SSEmTLSTransport
to securely call a remote
function for data processing.
Execution flows#
Execution flows (or graphs) are directed, potentially-cyclic workflows. They can be thought of as “subroutines” that encapsulate consistently-repeatable processes.
Each execution flow requires 0 or more inputs (e.g., any input edges expressed on the starting node of the graph) and may produce 0 or more outputs (e.g., any output edges expressed by the terminal nodes of the graph - note that a graph can have more than one terminal node, in the event of branching logic).
Flow#
Flow
objects specify the entry point to the graph, the nodes, and edges for the graph.
Inner Components of the flow are described in subsequent sections.
class Flow(ComponentWithIo):
start_node: Node
nodes: List[Node]
control_flow_connections: List[ControlFlowEdge]
data_flow_connections: Optional[List[DataFlowEdge]]
A flow exposes a (sub)set of the union of all the outputs exposed by all the EndNodes. However, if an output defined in the flow does not have a corresponding output with the same name in every EndNode, then a default value for that output in the flow definition must be specified. The default value is used in case the EndNode executed at runtime does not expose an output with that name. It is not possible to define two outputs with the same name and different types in two distinct EndNodes of the same flow. It is instead possible to define different default values for outputs with the same name in distinct EndNodes.
For example, let’s assume to have a flow with two EndNodes, called respectively end_node_a
and end_node_b
.
end_node_a
exposes one output called output_a
, while end_node_b
exposes another output called output_b
.
We want to expose both the outputs from the flow, so we will include them in the outputs
definition of the flow
and, since they are not common to all the EndNodes in the flow, we must define a default value for them.
We assign default_value_a
as default for output_a
and default_value_b
as default for output_b
.
Note that these default values are required to be included in the flow specification, not in the EndNodes.
Let’s now assume that at runtime we execute the flow, and we complete it through the end_node_a
with a value
for output_a
set to value_a
. This means that as output values of the flow we will get value_a
for
output_a
, as it was generated by the EndNode that was executed, while we will get default_value_b
for output_b
,
as no value was generated for output_b
by the EndNode being executed.
As inputs, a flow must expose all the inputs that are defined in its StartNode.
Note that flows must have a unique StartNode, which is defined by the start_node
parameter,
and it should appear in the list of nodes
.
Conversation#
At the core of the execution of a conversational agent there’s the conversation itself. The conversation is implicitly passed to all the components throughout the flow. It contains the messages being produced by the different nodes: each node in a flow and each agent can append messages to the conversation if needed. Messages should have, at least, a type (e.g., system, agent, user), content, the sender, and the recipient.
Sub-flows and sub-agents contained in a Flow (i.e., as part of AgentNode and FlowNode, see the Node section for more information) share the same conversation of the Flow they belong to. Sub-agents and sub-flows should have access to all the messages in the conversation, and they should append in the same conversation all the messages that are generated during their execution. At the end of the execution of a sub-flow/sub-agent, the Flow that contains them should have access to all the messages generated before and during the execution of the sub-flow/sub-agent.
Warning
The conversation of the parent Flow is shared with sub-flows and sub-agents and vice-versa. Do not use sub-flows or sub-agents for information isolation purposes. For example, if a sub-agent calls a remote model, it may forward the entire conversation to that model.
Node#
A Node
is a vertex in an execution flow.
class Node(ComponentWithIO):
branches: List[str]
Being an extension of ComponentWithIO, the Node already has the attributes of Component (id, name, …) and ComponentWithIO (inputs and outputs).
Additionally, the each Node class has an attribute called branches used to define the names of the branches that can follow the current node. This is used to support cases where branching in control flow is needed (see the respective section in this page). For example:
In a flow, at some point we need to take different paths based on the value of an input, or the result of a condition (e.g., the equivalent of an in-else statement)
A flow used in a subflow has multiple end nodes, that can be reached as a result of an earlier branching, and that might result in different follow-up operations, so the different outgoing branches have to be exposed
Most nodes that are part of the flow have at least one default branch,
used to define which is the following node to be executed, that we
define with the name next
. Note that the branches attribute of the
Node is typically managed (i.e., automatically inferred) by the
implementation of the Node, but it will appear in the representation.
Each type of node can also have other specific attributes that define its configuration. They are defined in the table in this section containing the list of node types available in Agent Spec.
The list of inputs and outputs exposed by a Node is supposed to be automatically (and dynamically) generated by the Node instance itself in one of the SDKs. The user is still allowed to explicitly define them when generating the representation from an SDK, but the set of inputs and/or outputs manually specified must match with the expected one as per node’s generation (i.e., all the expected inputs and/or outputs must be present in the list specified by the user). This allows user specifying better the type of an input/output with respect to the one inferred automatically by the node (e.g., specify that a value in a prompt template is supposed to be an integer instead of a generic string). The lists of inputs and outputs will always appear in the representation of every node.
The standard library of available nodes is described in a separate section later.
Some nodes infer inputs from special parts of their configurations. For
example, some nodes (e.g., the LLMNode) extract inputs from a property
called prompt_template
. We let users define placeholders in the
configuration parts that allow that, by simply wrapping the name of the
property among a double set of curly brackets. The node will
automatically infer the inputs by interpreting those configurations, and
the actual value of the input/output will be replaced at execution time.
For example, setting the prompt_template configuration of an LLMNode to “You are a great assistant. Please help the user with this request: {{request}}” will generate an input called “request” of type string.
Relationships / Edges#
For flows, Agent Spec defines separate relationships (edges) for both properties and control flow. This allows Agent Spec to unambiguously handle patterns such as conditional branches and loops, which are very challenging to support with data-only flow control.
Relations are only applicable for flows. All relations express a transition from some source node to some target node.
Control edges#
A control relationship defines a potential transition from a branch of some node to another. The actual transition to be taken during a given execution is defined by the implementation of a specific node.
class ControlFlowEdge(Component):
from_node: Node
from_branch: Optional[str]
to_node: Node
The from_branch attribute of a ControlFlowEdge is set to null by
default, which means that it will connect the default branch (i.e.,
next
) of the source node.
Data relationships (I/O system components)#
Considering the I/O system, a component id alone is not sufficient to identify a data relationship. A component may take multiple input parameters and/or produce multiple output values. We must be able to determine what value or reference is mapped to each input, and where each output is used.
Sources (inputs) can be connected to outputs of another node, or to static values.
Destination (outputs) can be connected to inputs of another node, or left unconnected.
class DataFlowEdge(Component):
source_node: Node
source_output: str
destination_node: Node
destination_input: str
Connecting multiple data edges#
In the case of control flow, multi-connections from the same outgoing branch of a node are not allowed (note that we do not enable parallelism through edges). Edges define which are the allowed “next step” transitions, so that it’s clear that it’s possible to execute one node after the execution of another. For more information about scenarios with multiple outgoing branches (e.g., based on the value of a condition), please refer to the section about Conditional branching.
For what concerns the data flow, instead, it is sometimes necessary to connect two different data outputs to the same input. Two simple examples follow:
Therefore, we let users connect multiple data outputs to the same input. If multiple outputs are connected to the same input, the last node that was executed and that has an output connected to the input will have the priority. In other words, the behavior is similar to having the input exposed as a public variable, and every node that has an output connected to that input updates its value.
Optionality of data relationships#
Some frameworks do not require to specify the data flow, as they assume that all the properties are publicly exposed in a shared “variable space” that any component can access, and the read/write system is simply name-based.
In practice, this means that:
when a component has an input with a specific name, it will look into the public variable space to read the value of the variable with that name
when a component has an output with a specific name, it will write (or overwrite if it already exists) into the public variable space the variable with that name
The main advantage of this approach is that users do not have to define any data flow, making the building experience faster.
We let users adopt this type of I/O system by setting the
data_flow_connections
parameter of the Flow to None.
In this case, a name-based approach explained above will be adopted, which means that if a component writes an output whose name matches a variable space entry, the respective value in the variable space is overwritten.
Note that this name-based approach can be expressed defining explicitly Data Flow connections (but the opposite is not possible) by connecting all the outputs to the inputs with the same name, following the control flow connections in the flow in order to account for overwrites.
How to translate public values into data flow edges...
As just affirmed, it’s possible to transform the name-based approach to the data flow one, by creating automatically the right set of DataFlowEdges.
As a basic approach, this translation can be done by simply connecting all the outputs to all the inputs with the same name. The priority-based solution for value updates explained in previous section 5.4.4.4.3 will ensure the correct behavior of the data flow.
In order to minimize the amount of connections created, it’s possible to also adopt different solutions that do a simulation of an execution by following the control flow connections. SDKs are allowed to implement one version of this smarter solution.
Conditional branching#
Being able to follow different paths (or branches) based on some conditions is an important feature required to represent processes as flows (e.g., flowcharts).
Conditional branching in Agent Spec is supported through a special step called BranchingNode (detailed later), a node that maps input values to different branches through a key-value mapping.
Nodes can have multiple outgoing branches, as previously mentioned in this page.
The branches
attribute of the Node is automatically filled and managed
by the implementation of the Node, but it will appear in the representation. Both
Node.branches
and ControlFlowEdge.from_branch
are set to null by
default, and that is the default behavior in case one single branch is
going out of a node (this is compatible with the definition of Node and
ControlFlowEdge in this page). If a value is specified for the branches
of the from_node of a ControlFlowEdge, then also from_branch must be set
to one of the values in branches. GUIs will show the different branches
as output flows of the node, so that each of them can be connected in a
1-to-1 manner with another node’s flow input.
Standard library of nodes to use in flows#
Here’s the list of nodes supported in Agent Spec:
LLMNode: uses a LLM to generate some text from a prompt
APINode: performs an API call with the given configuration and inputs
AgentNode: runs a multi-round conversation with an Agentic Component, used to better structure agentic components and easily reuse them.
FlowNode: runs a flow inline, used to better structure and easily reuse Flows
MapNode: performs a map-reduce operation on a given input collection, applying a specified Flow to each element in the collection
StartNode: entry point of a flow
EndNode: exit point of a flow
BranchingNode: allows conditional branching based on the value of an input
ToolNode: executes a tool
InputMessageNode: interrupts temporarily the execution to retrieve user input
OutputMessageNode: appends an agent message to the conversation
A more detailed description of each node follows.
Name |
Description |
Parameters |
Input |
Output |
Outgoing branches |
|||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LlmNode |
|
|
One per variable in the prompt template |
The output text generated by the LLM |
One, the default next |
|||||||||||||||||||||||||||||||||||
ApiNode |
|
|
Inferred from the json spec retrieved from API Spec URI, if available and reachable. Empty otherwise (users will have to manually specify them) |
Inferred from the json spec retrieved from API Spec URI, if available and reachable. Empty otherwise (users will have to manually specify them) |
One, the default next |
|||||||||||||||||||||||||||||||||||
AgentNode |
|
|
The ones defined by the Agent |
The ones defined by the Agent |
One, the default next |
|||||||||||||||||||||||||||||||||||
FlowNode |
|
|
Inferred from the inner structure. It’s the sets of inputs required by the StartNode of the inner flow |
Inferred from the inner structure.
It’s the set of outputs defined in the |
Inferred from the inner flow: one per unique |
|||||||||||||||||||||||||||||||||||
MapNode |
The Map node is used when we need to map a sequence of nodes to each of the values defined in a list (from output of a previous node). This node is responsible to asynchronically map each value of a collection (defined in input_schema) to the first node of the ‘subflow’ and reduce the outputs of the last node of the ‘subflow’ to defined variables (defined in output_schema) |
|
Inferred from the inner structure (as defined in FlowNode).
The names of the inputs will be the ones of the inner flow,
complemented with the
Note that all the input lists must have the same length, otherwise a runtime error will be thrown. |
Inferred from the inner structure (as defined in FlowNode),
combined with the reducer method of each output.
The names of the outputs will be the ones of the inner flow,
complemented with the
|
One, the default next |
|||||||||||||||||||||||||||||||||||
StartNode |
|
None |
The list of inputs that should be exposed by the flow |
Inferred form the inputs. If a value is given, it must match exactly the list of properties defined in inputs |
One, the default next |
|||||||||||||||||||||||||||||||||||
EndNode |
|
|
Inferred form the outputs. If a value is given, it must match exactly the list of properties defined in outputs |
The list of outputs that should be exposed by the flow |
None (note that the branch_name is used by the Flow, not by this node) |
|||||||||||||||||||||||||||||||||||
BranchingNode |
|
|
The input value that should be used as key for the mapping |
None |
One for each value in the mapping, plus a branch called default, which is the branch taken by the flow when mapping fails (i.e., the input does not match any key in the mapping) |
|||||||||||||||||||||||||||||||||||
ToolNode |
Executes the given tool |
|
Inferred from the definition of the tool to execute |
Inferred from the definition of the tool to execute |
One, the default next |
|||||||||||||||||||||||||||||||||||
InputMessageNode |
|
|
One per variable in the message |
One string property that represents the content of the input user message |
One, the default next |
|||||||||||||||||||||||||||||||||||
OutputMessageNode |
Appends an agent message to the ongoing flow conversation |
|
One per variable in the message |
No outputs |
One, the default next |
RemoteAgent#
A RemoteAgent
is an AgenticComponent
whose logic executes outside the
current process, typically behind a remote endpoint. The representation must therefore
capture enough information for an executor to perform the remote invocation and
to relay messages back and forth.
OciAgent#
OciAgent
is a concrete implementation of RemoteAgent
running on
Oracle Cloud Infrastructure. It adds OCI-specific authentication and connection details.
class OciAgent(ComponentWithIO):
agent_endpoint_id: str
client_config: OciClientConfig # contains all OCI authentication related configurations
Versioning#
Every Agent Spec configuration should include a property called agentspec_version
at the top level.
The value of agentspec_version
specifies the Agent Spec specification version the configuration is
written for.
For example, the JSON serialized version of an Agent should look like the following:
{
"component_type": "Agent",
"name": "my agent",
"id": "my_agent_id",
"description": "",
"llm_config": {
"component_type": "VllmConfig",
"name": "my llm",
"id": "my_llm_id",
"description": "",
"default_generation_parameters": {},
"model_id": "my/llm",
"url": "my.llm.url"
}
"tools": [],
"agentspec_version": "25.4.1"
}
For release versioning, Agent Spec follows the format YEAR.QUARTER.PATCH. Agent Spec follows a quarterly release cadence, and it aligns versioning to that cadence such that YEAR corresponds to the last two digits of the year, and QUARTER refers to the quarter of the release (from 1 to 4). The first release is 25.4.1.
Updates in the PATCH version must not introduce new features or behavioral changes, they should only cover security concerns and clarifications if needed. However, any version update, including PATCH ones, could contain breaking changes.
Breaking changes include all the modifications that would make a configuration written in the previous version invalid or semantically different, for example:
Removing/modifying components
Removing/renaming an attribute
Supporting new, or changing existing behavior of components, even when the existing signature is unchanged
Non-breaking changes include:
Adding new components
Adding new attributes
Disambiguation or clarification of underspecified components’ structure or behavior that do not contradict previous versions
It’s the responsibility of the maintainers of Agent Spec Runtimes, SDKs, and Adapters to keep up to date with the latest changes in the Agent Spec language specification, and to report the compatibility of their artifacts with the different Agent Spec specification versions.
Due to backward compatibility reasons, we recommend to create Agent Spec configurations with the minimum version supported by all the Components in the configuration with the desired behavior.
Backward compatibility#
All breaking changes must go through a deprecation cycle of one year.
Whenever a breaking change is introduced, a deprecation notice must be provided in the language specification.
Deprecated features can be removed in any quarter release after 1 year from the deprecation notice, but it should not be done in patch releases, unless required for security reasons.
In any case, removed features must be announced in the release notes.
MCP (Model Context Protocol)#
Model Context Protocol (MCP) provides a standardized way for LLM-based Assistants to interact with remote servers that expose tools and data sources. MCP enables communication over various transports such as Streamable HTTP, Server-Sent Events (SSE), or even local stdio for prototyping.
In Agent Spec, MCP components define configurations for establishing client sessions
and transports to MCP servers. These are used primarily for tools (via MCPTool
)
but can be extended to other remote interactions in future versions.
MCP Client transport#
The core abstraction is ClientTransport
, which manages connections and sessions.
class ClientTransport(Component):
session_parameters: Optional[Dict[str, Any]]
The session_parameters
should be used to specify parameters of the MCP client session,
such as the session name and version, or the session timeout.
These parameters are specified as a dictionary of parameter names and respective values.
The names are strings, while values can be of any type compatible with the JSON schema standard.
MCP transports such as StdioTransport
directly extend the ClientTransport
component.
Stdio Transport#
The StdioTransport
component should be used for connecting to an MCP server via
subprocess with stdio. This transport must support being passed a the executable
commmand to run to start the servers as well as a list of command line arguments to
pass to the executable. It can also support being passed environment variables as
well as the working directory to use when spawning the process.
class StdioTransport(ClientTransport):
command: str
args: List[str]
env: Optional[Dict[str, str]]
cwd: Optional[str]
Remote MCP transports#
Another category of MCP client transports rely on remote connections to MCP servers.
Those components should extend the RemoteTransport
component and should support
the url
and headers
fields.
class RemoteTransport(ClientTransport):
url: str
headers: Dict[str, str]
url
is a string representing the URL to send the request.headers
is a dictionary of additional headers to use in the client.
SSE Transport#
The server-sent events (SSE) transport should be used to connect to MCP servers via Server-Sent Events.
class SSETransport(RemoteTransport):
pass
Streamable HTTP Transport#
The Streamable HTTP transport should be used to connect to MCP servers via the Streamable HTTP transport.
class StreamableHTTPTransport(RemoteTransport):
pass
The transports defined above can be used in components like MCPTool
(see the Tools section) to connect to MCP servers.
Additions to MCP transports#
Finally, individual MCP client transports should be extended to support additional functionalities, such as mutual Transport Layer Security (mTLS) connections.
SSE Transport with mTLS#
class SSEmTLSTransport(SSETransport):
key_file: str
cert_file: str
ca_file: str
key_file
is the path to the client’s private key file (PEM format).cert_file
is the path to the client’s certificate chain file (PEM format).ca_file
is the path to the trusted CA certificate file (PEM format) to verify the server.
Streamable HTTP Transport with mTLS#
class StreamableHTTPmTLSTransport(StreamableHTTPTransport):
key_file: str
cert_file: str
ca_file: str
key_file
is the path to the client’s private key file (PEM format).cert_file
is the path to the client’s certificate chain file (PEM format).ca_file
is the path to the trusted CA certificate file (PEM format) to verify the server.
Warning
For production use, always prefer secure transports like those with mTLS to ensure mutual authentication.
Ecosystem of plugins#
In order to support a wide range of use-cases, Agent Spec allows the creation of custom components through a plugin system. Plugins are extensions which can include new components or variants of the built-in Agent Spec components. For supporting reading, writing and executing plugin components, the serialization and deserialization logic must be added in an Agent Spec SDK and the execution logic of the plugin component must be added in an Agent Spec Runtime of choice.
To enable the support of plugins in Agent Spec SDK and Runtime, every component
from a plugin should specify its component_type
. This is needed for
serialization and deserialization in order to be able to select the right
plugin serializer or deserializer. Additionally, the name and version of plugins
are needed, because this information will help track and understand the provenance
and compatibility of various components from the plugin ecosystem.
Additionally, if a plugin component is intended as a subtype of another component
(for example a Node
, such that the new component can be included in a Flow
which expects sub components of type Node
), it must then have the same
unmodified attributes as the parent type and can only add new attributes.
{
"component_type": "MyCustomComponent",
"component_plugin_name": "MyCustomComponentPlugin",
"component_plugin_version": "1.2.3.4",
"id": "component_id",
"name": "My custom component",
"metadata": {},
"extra_field1": "...",
}
Assuming an SDK in the Python programming language, as an example (see the sdk detailed below), the abstract interface implemented for a plugin should be similar to this:
class ComponentSerializationPlugin:
@abstractmethod
def plugin_name(self) -> str:
"""Return the plugin name."""
pass
@abstractmethod
def plugin_version(self) -> str:
"""Return the plugin version."""
pass
@abstractmethod
def supported_component_types(self) -> List[str]:
"""Indicate what component types the plugin supports."""
pass
@abstractmethod
def serialize(self, component: Component, serialization_provider) -> Dict[str, Any]:
"""Method to implement to serialize a component that the plugin should be able to support."""
pass
And similarly for deserialization:
class ComponentDeserializationPlugin:
def plugin_name(self) -> str: ...
def plugin_version(self) -> str: ...
def supported_component_types(self) -> List[str]: ...
@abstractmethod
def deserialize(self, serialized_component: Dict[str, Any], deserialization_provider: DeserializationProvider) -> Component:
"""Method to implement to deserialize a component that the plugin should be able to support."""
pass
Disaggregated components#
There are scenarios where some parts of an Agent Spec configuration should not be exported as part of the main assistant’s configuration. For example when:
Some parts of a Component configuration contain sensitive information;
It’s useful to plug different Component versions in a configuration, based on the use case (e.g., use different LlmConfigurations in development and production environment), but without duplicating the configuration for every Component’s version.
Important
Agent Spec exported configurations should never contain sensitive information.
For this reason, Agent Spec supports referencing components and values that are not serialized
in the same configuration, therefore called disaggregated.
A serialized configuration of disaggregated components contains only the dictionary of $referenced_components
,
and it does not contain any component at the top level.
These disaggregated components must be provided when the main configuration is deserialized,
otherwise the deserialization should fail.
Additional disaggregated components that are not part of any exported configuration (e.g., those containing
potentially sensitive information) can be additionally provided at deserialization time by the SDK or the Runtime
performing it.
The disaggregated components references follow the same reference system described for components, based on ID matching.
The ID used for matching the disaggregated component is, by default, the key used in the $referenced_components
dictionary.
Users can override this behavior at deserialization time by mapping it to a different ID to match a component reference.
A component reference and its matched disaggregated component must be type-compatible.
Note that also values (e.g., the prompt_template
in an LlmNode
, or the url
of a VllmConfig
)
can become referenced components. This means that in the main configuration from which they are disaggregated,
they will appear as component references in the $referenced_components
dictionary,
with an ID assigned to them (i.e., the key of the dictionary entry).
The value should replace the reference in the main configuration during deserialization.
Here’s an example of an Agent Spec configuration that uses disaggregated components:
{
"component_type": "Agent",
"id": "powerful_agent_id",
"name": "Powerful agent",
"description": null,
"metadata": {},
"llm_config": {
"component_type": "VllmConfig",
"default_generation_parameters": null,
"description": null,
"id": "llama_llm_id",
"metadata": {},
"model_id": "meta/llama-3.3-70b",
"name": "vllm",
"url": { "$component_ref": "llm_url_id" }
},
"system_prompt": "You are a powerful agent",
"tools": [
{ "$component_ref": "powerful_tool_id" }
],
"inputs": [],
"outputs": []
}
And here’s the configuration containing the disaggregated components:
{
"$referenced_components": {
"powerful_tool_id": {
"component_type": "ClientTool",
"name": "powerful_tool",
"id": "powerful_tool_id",
"description": "Does powerful things",
"metadata": {},
"inputs": [],
"outputs": []
},
"llm_url_id": "my.url.to.llm"
}
}
Additional components for future versions#
In this first version we focused on the foundational elements of agents, but some concepts are not yet covered, and should be part of further discussions, and included in future versions.
Among them, we can highlight:
Memory
Data sources & search support (e.g., for easy RAG setup)
Planning
Multi-agent systems
These topics will be covered in future versions of Agent Spec.
Language examples#
Standalone agent#
Agents are capable of leveraging tools in multi-turn conversation in order to reach a specific goal.
Agents do not express flow of control: the layout for these components simply expresses property assignments.
In the following example we provide a generic implementation of a flexible agent that includes all the components it can take advantage of (e.g., tools, llms). In a future extension of the language, more components can be added to this spec (e.g., memory, planner).
In the following example, we show the representation of an agent focused on benefits, which has the same structure depicted above.
Agent Spec representation
{
"$referenced_components": {
// LLM
"oci_genai_llm": {
"id": "93b6d1d1",
"type": "OciGenAiLLM",
"name": "OCI GenAi LLM",
"model_id": "command-r-08-2024",
"default_generation_parameters": {}
},
// Tools
"get_beneficiaries_tool": {
"id": "57961473",
"type": "ServerTool",
"name": "get_beneficiaries",
"description": "Tool that retrieves the beneficiaries of a benefit",
"inputs": [
{
"title": "benefit_id",
"description": "The benefit ID",
"type": "string"
}
],
"outputs": [
{
"title": "beneficiaries",
"description": "The list of beneficiaries of the benefit",
"type": "array",
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
]
},
"add_beneficiary_tool": {
"id": "ee92ebd5",
"type": "ServerTool",
"name": "Add beneficiary",
"description": "Tool that add a beneficiaries to a benefit",
"inputs": [
{
"title": "benefit_id",
"description": "The benefit ID",
"type": "string"
},
{
"title": "beneficiary_id",
"description": "The beneficiary ID",
"type": "string"
}
],
"outputs": [
{
"title": "success",
"type": "boolean"
}
]
},
// (Other tools omitted for brevity...)
"agent": {
"id": "230f3438",
"type": "Agent",
"name": "Benefits Agent",
"description": "Agent focused of managing benefits",
"prompt_template": "You are an expert in managing benefits for employees (i.e., beneficiaries).\nPlease be kind and perform the task that the user gives you.\n",
"llm": [
{
"$ref": "oci_genai_llm"
}
],
"tools": [
{
"$ref": "get_beneficiaries_tool"
},
{
"$ref": "add_beneficiary_tool"
},
{
"$ref": "get_benefits_tool"
},
{
"$ref": "add_benefit_tool"
},
{
"$ref": "revoke_benefit_tool"
}
],
// ...
"inputs": [],
"outputs": []
}
},
"agentspec_version": "25.4.1"
}
Standalone flow#
The following diagram illustrates a flow that could be used in an online store’s customer support system.
The flow checks if an order is eligible for a replacement, and if that is the case, which products should be offered to the user in exchange for their defective item.
The flow may be invoked by a conversational agent or executed upon configuration via another user interface.
This graph is implemented by the following Agent Spec representation:
Agent Spec representation
{
"$referenced_components": {
// LLM
"oci_genai_llm": {
"id": "93b6d1d1",
"type": "OciGenAiLLM",
"name": "OCI GenAi LLM",
"model_id": "command-r-08-2024"
},
// Inner flow used in MapNode
// We omit the definition of the inner nodes and edges for brevity
"check_item_is_eligible_replacement_flow": {
"id": "123kahr3412",
"type": "Flow",
"name": "Check if an item is an eligible replacement",
"start_node": {
"$ref": "inner_start_node"
},
"nodes": [
{
"$ref": "inner_start_node"
},
{
"$ref": "inner_end_node_add_item"
},
{
"$ref": "inner_end_node_skip_item"
},
{
"$ref": "check_if_item_is_suitable_replacement_node"
}
],
"control_flow_connections": [
// ...
],
"data_flow_connections": [
// ...
],
"inputs": [
{
"title": "order",
"description": "The order information as a dictionary",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
{
"title": "possible_replacement_item",
"description": "The item to check",
"type": "object",
"additionalProperties": {
"type": "string"
}
}
],
"outputs": [
{
"title": "eligible_item",
"description": "The item if it is eligible as replacement, null otherwise",
"type": [
"object",
null
],
"additionalProperties": {
"type": "string"
}
}
]
},
// Nodes in the main flow
"start_node": {
"id": "8kug123t",
"type": "StartNode",
"name": "Start of flow",
"input_values": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
],
"inputs": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
],
"outputs": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
]
},
"end_node": {
"id": "8kug123t",
"type": "EndNode",
"name": "End of flow",
"output_values": [
{
"title": "eligible_items_list",
"description": "The list of items eligible as replacements in this order",
"type": [
"array",
null
],
"default": null,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
],
"inputs": [
{
"title": "eligible_items_list",
"description": "The list of items eligible as replacements in this order",
"type": [
"array",
null
],
"default": null,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
],
"outputs": [
{
"title": "eligible_items_list",
"description": "The list of items eligible as replacements in this order",
"type": [
"array",
null
],
"default": null,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
]
},
"retrieve_order_info_node": {
"id": "4db7755a",
"type": "APINode",
"name": "Retrieve order information from order ID",
"url": "https://url.to.my.remote.api/orders/{{order_id}}",
"http_method": "GET",
"inputs": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
],
"outputs": [
{
"title": "order",
"description": "The order information as a dictionary",
"type": "object",
"additionalProperties": {
"type": "string"
}
}
]
},
"is_order_eligible_for_replacement_node": {
"id": "4db7755a",
"type": "LLMNode",
"name": "Check if order is eligible for replacement",
"prompt_template": "Given the order, please confirm that it is eligible to get some items replaced. Output yes or no.",
"llm": {
"$ref": "oci_genai_llm"
},
"inputs": [
{
"title": "order",
"description": "The order information as a dictionary",
"type": "object",
"additionalProperties": {
"type": "string"
}
}
],
"outputs": [
{
"title": "is_eligible",
"description": "Yes if the order is eligible for replacement, No otherwise",
"type": "string"
}
]
},
"retrieve_items_in_similar_orders_node": {
"id": "34961203",
"type": "APINode",
"name": "Find items in similar orders",
"url": "https://url.to.my.remote.api/orders/{{order_id}}/items_in_similar_orders",
"http_method": "GET",
"inputs": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
],
"outputs": [
{
"title": "possible_replacement_items",
"description": "The list of items in similar order",
"type": "array",
"default": [],
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
]
},
"get_items_that_are_eligible_replacements_node": {
"id": "5k12h31257",
"type": "MapNode",
"name": "Get items that are eligible replacements",
"subflow": "check_item_is_eligible_replacement_flow",
"inputs": [
{
"title": "order",
"description": "The order information as a dictionary",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
{
"title": "possible_replacement_items",
"description": "The list of items in similar order",
"type": "array",
"default": [],
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
],
"outputs": [
{
"title": "eligible_items_list",
"description": "The list of items eligible as replacements in this order",
"type": "array",
"default": [],
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
]
},
// ...
// Flow edges
"start_to_retrieve_order_info": {
"id": "ff474101",
"type": "ControlFlowEdge",
"from_node": {
"$ref": "start_node"
},
"to_node": {
"$ref": "retrieve_order_info_node"
}
},
"retrieve_order_info_to_is_order_eligible_for_replacement": {
"id": "a4a6bdb0",
"type": "ControlFlowEdge",
"from_node": {
"$ref": "retrieve_order_info_node"
},
"to_node": {
"$ref": "is_order_eligible_for_replacement_node"
}
},
"is_order_eligible_for_replacement_to_next_nodes": {
"id": "a4a6bdb0",
"type": "ConditionalControlFlowEdge",
"from_node": {
"$ref": "is_order_eligible_for_replacement_node"
},
"mapping": {
"true": "retrieve_items_in_similar_orders_node",
"false": "generate_and_output_rejection_reason"
},
"inputs": [
{
"title": "is_eligible",
"description": "Yes if the order is eligible for replacement, No otherwise",
"type": "string"
}
],
"outputs": []
},
// ...
// I/O edges
"order_id_edge": {
"id": "a57c10f2",
"type": "DataFlowEdge",
"source_node": {
"$ref": "start_node"
},
"source_output": "order_id",
"destination_node": {
"$ref": "retrieve_order_info_node"
},
"destination_input": "order_id"
},
"order_info_edge": {
"id": "92c75f51",
"type": "DataFlowEdge",
"source_node": {
"$ref": "retrieve_order_info_node"
},
"source_output": "order",
"destination_node": {
"$ref": "is_order_eligible_for_replacement_node"
},
"destination_input": "order"
},
// ...
// Flow
"find_order_replacement_flow": {
"id": "abcdefgh",
"type": "Flow",
"name": "Find order replacement",
"start_node": {
"$ref": "start_node"
},
"nodes": [
{
"$ref": "start_node"
},
{
"$ref": "end_node"
},
{
"$ref": "retrieve_order_info_node"
},
{
"$ref": "is_order_eligible_for_replacement_node"
},
{
"$ref": "retrieve_items_in_similar_orders_node"
},
{
"$ref": "get_items_that_are_eligible_replacements_node"
}
// ...
],
"control_flow_connections": [
{
"$ref": "start_to_retrieve_order_info"
},
{
"$ref": "retrieve_order_info_to_is_order_eligible_for_replacement"
}
// ...
],
"data_flow_connections": [
{
"$ref": "order_id_edge"
},
{
"$ref": "order_info_edge"
}
// ...
],
"inputs": [
{
"title": "order_id",
"description": "The order ID",
"type": "string"
}
],
"outputs": [
{
"title": "eligible_items_list",
"description": "The list of items eligible as replacements in this order",
"type": [
"array",
null
],
"default": null,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
]
}
},
"agentspec_version": "25.4.1"
}
Agents in flow#
In this example we are going to show how to use agents in a flow.
We propose a Coding Agent where different specialized agents operate in sequence in order to generate code based on a user request.
The flow consists of a main conversational agent that talks with a user to gather the request, then three agents that take care of the code generation and its review.
The advantage of having this type of agent implemented as a graph is that we have control on what is the sequence of calls and events that should happen before approving the generated code.
In particular, we can ensure that the code gets generated by the respective agent, and before being passed back to the main assistant that interacts with the user, it is passed through the two reviewer agents, and we must get both validations before going back to the main user facing agent.
For brevity, in the diagram we omit the internal structure of the agents, which is comparable to the one defined in example 5.1.
Put name of the agent in the diagram. Show that same agent can be executed in different places.
This graph is implemented by the following Agent Spec representation:
Agent Spec representation
{
"$referenced_components": {
// # Tools
"python_syntax_checker_tool": {
"id": "np2bmc823hba",
"type": "ServerTool",
"name": "Python syntax checker",
"description": "Check if the given python code is syntactically correct",
"inputs": [
{
"title": "code",
"description": "The python code to check",
"type": "string"
}
],
"outputs": [
{
"title": "is_correct",
"type": "boolean"
}
]
},
"run_python_code_in_sandbox_tool": {
"id": "3kjsagh783jka",
"type": "ServerTool",
"name": "Run python in sandbox",
"description": "Run code in a python sandbox and return true if execution was successful",
"inputs": [
{
"title": "code",
"description": "The python code to run",
"type": "string"
}
],
"outputs": [
{
"title": "is_successful",
"type": "boolean"
}
]
},
// ...
// Agents
// Main coding agent
// This agent is reused in several places (gather requirements, generate code, review it)
"coding_agent": {
"id": "gtrkj321",
"type": "Agent",
"name": "Coding Agent",
"prompt_template": "You are a great coding assistant. Your task is to gather user's requirement and then,\nbased on those requirements, generate the python code to perform the task, or review the code if it is already given.\nPlease be kind, and follow all the instructions of the user, but do only python code related tasks.\n",
"llm": [
{
"$ref": "oci_genai_llm"
}
],
"tools": [
{
"$ref": "python_syntax_checker_tool"
},
{
"$ref": "run_python_code_in_sandbox_tool"
}
],
"inputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": [
"string",
null
],
"default": null
},
{
"title": "review concerns",
"description": "The concerns raised by the review",
"type": [
"string",
null
],
"default": null
},
{
"title": "user request",
"description": "The user requirements that were gathered",
"type": [
"string",
null
],
"default": null
}
],
"outputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": [
"string",
null
],
"default": null
},
{
"title": "review concerns",
"description": "The concerns raised by the review",
"type": [
"string",
null
],
"default": null
},
{
"title": "user request",
"description": "The user requirements that were gathered",
"type": [
"string",
null
],
"default": null
}
]
},
// Agent for code security review
"code_security_expert_agent": {
"id": "981nj23a",
"type": "Agent",
"name": "Code Security Expert Agent",
"prompt_template": "You are a great code security reviewer.\nCheck the given user's code and expose all the concerns you have regarding the security of the code.\nThis is critical code, so be strict in your judgment, but nice in exposing the concerns.\n",
"llm": [
{
"$ref": "oci_genai_llm"
}
],
"tools": [
{
"$ref": "..."
}
],
"inputs": [
// Same as inner agent
"..."
],
"outputs": [
// Same as inner agent
"..."
]
},
// Nodes in the flow
"gather_requirements_node": {
"id": "9ku4323t",
"type": "AgentNode",
"name": "Gather requirements",
"agent": [
{
"$ref": "coding_agent"
}
],
"inputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": [
"string",
null
],
"default": null
},
{
"title": "review concerns",
"description": "The concerns raised by the review",
"type": [
"string",
null
],
"default": null
},
{
"title": "user request",
"description": "The user requirements that were gathered",
"type": [
"string",
null
],
"default": null
}
],
"outputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": [
"string",
null
],
"default": null
},
{
"title": "review concerns",
"description": "The concerns raised by the review",
"type": [
"string",
null
],
"default": null
},
{
"title": "user request",
"description": "The user requirements that were gathered",
"type": [
"string",
null
],
"default": null
}
]
},
"code_generator_node": {
"id": "yt23qwne",
"type": "AgentNode",
"name": "Code Generator",
"agent": [
{
"$ref": "coding_agent"
}
],
"inputs": [
{
"title": "generated code",
"description": "The python code to review",
"type": "string"
}
],
"outputs": [
{
"title": "review concerns",
"description": "The security concerns",
"type": "string"
}
]
},
"code_reviewer_node": {
"id": "83724698",
"type": "AgentNode",
"name": "Code reviewer",
"agent": [
{
"$ref": "coding_agent"
}
],
"inputs": [
// Same as inner agent
"..."
],
"outputs": [
// Same as inner agent
"..."
]
},
"code_security_expert_node": {
"id": "i3124bjkgf",
"type": "AgentNode",
"name": "Security Expert",
"agent": [
{
"$ref": "code_security_expert_agent"
}
],
"inputs": [
// Same as inner agent
"..."
],
"outputs": [
// Same as inner agent
"..."
]
},
"start_node": {
"id": "8kug123t",
"type": "StartNode",
"name": "Start of flow",
"input_values": null,
// Inputs and outputs are automatically generated from input_values
"inputs": [],
"outputs": []
},
"end_node": {
"id": "8kug123t",
"type": "EndNode",
"name": "End of flow",
"output_values": [
{
"title": "generated code",
"description": "The python code generated",
"type": "string"
}
],
// Inputs and outputs are automatically generated from output_values
"inputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": "string"
}
],
"outputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": "string"
}
]
},
// Flow edges
"start_to_gather_requirements": {
"id": "hqwjne43",
"type": "ControlFlowEdge",
"from_node": {
"$ref": "start_node"
},
"to_node": {
"$ref": "gather_requirements_node"
}
},
"gather_requirements_to_generator": {
"id": "hqwjne43",
"type": "ControlFlowEdge",
"from_node": {
"$ref": "gather_requirements_node"
},
"to_node": {
"$ref": "code_generator_node"
}
},
// ...
// I/O edges
"user_request_to_code_generator_edge": {
"id": "a57c10f2",
"type": "DataFlowEdge",
"source_node": {
"$ref": "gather_requirements_node"
},
"source_output": "user request",
"destination_node": {
"$ref": "code_generator_node"
},
"destination_input": "user request"
},
"user_request_to_code_reviewer_edge": {
"id": "a57c10f2",
"type": "DataFlowEdge",
"source_node": {
"$ref": "gather_requirements_node"
},
"source_output": "user request",
"destination_node": {
"$ref": "code_reviewer_node"
},
"destination_input": "user request"
},
"code_generated_to_reviewer_edge": {
"id": "92c75f51",
"type": "DataFlowEdge",
"source_node": {
"$ref": "code_generator_node"
},
"source_output": "generated code",
"destination_node": {
"$ref": "code_reviewer_node"
},
"destination_input": "generated code"
},
// ...
// Flow
"coding_assistant_flow": {
"id": "7khg1i34",
"type": "Flow",
"name": "Coding agent flow",
"start_node": {
"$ref": "start_node"
},
"nodes": [
{
"$ref": "start_node"
},
{
"$ref": "end_node"
},
{
"$ref": "gather_requirements_node"
},
{
"$ref": "code_generator_node"
},
{
"$ref": "code_reviewer_node"
},
{
"$ref": "code_security_expert_node"
}
// ...
],
"control_flow_connections": [
{
"$ref": "start_to_gather_requirements"
},
{
"$ref": "gather_requirements_to_generator"
}
// ...
],
"data_flow_connections": [
{
"$ref": "user_request_to_code_generator_edge"
},
{
"$ref": "user_request_to_code_reviewer_edge"
},
{
"$ref": "code_generated_to_reviewer_edge"
}
// ...
],
"inputs": [],
"outputs": [
{
"title": "generated code",
"description": "The python code generated",
"type": "string"
}
]
}
}
}
(Generated) JSON Language spec#
We put here the current JSON spec of the Agent Spec language.
JSON Schema
{
"$defs": {
"Agent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgent"
}
]
},
"AgentNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgentNode"
}
]
},
"AgenticComponent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgenticComponent"
}
]
},
"ApiNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseApiNode"
}
]
},
"BranchingNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseBranchingNode"
}
]
},
"ClientTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseClientTool"
}
]
},
"ClientTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseClientTransport"
}
]
},
"ComponentWithIO": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseComponentWithIO"
}
]
},
"ControlFlowEdge": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseControlFlowEdge"
}
]
},
"DataFlowEdge": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseDataFlowEdge"
}
]
},
"EndNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseEndNode"
}
]
},
"Flow": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseFlow"
}
]
},
"FlowNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseFlowNode"
}
]
},
"InputMessageNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseInputMessageNode"
}
]
},
"LlmConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseLlmConfig"
}
]
},
"LlmGenerationConfig": {
"additionalProperties": true,
"description": "A configuration object defining LLM generation parameters.\n\nParameters include number of tokens, sampling parameters, etc.",
"properties": {
"max_tokens": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"title": "Max Tokens"
},
"temperature": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Temperature"
},
"top_p": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Top P"
}
},
"title": "LlmGenerationConfig",
"type": "object"
},
"LlmNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseLlmNode"
}
]
},
"MCPTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseMCPTool"
}
]
},
"MapNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseMapNode"
}
]
},
"ModelProvider": {
"description": "Provider of the model. It is used to ensure the requests to this model respect\nthe format expected by the provider.",
"enum": [
"META",
"GROK",
"COHERE",
"OTHER"
],
"title": "ModelProvider",
"type": "string"
},
"Node": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseNode"
}
]
},
"OciAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciAgent"
}
]
},
"OciClientConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfig"
}
]
},
"OciClientConfigWithApiKey": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithApiKey"
}
]
},
"OciClientConfigWithInstancePrincipal": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithInstancePrincipal"
}
]
},
"OciClientConfigWithResourcePrincipal": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithResourcePrincipal"
}
]
},
"OciClientConfigWithSecurityToken": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithSecurityToken"
}
]
},
"OciGenAiConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciGenAiConfig"
}
]
},
"OllamaConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOllamaConfig"
}
]
},
"OpenAiAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiAgent"
}
]
},
"OpenAiCompatibleConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiCompatibleConfig"
}
]
},
"OpenAiConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiConfig"
}
]
},
"OutputMessageNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOutputMessageNode"
}
]
},
"Property": {
"description": "This object must be a valid JSON Schema",
"type": "object"
},
"ReductionMethod": {
"description": "Enumerator for the types of reduction available in the MapNode.",
"enum": [
"append",
"sum",
"average",
"max",
"min"
],
"title": "ReductionMethod",
"type": "string"
},
"RemoteAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteAgent"
}
]
},
"RemoteTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteTool"
}
]
},
"RemoteTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteTransport"
}
]
},
"SSETransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseSSETransport"
}
]
},
"SSEmTLSTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseSSEmTLSTransport"
}
]
},
"ServerTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseServerTool"
}
]
},
"ServingMode": {
"enum": [
"ON_DEMAND",
"DEDICATED"
],
"title": "ServingMode",
"type": "string"
},
"SessionParameters": {
"description": "Class to specify parameters of the MCP client session.",
"properties": {
"read_timeout_seconds": {
"default": 60,
"title": "Read Timeout Seconds",
"type": "number"
}
},
"title": "SessionParameters",
"type": "object"
},
"StartNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStartNode"
}
]
},
"StdioTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStdioTransport"
}
]
},
"StreamableHTTPTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStreamableHTTPTransport"
}
]
},
"StreamableHTTPmTLSTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStreamableHTTPmTLSTransport"
}
]
},
"Tool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseTool"
}
]
},
"ToolNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseToolNode"
}
]
},
"VllmConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseVllmConfig"
}
]
},
"BaseAgent": {
"additionalProperties": false,
"description": "An agent is a component that can do several rounds of conversation to solve a task.\n\nIt can be executed by itself, or be executed in a flow using an AgentNode.\n\n\nExamples\n--------\n>>> from pyagentspec.agent import Agent\n>>> from pyagentspec.property import Property\n>>> expertise_property=Property(\n... json_schema={\"title\": \"domain_of_expertise\", \"type\": \"string\"}\n... )\n>>> system_prompt = '''You are an expert in {{domain_of_expertise}}.\n... Please help the users with their requests.'''\n>>> agent = Agent(\n... name=\"Adaptive expert agent\",\n... system_prompt=system_prompt,\n... llm_config=llm_config,\n... inputs=[expertise_property],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"llm_config": {
"$ref": "#/$defs/LlmConfig"
},
"system_prompt": {
"title": "System Prompt",
"type": "string"
},
"tools": {
"items": {
"$ref": "#/$defs/Tool"
},
"title": "Tools",
"type": "array"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "Agent"
}
},
"required": [
"name",
"llm_config",
"system_prompt"
],
"title": "Agent",
"type": "object",
"x-abstract-component": false
},
"BaseAgentNode": {
"additionalProperties": false,
"description": "The agent execution node is a node that will execute an agent as part of a flow.\n\nIf branches are configured, the agent will be prompted to select a branch before the agent node\ncompletes to transition to another node of the Flow.\n\n- **Inputs**\n Inferred from the definition of the agent to execute.\n- **Outputs**\n Inferred from the definition of the agent to execute.\n- **Branches**\n One, the default next.\n\nExamples\n--------\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.agent import Agent\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.nodes import AgentNode, StartNode, EndNode\n>>> from pyagentspec.tools import ServerTool\n>>> query_property = Property(json_schema={\"title\": \"query\", \"type\": \"string\"})\n>>> search_results_property = Property(\n... json_schema={\"title\": \"search_results\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}\n... )\n>>> search_tool = ServerTool(\n... name=\"search_tool\",\n... description=(\n... \"This tool runs a web search with the given query \"\n... \"and returns the most relevant results\"\n... ),\n... inputs=[query_property],\n... outputs=[search_results_property],\n... )\n>>> agent = Agent(\n... name=\"Search agent\",\n... llm_config=llm_config,\n... system_prompt=(\n... \"Your task is to gather the required information for the user: {{query}}\"\n... ),\n... tools=[search_tool],\n... outputs=[search_results_property],\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[query_property])\n>>> end_node = EndNode(name=\"end\", outputs=[search_results_property])\n>>> agent_node = AgentNode(\n... name=\"Search agent node\",\n... agent=agent,\n... )\n>>> flow = Flow(\n... name=\"Search agent flow\",\n... start_node=start_node,\n... nodes=[start_node, agent_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_agent\", from_node=start_node, to_node=agent_node),\n... ControlFlowEdge(name=\"agent_to_end\", from_node=agent_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"query_edge\",\n... source_node=start_node,\n... source_output=\"query\",\n... destination_node=agent_node,\n... destination_input=\"query\",\n... ),\n... DataFlowEdge(\n... name=\"search_results_edge\",\n... source_node=agent_node,\n... source_output=\"search_results\",\n... destination_node=end_node,\n... destination_input=\"search_results\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"agent": {
"$ref": "#/$defs/AgenticComponent"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "AgentNode"
}
},
"required": [
"name",
"agent"
],
"title": "AgentNode",
"type": "object",
"x-abstract-component": false
},
"BaseAgenticComponent": {
"anyOf": [
{
"$ref": "#/$defs/OciAgent"
},
{
"$ref": "#/$defs/RemoteAgent"
},
{
"$ref": "#/$defs/Agent"
},
{
"$ref": "#/$defs/OpenAiAgent"
},
{
"$ref": "#/$defs/Flow"
}
],
"x-abstract-component": true
},
"BaseApiNode": {
"additionalProperties": false,
"description": "Make an API call.\n\nThis node is intended to be a part of a Flow.\n\n- **Inputs**\n Inferred from the json spec retrieved from API Spec URI, if available and reachable.\n Otherwise, users have to manually specify them.\n- **Outputs**\n Inferred from the json spec retrieved from API Spec URI, if available and reachable.\n Otherwise, users have to manually specify them.\n- **Branches**\n One, the default next.\n\n\nExamples\n--------\n>>> from pyagentspec.flows.nodes import ApiNode\n>>> from pyagentspec.property import Property\n>>> weather_result_property = Property(\n... json_schema={\n... \"title\": \"zurich_weather\",\n... \"type\": \"object\",\n... \"properties\": {\n... \"temperature\": {\n... \"type\": \"number\",\n... \"description\": \"Temperature in celsius degrees\",\n... },\n... \"weather\": {\"type\": \"string\"}\n... },\n... }\n... )\n>>> call_current_weather_step = ApiNode(\n... name=\"Weather API call node\",\n... url=\"https://example.com/weather\",\n... http_method = \"GET\",\n... query_params={\n... \"location\": \"zurich\",\n... },\n... outputs=[weather_result_property]\n... )\n>>>\n>>> item_id_property = Property(\n... json_schema={\"title\": \"item_id\", \"type\": \"string\"}\n... )\n>>> order_id_property = Property(\n... json_schema={\"title\": \"order_id\", \"type\": \"string\"}\n... )\n>>> store_id_property = Property(\n... json_schema={\"title\": \"store_id\", \"type\": \"string\"}\n... )\n>>> session_id_property = Property(\n... json_schema={\"title\": \"session_id\", \"type\": \"string\"}\n... )\n>>> create_order_step = ApiNode(\n... name=\"Orders api call node\",\n... url=\"https://example.com/orders/{{ order_id }}\",\n... http_method=\"POST\",\n... # sending an object which will automatically be transformed into JSON\n... data={\n... # define a static body parameter\n... \"topic_id\": 12345,\n... # define a templated body parameter.\n... # The value for {{ item_id }} will be taken from the IO system at runtime\n... \"item_id\": \"{{ item_id }}\",\n... },\n... query_params={\n... # provide one templated query parameter called \"store_id\"\n... # which will take its value from the IO system from key \"store_id\"\n... \"store_id\": \"{{ store_id }}\",\n... },\n... headers={\n... # set header session_id. the value is coming from the IO system\n... \"session_id\": \"{{ session_id }}\",\n... },\n... inputs=[item_id_property, order_id_property, store_id_property, session_id_property],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"url": {
"title": "Url",
"type": "string"
},
"http_method": {
"title": "Http Method",
"type": "string"
},
"api_spec_uri": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Api Spec Uri"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"query_params": {
"additionalProperties": true,
"title": "Query Params",
"type": "object"
},
"headers": {
"additionalProperties": true,
"title": "Headers",
"type": "object"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "ApiNode"
}
},
"required": [
"name",
"url",
"http_method"
],
"title": "ApiNode",
"type": "object",
"x-abstract-component": false
},
"BaseBranchingNode": {
"additionalProperties": false,
"description": "Select the next node to transition to based on a mapping.\n\nThe input is used as key for the mapping. If the input does not correspond to any of the keys\nof the mapping the branch 'default' will be selected. This node is intended to be a part of a\nFlow.\n\n- **Inputs**\n The input value that should be used as key for the mapping.\n- **Outputs**\n None.\n- **Branches**\n One for each value in the mapping, plus a branch called ``default``,\n which is the branch taken by the flow when mapping fails\n (i.e., the input does not match any key in the mapping).\n\nExamples\n--------\n>>> from pyagentspec.agent import Agent\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import AgentNode, BranchingNode, StartNode, EndNode\n>>> from pyagentspec.property import Property\n>>> CORRECT_PASSWORD_BRANCH = \"PASSWORD_OK\"\n>>> password_property = Property(\n... json_schema={\"title\": \"password\", \"type\": \"string\"}\n... )\n>>> agent = Agent(\n... name=\"User input agent\",\n... llm_config=llm_config,\n... system_prompt=(\n... \"Your task is to ask the password to the user. \"\n... \"Once you get it, submit it and end.\"\n... ),\n... outputs=[password_property],\n... )\n>>> start_node = StartNode(name=\"start\")\n>>> access_granted_end_node = EndNode(\n... name=\"access granted end\", branch_name=\"ACCESS_GRANTED\"\n... )\n>>> access_denied_end_node = EndNode(\n... name=\"access denied end\", branch_name=\"ACCESS_DENIED\"\n... )\n>>> branching_node = BranchingNode(\n... name=\"password check\",\n... mapping={\"123456\": CORRECT_PASSWORD_BRANCH},\n... inputs=[password_property]\n... )\n>>> agent_node = AgentNode(\n... name=\"User input agent node\",\n... agent=agent,\n... )\n>>> assistant = Flow(\n... name=\"Check access flow\",\n... start_node=start_node,\n... nodes=[\n... start_node,\n... agent_node,\n... branching_node,\n... access_granted_end_node,\n... access_denied_end_node\n... ],\n... control_flow_connections=[\n... ControlFlowEdge(\n... name=\"start_to_agent\",\n... from_node=start_node,\n... to_node=agent_node\n... ),\n... ControlFlowEdge(\n... name=\"agent_to_branching\",\n... from_node=agent_node,\n... to_node=branching_node\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_access_granted\",\n... from_node=branching_node,\n... from_branch=CORRECT_PASSWORD_BRANCH,\n... to_node=access_granted_end_node,\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_access_denied\",\n... from_node=branching_node,\n... from_branch=BranchingNode.DEFAULT_BRANCH,\n... to_node=access_denied_end_node,\n... ),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"password_edge\",\n... source_node=agent_node,\n... source_output=\"password\",\n... destination_node=branching_node,\n... destination_input=\"password\",\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"mapping": {
"additionalProperties": {
"type": "string"
},
"title": "Mapping",
"type": "object"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "BranchingNode"
}
},
"required": [
"name",
"mapping"
],
"title": "BranchingNode",
"type": "object",
"x-abstract-component": false
},
"BaseClientTool": {
"additionalProperties": false,
"description": "A tool that needs to be run by the client application.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "ClientTool"
}
},
"required": [
"name"
],
"title": "ClientTool",
"type": "object",
"x-abstract-component": false
},
"BaseClientTransport": {
"anyOf": [
{
"$ref": "#/$defs/RemoteTransport"
},
{
"$ref": "#/$defs/SSEmTLSTransport"
},
{
"$ref": "#/$defs/StreamableHTTPmTLSTransport"
},
{
"$ref": "#/$defs/SSETransport"
},
{
"$ref": "#/$defs/StdioTransport"
},
{
"$ref": "#/$defs/StreamableHTTPTransport"
}
],
"x-abstract-component": true
},
"BaseComponentWithIO": {
"anyOf": [
{
"$ref": "#/$defs/ApiNode"
},
{
"$ref": "#/$defs/ClientTool"
},
{
"$ref": "#/$defs/AgenticComponent"
},
{
"$ref": "#/$defs/RemoteAgent"
},
{
"$ref": "#/$defs/LlmNode"
},
{
"$ref": "#/$defs/Agent"
},
{
"$ref": "#/$defs/OciAgent"
},
{
"$ref": "#/$defs/MapNode"
},
{
"$ref": "#/$defs/AgentNode"
},
{
"$ref": "#/$defs/OpenAiAgent"
},
{
"$ref": "#/$defs/FlowNode"
},
{
"$ref": "#/$defs/Flow"
},
{
"$ref": "#/$defs/ToolNode"
},
{
"$ref": "#/$defs/ServerTool"
},
{
"$ref": "#/$defs/OutputMessageNode"
},
{
"$ref": "#/$defs/RemoteTool"
},
{
"$ref": "#/$defs/StartNode"
},
{
"$ref": "#/$defs/EndNode"
},
{
"$ref": "#/$defs/Node"
},
{
"$ref": "#/$defs/Tool"
},
{
"$ref": "#/$defs/MCPTool"
},
{
"$ref": "#/$defs/BranchingNode"
},
{
"$ref": "#/$defs/InputMessageNode"
}
],
"x-abstract-component": true
},
"BaseControlFlowEdge": {
"additionalProperties": false,
"description": "A control flow edge specifies a possible transition from a node to another in a flow.\n\nA single node can have several potential next nodes, in which case several control flow edges\nshould be present in the control flow connections of that flow.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"from_node": {
"$ref": "#/$defs/Node"
},
"from_branch": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "From Branch"
},
"to_node": {
"$ref": "#/$defs/Node"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "ControlFlowEdge"
}
},
"required": [
"name",
"from_node",
"to_node"
],
"title": "ControlFlowEdge",
"type": "object",
"x-abstract-component": false
},
"BaseDataFlowEdge": {
"additionalProperties": false,
"description": "A data flow edge specifies how the output of a node propagates as input of another node.\n\nAn outputs can be propagated as input of several nodes.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"source_node": {
"$ref": "#/$defs/Node"
},
"source_output": {
"title": "Source Output",
"type": "string"
},
"destination_node": {
"$ref": "#/$defs/Node"
},
"destination_input": {
"title": "Destination Input",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "DataFlowEdge"
}
},
"required": [
"name",
"source_node",
"source_output",
"destination_node",
"destination_input"
],
"title": "DataFlowEdge",
"type": "object",
"x-abstract-component": false
},
"BaseEndNode": {
"additionalProperties": false,
"description": "End nodes denote the end of the execution of a flow.\n\nThere might be several end nodes in a flow, in which case the executor of the flow\nshould be able to track which one was reached and pass that back to the caller.\n\n- **Inputs**\n The list of inputs of the step. If both input and output properties are specified they\n must be an exact match\n- **Outputs**\n The list of outputs that should be exposed by the flow. If both input and output properties\n are specified they must be an exact match\n- **Branches**\n None.\n\nExamples\n--------\n>>> from pyagentspec.agent import Agent\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import AgentNode, BranchingNode, StartNode, EndNode\n>>> from pyagentspec.property import Property\n>>> languages_to_branch_name = {\n... \"english\": \"ENGLISH\",\n... \"spanish\": \"SPANISH\",\n... \"italian\": \"ITALIAN\",\n... }\n>>> language_property = Property(\n... json_schema={\"title\": \"language\", \"type\": \"string\"}\n... )\n>>> agent = Agent(\n... name=\"Language detector agent\",\n... llm_config=llm_config,\n... system_prompt=(\n... \"Your task is to understand the language spoken by the user.\"\n... \"Please output only the language in lowercase and submit.\"\n... ),\n... outputs=[language_property],\n... )\n>>> start_node = StartNode(name=\"start\")\n>>> english_end_node = EndNode(\n... name=\"english end\", branch_name=languages_to_branch_name[\"english\"]\n... )\n>>> spanish_end_node = EndNode(\n... name=\"spanish end\", branch_name=languages_to_branch_name[\"spanish\"]\n... )\n>>> italian_end_node = EndNode(\n... name=\"italian end\", branch_name=languages_to_branch_name[\"italian\"]\n... )\n>>> unknown_end_node = EndNode(name=\"unknown language end\", branch_name=\"unknown\")\n>>> branching_node = BranchingNode(\n... name=\"language check\",\n... mapping=languages_to_branch_name,\n... inputs=[language_property]\n... )\n>>> agent_node = AgentNode(\n... name=\"User input agent node\",\n... agent=agent,\n... )\n>>> assistant = Flow(\n... name=\"Check access flow\",\n... start_node=start_node,\n... nodes=[\n... start_node,\n... agent_node,\n... branching_node,\n... english_end_node,\n... spanish_end_node,\n... italian_end_node,\n... unknown_end_node,\n... ],\n... control_flow_connections=[\n... ControlFlowEdge(\n... name=\"start_to_agent\", from_node=start_node, to_node=agent_node\n... ),\n... ControlFlowEdge(\n... name=\"agent_to_branching\", from_node=agent_node, to_node=branching_node\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_english_end\",\n... from_node=branching_node,\n... from_branch=languages_to_branch_name[\"english\"],\n... to_node=english_end_node,\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_spanish_end\",\n... from_node=branching_node,\n... from_branch=languages_to_branch_name[\"spanish\"],\n... to_node=spanish_end_node,\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_italian_end\",\n... from_node=branching_node,\n... from_branch=languages_to_branch_name[\"italian\"],\n... to_node=italian_end_node,\n... ),\n... ControlFlowEdge(\n... name=\"branching_to_unknown_end\",\n... from_node=branching_node,\n... from_branch=BranchingNode.DEFAULT_BRANCH,\n... to_node=unknown_end_node,\n... ),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"language_edge\",\n... source_node=agent_node,\n... source_output=\"language\",\n... destination_node=branching_node,\n... destination_input=\"language\",\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"branch_name": {
"default": "next",
"title": "Branch Name",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "EndNode"
}
},
"required": [
"name"
],
"title": "EndNode",
"type": "object",
"x-abstract-component": false
},
"BaseFlow": {
"additionalProperties": false,
"description": "A flow is a component to model sequences of operations to do in a precised order.\n\nThe operations and sequence is defined by the nodes and transitions associated to the flow.\nSteps can be deterministic, or for some use LLMs.\n\nExample\n-------\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.nodes import LlmNode, StartNode, EndNode\n>>> prompt_property = Property(\n... json_schema={\"title\": \"prompt\", \"type\": \"string\"}\n... )\n>>> llm_output_property = Property(\n... json_schema={\"title\": \"llm_output\", \"type\": \"string\"}\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[prompt_property])\n>>> end_node = EndNode(name=\"end\", outputs=[llm_output_property])\n>>> llm_node = LlmNode(\n... name=\"simple llm node\",\n... llm_config=llm_config,\n... prompt_template=\"{{prompt}}\",\n... inputs=[prompt_property],\n... outputs=[llm_output_property],\n... )\n>>> flow = Flow(\n... name=\"Simple prompting flow\",\n... start_node=start_node,\n... nodes=[start_node, llm_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_llm\", from_node=start_node, to_node=llm_node),\n... ControlFlowEdge(name=\"llm_to_end\", from_node=llm_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"prompt_edge\",\n... source_node=start_node,\n... source_output=\"prompt\",\n... destination_node=llm_node,\n... destination_input=\"prompt\",\n... ),\n... DataFlowEdge(\n... name=\"llm_output_edge\",\n... source_node=llm_node,\n... source_output=\"llm_output\",\n... destination_node=end_node,\n... destination_input=\"llm_output\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"start_node": {
"$ref": "#/$defs/Node"
},
"nodes": {
"items": {
"$ref": "#/$defs/Node"
},
"title": "Nodes",
"type": "array"
},
"control_flow_connections": {
"items": {
"$ref": "#/$defs/ControlFlowEdge"
},
"title": "Control Flow Connections",
"type": "array"
},
"data_flow_connections": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/DataFlowEdge"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Data Flow Connections"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "Flow"
}
},
"required": [
"name",
"start_node",
"nodes",
"control_flow_connections"
],
"title": "Flow",
"type": "object",
"x-abstract-component": false
},
"BaseFlowNode": {
"additionalProperties": false,
"description": "The flow node executes a subflow as part of a flow.\n\n- **Inputs**\n Inferred from the inner structure. It's the sets of inputs\n required by the StartNode of the inner flow.\n- **Outputs**\n Inferred from the inner structure. It's the union of the\n sets of outputs exposed by the EndNodes of the inner flow.\n- **Branches**\n Inferred from the inner flow, one per each different value of the attribute\n ``branch_name`` of the nodes of type EndNode in the inner flow.\n\nExample\n-------\nThe ``FlowNode`` is particularly suitable when subflows can be reused inside a project.\nLet's see an example with a flow that estimates numerical value\nusing the \"wisdowm of the crowd\" effect:\n\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.nodes import MapNode, LlmNode, ToolNode, StartNode, EndNode\n>>> from pyagentspec.tools import ServerTool\n>>> duplication_tool = ServerTool(\n... name=\"duplication_tool\",\n... description=\"\",\n... inputs=[\n... Property(\n... json_schema={\"title\": \"element\", \"description\": \"\", \"type\": \"string\"}\n... ),\n... Property(\n... json_schema={\"title\": \"n\", \"description\": \"\", \"type\": \"integer\"}\n... ),\n... ],\n... outputs=[\n... Property(\n... json_schema={\n... \"title\": \"flow_iterable_queries\",\n... \"type\": \"array\",\n... \"items\": {\"type\": \"string\"}\n... },\n... )\n... ],\n... )\n>>> reduce_tool = ServerTool(\n... name=\"reduce_tool\",\n... description=\"\",\n... inputs=[\n... Property(\n... json_schema={\"title\": \"elements\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}\n... ),\n... ],\n... outputs=[Property(json_schema={\"title\": \"flow_processed_query\", \"type\": \"string\"})],\n... )\n>>> # Defining a simple prompt\n>>> REASONING_PROMPT_TEMPLATE = '''Provide your best numerical estimate for: {{user_input}}\n... Your answer should be a single number.\n... Do not include any units, reasoning, or extra text.'''\n>>> # Defining the subflow for the map step\n>>> user_input_property = Property(\n... json_schema={\"title\": \"user_input\", \"type\": \"string\"}\n... )\n>>> flow_processed_query_property = Property(\n... json_schema={\"title\": \"flow_processed_query\", \"type\": \"string\"}\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[user_input_property])\n>>> end_node = EndNode(name=\"end\", outputs=[flow_processed_query_property])\n>>> llm_node = LlmNode(\n... name=\"reasoning llm node\",\n... llm_config=llm_config,\n... prompt_template=REASONING_PROMPT_TEMPLATE,\n... inputs=[user_input_property],\n... outputs=[flow_processed_query_property],\n... )\n>>> inner_map_flow = Flow(\n... name=\"Map flow\",\n... start_node=start_node,\n... nodes=[start_node, llm_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_llm\", from_node=start_node, to_node=llm_node),\n... ControlFlowEdge(name=\"llm_to_end\", from_node=llm_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"query_edge\",\n... source_node=start_node,\n... source_output=\"user_input\",\n... destination_node=llm_node,\n... destination_input=\"user_input\",\n... ),\n... DataFlowEdge(\n... name=\"search_results_edge\",\n... source_node=llm_node,\n... source_output=\"flow_processed_query\",\n... destination_node=end_node,\n... destination_input=\"flow_processed_query\"\n... ),\n... ],\n... )\n>>> user_query_property = Property(\n... json_schema={\"title\": \"user_query\", \"type\": \"string\"}\n... )\n>>> n_repeat_property = Property(\n... json_schema={\"title\": \"n_repeat\", \"type\": \"integer\"}\n... )\n>>> flow_iterable_queries_property = Property(\n... json_schema={\n... \"title\": \"iterated_user_input\",\n... \"type\": \"array\",\n... \"items\": {\"type\": \"string\"},\n... }\n... )\n>>> flow_processed_queries_property = Property(\n... json_schema={\n... \"title\": \"collected_flow_processed_query\",\n... \"type\": \"array\",\n... \"items\": {\"type\": \"string\"},\n... }\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[user_query_property, n_repeat_property])\n>>> end_node = EndNode(name=\"end\", outputs=[flow_processed_query_property])\n>>> duplication_node = ToolNode(\n... name=\"duplication_tool node\",\n... tool=duplication_tool,\n... )\n>>> reduce_node = ToolNode(\n... name=\"reduce_tool node\",\n... tool=reduce_tool,\n... )\n>>> map_node = MapNode(\n... name=\"map node\",\n... subflow=inner_map_flow,\n... inputs=[flow_iterable_queries_property],\n... outputs=[flow_processed_queries_property],\n... )\n>>> mapreduce_flow = Flow(\n... name=\"Map-reduce flow\",\n... start_node=start_node,\n... nodes=[start_node, duplication_node, map_node, reduce_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(\n... name=\"start_to_duplication\", from_node=start_node, to_node=duplication_node\n... ),\n... ControlFlowEdge(\n... name=\"duplication_to_map\", from_node=duplication_node, to_node=map_node\n... ),\n... ControlFlowEdge(name=\"map_to_reduce\", from_node=map_node, to_node=reduce_node),\n... ControlFlowEdge(name=\"reduce_to_end\", from_node=reduce_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"query_edge\",\n... source_node=start_node,\n... source_output=\"user_query\",\n... destination_node=duplication_node,\n... destination_input=\"element\",\n... ),\n... DataFlowEdge(\n... name=\"n_repeat_edge\",\n... source_node=start_node,\n... source_output=\"n_repeat\",\n... destination_node=duplication_node,\n... destination_input=\"n\",\n... ),\n... DataFlowEdge(\n... name=\"flow_iterables_edge\",\n... source_node=duplication_node,\n... source_output=\"flow_iterable_queries\",\n... destination_node=map_node,\n... destination_input=\"iterated_user_input\",\n... ),\n... DataFlowEdge(\n... name=\"flow_processed_queries_edge\",\n... source_node=map_node,\n... source_output=\"collected_flow_processed_query\",\n... destination_node=reduce_node,\n... destination_input=\"elements\",\n... ),\n... DataFlowEdge(\n... name=\"flow_processed_query_edge\",\n... source_node=reduce_node,\n... source_output=\"flow_processed_query\",\n... destination_node=end_node,\n... destination_input=\"flow_processed_query\",\n... ),\n... ],\n... )\n\nOnce the subflow is created we can simply integrate it with the ``FlowNode``:\n\n>>> from pyagentspec.flows.nodes import FlowNode, AgentNode\n>>> from pyagentspec.agent import Agent\n>>> start_node = StartNode(name=\"start\")\n>>> end_node = EndNode(name=\"end\", outputs=[flow_processed_query_property])\n>>> flow_node = FlowNode(name=\"flow node\", subflow=mapreduce_flow)\n>>> agent = Agent(\n... name=\"User interaction agent\",\n... llm_config=llm_config,\n... system_prompt=(\n... \"Your task is to gather from the user the query and the number of times \"\n... \"it should be asked to an LLM. Once you have this information, submit and exit.\"\n... ),\n... outputs=[user_query_property, n_repeat_property],\n... )\n>>> agent_node = AgentNode(name=\"flow node\", agent=agent)\n>>> flow = Flow(\n... name=\"Map flow\",\n... start_node=start_node,\n... nodes=[start_node, agent_node, flow_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_agent\", from_node=start_node, to_node=agent_node),\n... ControlFlowEdge(name=\"agent_to_flow\", from_node=agent_node, to_node=flow_node),\n... ControlFlowEdge(name=\"flow_to_end\", from_node=flow_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"query_edge\",\n... source_node=agent_node,\n... source_output=\"user_query\",\n... destination_node=flow_node,\n... destination_input=\"user_query\",\n... ),\n... DataFlowEdge(\n... name=\"n_rep_edge\",\n... source_node=agent_node,\n... source_output=\"n_repeat\",\n... destination_node=flow_node,\n... destination_input=\"n_repeat\"\n... ),\n... DataFlowEdge(\n... name=\"n_rep_edge\",\n... source_node=flow_node,\n... source_output=\"flow_processed_query\",\n... destination_node=end_node,\n... destination_input=\"flow_processed_query\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"subflow": {
"$ref": "#/$defs/Flow"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "FlowNode"
}
},
"required": [
"name",
"subflow"
],
"title": "FlowNode",
"type": "object",
"x-abstract-component": false
},
"BaseInputMessageNode": {
"additionalProperties": false,
"description": "This node interrupts the execution of the flow in order to wait for a user input, and restarts after receiving it.\nAn agent message, if given, is appended to the conversation before waiting for input.\nUser input is appended to the conversation as a user message, and it is returned as a string property from the node.\n\n- **Inputs**\n One per variable in the message\n- **Outputs**\n One string property that represents the content of the input user message.\n- **Branches**\n One, the default next.\n\nExamples\n--------\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import StartNode, EndNode, InputMessageNode, OutputMessageNode, LlmNode\n>>> from pyagentspec.property import StringProperty\n>>> start_node = StartNode(name=\"start\")\n>>> prompt_node = OutputMessageNode(name=\"ask_input\", message=\"What is the paragraph you want to rephrase?\")\n>>> input_node = InputMessageNode(name=\"user_input\", outputs=[StringProperty(title=\"user_input\")])\n>>> llm_node = LlmNode(\n... name=\"rephrase\",\n... llm_config=llm_config,\n... prompt_template=\"Rephrase {{user_input}}\",\n... outputs=[StringProperty(title=\"rephrased_user_input\")],\n... )\n>>> output_node = OutputMessageNode(name=\"ask_input\", message=\"{{rephrased_user_input}}\")\n>>> end_node = EndNode(name=\"end\")\n>>> flow = Flow(\n... name=\"rephrase_paragraph_flow\",\n... start_node=start_node,\n... nodes=[start_node, prompt_node, input_node, llm_node, output_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"ce1\", from_node=start_node, to_node=prompt_node),\n... ControlFlowEdge(name=\"ce2\", from_node=prompt_node, to_node=input_node),\n... ControlFlowEdge(name=\"ce3\", from_node=input_node, to_node=llm_node),\n... ControlFlowEdge(name=\"ce4\", from_node=llm_node, to_node=output_node),\n... ControlFlowEdge(name=\"ce5\", from_node=output_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"de1\",\n... source_node=input_node,\n... source_output=\"user_input\",\n... destination_node=llm_node,\n... destination_input=\"user_input\",\n... ),\n... DataFlowEdge(\n... name=\"de2\",\n... source_node=llm_node,\n... source_output=\"rephrased_user_input\",\n... destination_node=output_node,\n... destination_input=\"rephrased_user_input\",\n... ),\n... ]\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Message"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "InputMessageNode"
}
},
"required": [
"name"
],
"title": "InputMessageNode",
"type": "object",
"x-abstract-component": false
},
"BaseLlmConfig": {
"anyOf": [
{
"$ref": "#/$defs/OpenAiConfig"
},
{
"$ref": "#/$defs/OllamaConfig"
},
{
"$ref": "#/$defs/OpenAiCompatibleConfig"
},
{
"$ref": "#/$defs/VllmConfig"
},
{
"$ref": "#/$defs/OciGenAiConfig"
}
],
"x-abstract-component": true
},
"BaseLlmNode": {
"additionalProperties": false,
"description": "Execute a prompt template with a given LLM.\n\nThis node is intended to be a part of a Flow.\n\n- **Inputs**\n One per placeholder in the prompt template.\n- **Outputs**\n The output text generated by the LLM.\n- **Branches**\n One, the default next.\n\nExample\n-------\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.nodes import LlmNode, StartNode, EndNode\n>>> country_property = Property(\n... json_schema={\"title\": \"country\", \"type\": \"string\"}\n... )\n>>> capital_property = Property(\n... json_schema={\"title\": \"capital\", \"type\": \"string\"}\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[country_property])\n>>> end_node = EndNode(name=\"end\", outputs=[capital_property])\n>>> llm_node = LlmNode(\n... name=\"simple llm node\",\n... llm_config=llm_config,\n... prompt_template=\"What is the capital of {{ country }}?\",\n... inputs=[country_property],\n... outputs=[capital_property],\n... )\n>>> flow = Flow(\n... name=\"Get the country's capital flow\",\n... start_node=start_node,\n... nodes=[start_node, llm_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_llm\", from_node=start_node, to_node=llm_node),\n... ControlFlowEdge(name=\"llm_to_end\", from_node=llm_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"country_edge\",\n... source_node=start_node,\n... source_output=\"country\",\n... destination_node=llm_node,\n... destination_input=\"country\",\n... ),\n... DataFlowEdge(\n... name=\"capital_edge\",\n... source_node=llm_node,\n... source_output=\"capital\",\n... destination_node=end_node,\n... destination_input=\"capital\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"llm_config": {
"$ref": "#/$defs/LlmConfig"
},
"prompt_template": {
"title": "Prompt Template",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "LlmNode"
}
},
"required": [
"name",
"llm_config",
"prompt_template"
],
"title": "LlmNode",
"type": "object",
"x-abstract-component": false
},
"BaseMCPTool": {
"additionalProperties": false,
"description": "Class for tools exposed by MCP servers",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"client_transport": {
"$ref": "#/$defs/ClientTransport"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "MCPTool"
}
},
"required": [
"name",
"client_transport"
],
"title": "MCPTool",
"type": "object",
"x-abstract-component": false
},
"BaseMapNode": {
"additionalProperties": false,
"description": "The map node executes a subflow on each element of a given input as part of a flow.\n\n- **Inputs**\n Inferred from the inner structure. It's the sets of inputs\n required by the StartNode of the inner flow.\n The names of the inputs will be the ones of the inner flow,\n complemented with the ``iterated_`` prefix. Their type is\n ``Union[inner_type, List[inner_type]]``, where ``inner_type``\n is the type of the respective input in the inner flow.\n- **Outputs**\n Inferred from the inner structure. It's the union of the\n sets of outputs exposed by the EndNodes of the inner flow,\n combined with the reducer method of each output.\n The names of the outputs will be the ones of the inner flow,\n complemented with the ``collected_`` prefix. Their type depends\n on the ``reduce`` method specified for that output:\n\n - ``List`` of the respective output type in case of ``append``\n - same type of the respective output type in case of ``sum``, ``avg``\n\n- **Branches**\n One, the default next.\n\nExamples\n--------\nIn this example we will create a flow that returns\nan L2-normalized version of a given list of numbers.\n\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import EndNode, StartNode, MapNode, ToolNode\n>>> from pyagentspec.tools import ServerTool\n\nFirst, we define a MapNode that returns the square of all the elements in a list.\nIt will be used to compute the L2-norm.\n\n>>> x_property = Property(json_schema={\"title\": \"x\", \"type\": \"number\"})\n>>> x_square_property = Property(\n... json_schema={\"title\": \"x_square\", \"type\": \"number\"}\n... )\n>>> square_tool = ServerTool(\n... name=\"compute_square_tool\",\n... description=\"Computes the square of a number\",\n... inputs=[x_property],\n... outputs=[x_square_property],\n... )\n>>> list_of_x_property = Property(\n... json_schema={\"title\": \"x_list\", \"type\": \"array\", \"items\": {\"type\": \"number\"}}\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[x_property])\n>>> end_node = EndNode(name=\"end\", outputs=[x_square_property])\n>>> square_tool_node = ToolNode(name=\"square tool node\", tool=square_tool)\n>>> square_number_flow = Flow(\n... name=\"Square number flow\",\n... start_node=start_node,\n... nodes=[start_node, square_tool_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(\n... name=\"start_to_tool\", from_node=start_node, to_node=square_tool_node\n... ),\n... ControlFlowEdge(\n... name=\"tool_to_end\", from_node=square_tool_node, to_node=end_node\n... ),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"x_edge\",\n... source_node=start_node,\n... source_output=\"x\",\n... destination_node=square_tool_node,\n... destination_input=\"x\",\n... ),\n... DataFlowEdge(\n... name=\"x_square_edge\",\n... source_node=square_tool_node,\n... source_output=\"x_square\",\n... destination_node=end_node,\n... destination_input=\"x_square\",\n... ),\n... ],\n... )\n>>> list_of_x_square_property = Property(\n... json_schema={\"title\": \"x_square_list\", \"type\": \"array\", \"items\": {\"type\": \"number\"}}\n... )\n>>> square_numbers_map_node = MapNode(\n... name=\"square number map node\",\n... subflow=square_number_flow,\n... )\n\nNow we define the MapNode responsible for normalizing the given list of input numbers.\nThe denominator is the same for all of the numbers,\nwe are going to map only the numerators (i.e., the input numbers).\n\n>>> numerator_property = Property(\n... json_schema={\"title\": \"numerator\", \"type\": \"number\"}\n... )\n>>> denominator_property = Property(\n... json_schema={\"title\": \"denominator\", \"type\": \"number\"}\n... )\n>>> result_property = Property(\n... json_schema={\"title\": \"result\", \"type\": \"number\"}\n... )\n>>> division_tool = ServerTool(\n... name=\"division_tool\",\n... description=\"Computes the ratio between two numbers\",\n... inputs=[numerator_property, denominator_property],\n... outputs=[result_property],\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[numerator_property, denominator_property])\n>>> end_node = EndNode(name=\"end\", outputs=[result_property])\n>>> divide_node = ToolNode(name=\"divide node\", tool=division_tool)\n>>> normalize_flow = Flow(\n... name=\"Normalize flow\",\n... start_node=start_node,\n... nodes=[start_node, divide_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_tool\", from_node=start_node, to_node=divide_node),\n... ControlFlowEdge(name=\"tool_to_end\", from_node=divide_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"numerator_edge\",\n... source_node=start_node,\n... source_output=\"numerator\",\n... destination_node=divide_node,\n... destination_input=\"numerator\",\n... ),\n... DataFlowEdge(\n... name=\"denominator_edge\",\n... source_node=start_node,\n... source_output=\"denominator\",\n... destination_node=divide_node,\n... destination_input=\"denominator\",\n... ),\n... DataFlowEdge(\n... name=\"result_edge\",\n... source_node=divide_node,\n... source_output=\"result\",\n... destination_node=end_node,\n... destination_input=\"result\",\n... ),\n... ],\n... )\n\nFinally, we define the overall flow:\n\n- The list of inputs is squared\n- The squared list is summed and root squared\n- The list of inputs is normalized based on the outcomes of the previous 2 steps\n\n>>> squared_sum_property = Property(\n... json_schema={\"title\": \"squared_sum\", \"type\": \"number\"}\n... )\n>>> normalized_list_of_x_property = Property(\n... json_schema={\n... \"title\": \"x_list_normalized\",\n... \"type\": \"array\",\n... \"items\": {\"type\": \"number\"},\n... }\n... )\n>>> normalize_map_node = MapNode(\n... name=\"normalize map node\",\n... subflow=normalize_flow,\n... )\n>>> squared_sum_tool = ServerTool(\n... name=\"squared_sum_tool\",\n... description=\"Computes the squared sum of a list of numbers\",\n... inputs=[list_of_x_property],\n... outputs=[squared_sum_property],\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[list_of_x_property])\n>>> end_node = EndNode(name=\"end\", outputs=[normalized_list_of_x_property])\n>>> squared_sum_tool_node = ToolNode(name=\"squared sum tool node\", tool=squared_sum_tool)\n>>> flow = Flow(\n... name=\"L2 normalize flow\",\n... start_node=start_node,\n... nodes=[\n... start_node,\n... square_numbers_map_node,\n... squared_sum_tool_node,\n... normalize_map_node,\n... end_node,\n... ],\n... control_flow_connections=[\n... ControlFlowEdge(\n... name=\"start_to_square_numbers\",\n... from_node=start_node,\n... to_node=square_numbers_map_node\n... ),\n... ControlFlowEdge(\n... name=\"square_numbers_to_squared_sum_tool\",\n... from_node=square_numbers_map_node,\n... to_node=squared_sum_tool_node\n... ),\n... ControlFlowEdge(\n... name=\"squared_sum_tool_to_normalize\",\n... from_node=squared_sum_tool_node,\n... to_node=normalize_map_node\n... ),\n... ControlFlowEdge(\n... name=\"normalize_to_end\",\n... from_node=normalize_map_node,\n... to_node=end_node\n... ),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"list_of_x_edge\",\n... source_node=start_node,\n... source_output=\"x_list\",\n... destination_node=square_numbers_map_node,\n... destination_input=\"iterated_x\",\n... ),\n... DataFlowEdge(\n... name=\"x_square_list_edge\",\n... source_node=square_numbers_map_node,\n... source_output=\"collected_x_square\",\n... destination_node=squared_sum_tool_node,\n... destination_input=\"x_list\",\n... ),\n... DataFlowEdge(\n... name=\"numerator_edge\",\n... source_node=start_node,\n... source_output=\"x_list\",\n... destination_node=normalize_map_node,\n... destination_input=\"iterated_numerator\",\n... ),\n... DataFlowEdge(\n... name=\"denominator_edge\",\n... source_node=squared_sum_tool_node,\n... source_output=\"squared_sum\",\n... destination_node=normalize_map_node,\n... destination_input=\"iterated_denominator\",\n... ),\n... DataFlowEdge(\n... name=\"x_list_normalized_edge\",\n... source_node=normalize_map_node,\n... source_output=\"collected_result\",\n... destination_node=end_node,\n... destination_input=\"x_list_normalized\",\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"subflow": {
"$ref": "#/$defs/Flow"
},
"reducers": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/$defs/ReductionMethod"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Reducers"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "MapNode"
}
},
"required": [
"name",
"subflow"
],
"title": "MapNode",
"type": "object",
"x-abstract-component": false
},
"BaseNode": {
"anyOf": [
{
"$ref": "#/$defs/ApiNode"
},
{
"$ref": "#/$defs/OutputMessageNode"
},
{
"$ref": "#/$defs/MapNode"
},
{
"$ref": "#/$defs/StartNode"
},
{
"$ref": "#/$defs/EndNode"
},
{
"$ref": "#/$defs/AgentNode"
},
{
"$ref": "#/$defs/LlmNode"
},
{
"$ref": "#/$defs/ToolNode"
},
{
"$ref": "#/$defs/BranchingNode"
},
{
"$ref": "#/$defs/InputMessageNode"
},
{
"$ref": "#/$defs/FlowNode"
}
],
"x-abstract-component": true
},
"BaseOciAgent": {
"additionalProperties": false,
"description": "An agent is a component that can do several rounds of conversation to solve a task.\n\nThe agent is defined on the OCI console and this is only a wrapper to connect to it.\nIt can be executed by itself, or be executed in a flow using an AgentNode.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"agent_endpoint_id": {
"title": "Agent Endpoint Id",
"type": "string"
},
"client_config": {
"$ref": "#/$defs/OciClientConfig"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciAgent"
}
},
"required": [
"name",
"agent_endpoint_id",
"client_config"
],
"title": "OciAgent",
"type": "object",
"x-abstract-component": false
},
"BaseOciClientConfig": {
"anyOf": [
{
"$ref": "#/$defs/OciClientConfigWithApiKey"
},
{
"$ref": "#/$defs/OciClientConfigWithInstancePrincipal"
},
{
"$ref": "#/$defs/OciClientConfigWithResourcePrincipal"
},
{
"$ref": "#/$defs/OciClientConfigWithSecurityToken"
}
],
"x-abstract-component": true
},
"BaseOciClientConfigWithApiKey": {
"additionalProperties": false,
"description": "OCI client config class for authentication using API_KEY and a config file.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"service_endpoint": {
"title": "Service Endpoint",
"type": "string"
},
"auth_type": {
"const": "API_KEY",
"default": "API_KEY",
"title": "Auth Type",
"type": "string"
},
"auth_profile": {
"title": "Auth Profile",
"type": "string"
},
"auth_file_location": {
"title": "Auth File Location",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciClientConfigWithApiKey"
}
},
"required": [
"name",
"service_endpoint",
"auth_profile",
"auth_file_location"
],
"title": "OciClientConfigWithApiKey",
"type": "object",
"x-abstract-component": false
},
"BaseOciClientConfigWithInstancePrincipal": {
"additionalProperties": false,
"description": "OCI client config class for authentication using INSTANCE_PRINCIPAL.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"service_endpoint": {
"title": "Service Endpoint",
"type": "string"
},
"auth_type": {
"const": "INSTANCE_PRINCIPAL",
"default": "INSTANCE_PRINCIPAL",
"title": "Auth Type",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciClientConfigWithInstancePrincipal"
}
},
"required": [
"name",
"service_endpoint"
],
"title": "OciClientConfigWithInstancePrincipal",
"type": "object",
"x-abstract-component": false
},
"BaseOciClientConfigWithResourcePrincipal": {
"additionalProperties": false,
"description": "OCI client config class for authentication using RESOURCE_PRINCIPAL.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"service_endpoint": {
"title": "Service Endpoint",
"type": "string"
},
"auth_type": {
"const": "RESOURCE_PRINCIPAL",
"default": "RESOURCE_PRINCIPAL",
"title": "Auth Type",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciClientConfigWithResourcePrincipal"
}
},
"required": [
"name",
"service_endpoint"
],
"title": "OciClientConfigWithResourcePrincipal",
"type": "object",
"x-abstract-component": false
},
"BaseOciClientConfigWithSecurityToken": {
"additionalProperties": false,
"description": "OCI client config class for authentication using SECURITY_TOKEN.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"service_endpoint": {
"title": "Service Endpoint",
"type": "string"
},
"auth_type": {
"const": "SECURITY_TOKEN",
"default": "SECURITY_TOKEN",
"title": "Auth Type",
"type": "string"
},
"auth_profile": {
"title": "Auth Profile",
"type": "string"
},
"auth_file_location": {
"title": "Auth File Location",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciClientConfigWithSecurityToken"
}
},
"required": [
"name",
"service_endpoint",
"auth_profile",
"auth_file_location"
],
"title": "OciClientConfigWithSecurityToken",
"type": "object",
"x-abstract-component": false
},
"BaseOciGenAiConfig": {
"additionalProperties": false,
"description": "Class to configure a connection to a OCI GenAI hosted model.\n\nRequires to specify the model id and the client configuration to the OCI GenAI service.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"default_generation_parameters": {
"anyOf": [
{
"$ref": "#/$defs/LlmGenerationConfig"
},
{
"type": "null"
}
],
"default": null
},
"model_id": {
"title": "Model Id",
"type": "string"
},
"compartment_id": {
"title": "Compartment Id",
"type": "string"
},
"serving_mode": {
"$ref": "#/$defs/ServingMode",
"default": "ON_DEMAND"
},
"provider": {
"anyOf": [
{
"$ref": "#/$defs/ModelProvider"
},
{
"type": "null"
}
],
"default": null
},
"client_config": {
"$ref": "#/$defs/OciClientConfig"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OciGenAiConfig"
}
},
"required": [
"name",
"model_id",
"compartment_id",
"client_config"
],
"title": "OciGenAiConfig",
"type": "object",
"x-abstract-component": false
},
"BaseOllamaConfig": {
"additionalProperties": false,
"description": "Class to configure a connection to a local model ran with Ollama.\n\nRequires to specify the url and port at which the model is running.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"default_generation_parameters": {
"anyOf": [
{
"$ref": "#/$defs/LlmGenerationConfig"
},
{
"type": "null"
}
],
"default": null
},
"url": {
"title": "Url",
"type": "string"
},
"model_id": {
"title": "Model Id",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OllamaConfig"
}
},
"required": [
"name",
"url",
"model_id"
],
"title": "OllamaConfig",
"type": "object",
"x-abstract-component": false
},
"BaseOpenAiAgent": {
"additionalProperties": false,
"description": "An agent is a component that can do several rounds of conversation to solve a task.\n\nThe agent is defined on the OCI console and this is only a wrapper to connect to it.\nIt can be executed by itself, or be executed in a flow using an AgentNode.\n\n.. warning::\n ``OpenAiAgent`` is currently in beta and may undergo significant changes.\n The API and behaviour are not guaranteed to be stable and may change in future versions.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"llm_config": {
"$ref": "#/$defs/OpenAiConfig"
},
"remote_agent_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Remote Agent Id"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OpenAiAgent"
}
},
"required": [
"name",
"llm_config"
],
"title": "OpenAiAgent",
"type": "object",
"x-abstract-component": false
},
"BaseOpenAiCompatibleConfig": {
"anyOf": [
{
"$ref": "#/$defs/VllmConfig"
},
{
"$ref": "#/$defs/OllamaConfig"
},
{
"additionalProperties": false,
"description": "Class to configure a connection to an LLM that is compatible with OpenAI completions APIs.\n\nRequires to specify the url of the APIs to contact.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"default_generation_parameters": {
"anyOf": [
{
"$ref": "#/$defs/LlmGenerationConfig"
},
{
"type": "null"
}
],
"default": null
},
"url": {
"title": "Url",
"type": "string"
},
"model_id": {
"title": "Model Id",
"type": "string"
}
},
"required": [
"name",
"url",
"model_id"
],
"title": "OpenAiCompatibleConfig",
"type": "object"
}
],
"x-abstract-component": false
},
"BaseOpenAiConfig": {
"additionalProperties": false,
"description": "Class to configure a connection to a OpenAI LLM.\n\nRequires to specify the identity of the model to use.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"default_generation_parameters": {
"anyOf": [
{
"$ref": "#/$defs/LlmGenerationConfig"
},
{
"type": "null"
}
],
"default": null
},
"model_id": {
"title": "Model Id",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OpenAiConfig"
}
},
"required": [
"name",
"model_id"
],
"title": "OpenAiConfig",
"type": "object",
"x-abstract-component": false
},
"BaseOutputMessageNode": {
"additionalProperties": false,
"description": "This node appends an agent message to the ongoing flow conversation.\n\n- **Inputs**\n One per variable in the message.\n- **Outputs**\n No outputs.\n- **Branches**\n One, the default next.\n\nExamples\n--------\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import StartNode, EndNode, InputMessageNode, OutputMessageNode, LlmNode\n>>> from pyagentspec.property import StringProperty\n>>> start_node = StartNode(name=\"start\")\n>>> prompt_node = OutputMessageNode(name=\"ask_input\", message=\"What is the paragraph you want to rephrase?\")\n>>> input_node = InputMessageNode(name=\"user_input\", outputs=[StringProperty(title=\"user_input\")])\n>>> llm_node = LlmNode(\n... name=\"rephrase\",\n... llm_config=llm_config,\n... prompt_template=\"Rephrase {{user_input}}\",\n... outputs=[StringProperty(title=\"rephrased_user_input\")],\n... )\n>>> output_node = OutputMessageNode(name=\"ask_input\", message=\"{{rephrased_user_input}}\")\n>>> end_node = EndNode(name=\"end\")\n>>> flow = Flow(\n... name=\"rephrase_paragraph_flow\",\n... start_node=start_node,\n... nodes=[start_node, prompt_node, input_node, llm_node, output_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"ce1\", from_node=start_node, to_node=prompt_node),\n... ControlFlowEdge(name=\"ce2\", from_node=prompt_node, to_node=input_node),\n... ControlFlowEdge(name=\"ce3\", from_node=input_node, to_node=llm_node),\n... ControlFlowEdge(name=\"ce4\", from_node=llm_node, to_node=output_node),\n... ControlFlowEdge(name=\"ce5\", from_node=output_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"de1\",\n... source_node=input_node,\n... source_output=\"user_input\",\n... destination_node=llm_node,\n... destination_input=\"user_input\",\n... ),\n... DataFlowEdge(\n... name=\"de2\",\n... source_node=llm_node,\n... source_output=\"rephrased_user_input\",\n... destination_node=output_node,\n... destination_input=\"rephrased_user_input\",\n... ),\n... ]\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"message": {
"title": "Message",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "OutputMessageNode"
}
},
"required": [
"name",
"message"
],
"title": "OutputMessageNode",
"type": "object",
"x-abstract-component": false
},
"BaseRemoteAgent": {
"anyOf": [
{
"$ref": "#/$defs/OciAgent"
},
{
"$ref": "#/$defs/OpenAiAgent"
}
],
"x-abstract-component": true
},
"BaseRemoteTool": {
"additionalProperties": false,
"description": "A tool that is run remotely and called through REST.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"url": {
"title": "Url",
"type": "string"
},
"http_method": {
"title": "Http Method",
"type": "string"
},
"api_spec_uri": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Api Spec Uri"
},
"data": {
"additionalProperties": true,
"title": "Data",
"type": "object"
},
"query_params": {
"additionalProperties": true,
"title": "Query Params",
"type": "object"
},
"headers": {
"additionalProperties": true,
"title": "Headers",
"type": "object"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "RemoteTool"
}
},
"required": [
"name",
"url",
"http_method"
],
"title": "RemoteTool",
"type": "object",
"x-abstract-component": false
},
"BaseRemoteTransport": {
"anyOf": [
{
"$ref": "#/$defs/StreamableHTTPmTLSTransport"
},
{
"$ref": "#/$defs/StreamableHTTPTransport"
},
{
"$ref": "#/$defs/SSETransport"
},
{
"$ref": "#/$defs/SSEmTLSTransport"
}
],
"x-abstract-component": true
},
"BaseSSETransport": {
"anyOf": [
{
"$ref": "#/$defs/SSEmTLSTransport"
},
{
"additionalProperties": false,
"description": "Transport implementation that connects to an MCP server via Server-Sent Events.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"session_parameters": {
"$ref": "#/$defs/SessionParameters"
},
"url": {
"title": "Url",
"type": "string"
},
"headers": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Headers"
}
},
"required": [
"name",
"url"
],
"title": "SSETransport",
"type": "object"
}
],
"x-abstract-component": false
},
"BaseSSEmTLSTransport": {
"additionalProperties": false,
"description": "Transport layer for SSE with mTLS (mutual Transport Layer Security).\n\nThis transport establishes a secure, mutually authenticated TLS connection to the MCP server using client\ncertificates. Production deployments MUST use this transport to ensure both client and server identities\nare verified.\n\nNotes\n-----\n- Users MUST provide a valid client certificate (PEM format) and private key.\n- Users MUST provide (or trust) the correct certificate authority (CA) for the server they're connecting to.\n- The client certificate/key and CA certificate paths can be managed via secrets, config files, or secure\n environment variables in any production system.\n- Executors should ensure that these files are rotated and managed securely.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"session_parameters": {
"$ref": "#/$defs/SessionParameters"
},
"url": {
"title": "Url",
"type": "string"
},
"headers": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Headers"
},
"key_file": {
"title": "Key File",
"type": "string"
},
"cert_file": {
"title": "Cert File",
"type": "string"
},
"ca_file": {
"title": "Ca File",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "SSEmTLSTransport"
}
},
"required": [
"name",
"url",
"key_file",
"cert_file",
"ca_file"
],
"title": "SSEmTLSTransport",
"type": "object",
"x-abstract-component": false
},
"BaseServerTool": {
"additionalProperties": false,
"description": "A tool that is registered to and executed by the orchestrator.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "ServerTool"
}
},
"required": [
"name"
],
"title": "ServerTool",
"type": "object",
"x-abstract-component": false
},
"BaseStartNode": {
"additionalProperties": false,
"description": "Start nodes denote the start of the execution of a flow.\n\n- **Inputs**\n The list of inputs that should be the inputs of the flow. If both input and output\n properties are specified they must be an exact match\n- **Outputs**\n The list of outputs of the step. If both input and output properties are specified they\n must be an exact match\n- **Branches**\n One, the default next.\n\nExamples\n--------\n>>> from pyagentspec.property import Property\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import EndNode, LlmNode, StartNode\n>>> user_question_property = Property(\n... json_schema=dict(\n... title=\"user_question\",\n... description=\"The user question.\",\n... type=\"string\",\n... )\n... )\n>>> answer_property = Property(json_schema=dict(title=\"answer\", type=\"string\"))\n>>> start_node = StartNode(name=\"start\", inputs=[user_question_property])\n>>> end_node = EndNode(name=\"end\", outputs=[answer_property])\n>>> llm_node = LlmNode(\n... name=\"llm node\",\n... prompt_template=\"Answer the user question: {{user_question}}\",\n... llm_config=llm_config,\n... )\n>>> flow = Flow(\n... name=\"flow\",\n... start_node=start_node,\n... nodes=[start_node, llm_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_llm\", from_node=start_node, to_node=llm_node),\n... ControlFlowEdge(name=\"llm_to_end\", from_node=llm_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"query_edge\",\n... source_node=start_node,\n... source_output=\"user_question\",\n... destination_node=llm_node,\n... destination_input=\"user_question\",\n... ),\n... DataFlowEdge(\n... name=\"answer_edge\",\n... source_node=llm_node,\n... source_output=\"generated_text\",\n... destination_node=end_node,\n... destination_input=\"answer\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "StartNode"
}
},
"required": [
"name"
],
"title": "StartNode",
"type": "object",
"x-abstract-component": false
},
"BaseStdioTransport": {
"additionalProperties": false,
"description": "Base transport for connecting to an MCP server via subprocess with stdio.\n\nThis is a base class that can be subclassed for specific command-based\ntransports like Python, Node, Uvx, etc.\n\n.. warning::\n Stdio should be used for local prototyping only.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"session_parameters": {
"$ref": "#/$defs/SessionParameters"
},
"command": {
"title": "Command",
"type": "string"
},
"args": {
"items": {
"type": "string"
},
"title": "Args",
"type": "array"
},
"env": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Env"
},
"cwd": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Cwd"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "StdioTransport"
}
},
"required": [
"name",
"command"
],
"title": "StdioTransport",
"type": "object",
"x-abstract-component": false
},
"BaseStreamableHTTPTransport": {
"anyOf": [
{
"$ref": "#/$defs/StreamableHTTPmTLSTransport"
},
{
"additionalProperties": false,
"description": "Transport implementation that connects to an MCP server via Streamable HTTP.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"session_parameters": {
"$ref": "#/$defs/SessionParameters"
},
"url": {
"title": "Url",
"type": "string"
},
"headers": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Headers"
}
},
"required": [
"name",
"url"
],
"title": "StreamableHTTPTransport",
"type": "object"
}
],
"x-abstract-component": false
},
"BaseStreamableHTTPmTLSTransport": {
"additionalProperties": false,
"description": "Transport layer for streamable HTTP with mTLS (mutual Transport Layer Security).\n\nThis transport establishes a secure, mutually authenticated TLS connection to the MCP server using client\ncertificates. Production deployments MUST use this transport to ensure both client and server identities\nare verified.\n\nNotes\n-----\n- Users MUST provide a valid client certificate (PEM format) and private key.\n- Users MUST provide (or trust) the correct certificate authority (CA) for the server they're connecting to.\n- The client certificate/key and CA certificate paths can be managed via secrets, config files, or secure\n environment variables in any production system.\n- Executors should ensure that these files are rotated and managed securely.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"session_parameters": {
"$ref": "#/$defs/SessionParameters"
},
"url": {
"title": "Url",
"type": "string"
},
"headers": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Headers"
},
"key_file": {
"title": "Key File",
"type": "string"
},
"cert_file": {
"title": "Cert File",
"type": "string"
},
"ca_file": {
"title": "Ca File",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "StreamableHTTPmTLSTransport"
}
},
"required": [
"name",
"url",
"key_file",
"cert_file",
"ca_file"
],
"title": "StreamableHTTPmTLSTransport",
"type": "object",
"x-abstract-component": false
},
"BaseTool": {
"anyOf": [
{
"$ref": "#/$defs/ClientTool"
},
{
"$ref": "#/$defs/ServerTool"
},
{
"$ref": "#/$defs/RemoteTool"
},
{
"$ref": "#/$defs/MCPTool"
}
],
"x-abstract-component": true
},
"BaseToolNode": {
"additionalProperties": false,
"description": "The tool execution node is a node that will execute a tool as part of a flow.\n\n- **Inputs**\n Inferred from the definition of the tool to execute.\n- **Outputs**\n Inferred from the definition of the tool to execute.\n- **Branches**\n One, the default next.\n\nExamples\n--------\n>>> from pyagentspec.flows.edges import ControlFlowEdge, DataFlowEdge\n>>> from pyagentspec.flows.flow import Flow\n>>> from pyagentspec.flows.nodes import ToolNode, StartNode, EndNode\n>>> from pyagentspec.tools import ServerTool\n>>> from pyagentspec.property import Property\n>>>\n>>> x_property = Property(json_schema={\"title\": \"x\", \"type\": \"number\"})\n>>> x_square_root_property = Property(\n... json_schema={\"title\": \"x_square_root\", \"type\": \"number\"}\n... )\n>>> square_root_tool = ServerTool(\n... name=\"compute_square_root\",\n... description=\"Computes the square root of a number\",\n... inputs=[x_property],\n... outputs=[x_square_root_property],\n... )\n>>> start_node = StartNode(name=\"start\", inputs=[x_property])\n>>> end_node = EndNode(name=\"end\", outputs=[x_square_root_property])\n>>> tool_node = ToolNode(name=\"\", tool=square_root_tool)\n>>> flow = Flow(\n... name=\"Compute square root flow\",\n... start_node=start_node,\n... nodes=[start_node, tool_node, end_node],\n... control_flow_connections=[\n... ControlFlowEdge(name=\"start_to_tool\", from_node=start_node, to_node=tool_node),\n... ControlFlowEdge(name=\"tool_to_end\", from_node=tool_node, to_node=end_node),\n... ],\n... data_flow_connections=[\n... DataFlowEdge(\n... name=\"x_edge\",\n... source_node=start_node,\n... source_output=\"x\",\n... destination_node=tool_node,\n... destination_input=\"x\",\n... ),\n... DataFlowEdge(\n... name=\"x_square_root_edge\",\n... source_node=tool_node,\n... source_output=\"x_square_root\",\n... destination_node=end_node,\n... destination_input=\"x_square_root\"\n... ),\n... ],\n... )",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"inputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Inputs"
},
"outputs": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/Property"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"title": "Outputs"
},
"branches": {
"items": {
"type": "string"
},
"title": "Branches",
"type": "array"
},
"tool": {
"$ref": "#/$defs/Tool"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "ToolNode"
}
},
"required": [
"name",
"tool"
],
"title": "ToolNode",
"type": "object",
"x-abstract-component": false
},
"BaseVllmConfig": {
"additionalProperties": false,
"description": "Class to configure a connection to a vLLM-hosted LLM.\n\nRequires to specify the url at which the instance is running.",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"title": "Name",
"type": "string"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description"
},
"metadata": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Metadata"
},
"default_generation_parameters": {
"anyOf": [
{
"$ref": "#/$defs/LlmGenerationConfig"
},
{
"type": "null"
}
],
"default": null
},
"url": {
"title": "Url",
"type": "string"
},
"model_id": {
"title": "Model Id",
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"component_type": {
"const": "VllmConfig"
}
},
"required": [
"name",
"url",
"model_id"
],
"title": "VllmConfig",
"type": "object",
"x-abstract-component": false
},
"ReferencedComponents": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"$ref": "#/$defs/BaseAgent"
},
{
"$ref": "#/$defs/BaseAgentNode"
},
{
"$ref": "#/$defs/BaseAgenticComponent"
},
{
"$ref": "#/$defs/BaseApiNode"
},
{
"$ref": "#/$defs/BaseBranchingNode"
},
{
"$ref": "#/$defs/BaseClientTool"
},
{
"$ref": "#/$defs/BaseClientTransport"
},
{
"$ref": "#/$defs/BaseComponentWithIO"
},
{
"$ref": "#/$defs/BaseControlFlowEdge"
},
{
"$ref": "#/$defs/BaseDataFlowEdge"
},
{
"$ref": "#/$defs/BaseEndNode"
},
{
"$ref": "#/$defs/BaseFlow"
},
{
"$ref": "#/$defs/BaseFlowNode"
},
{
"$ref": "#/$defs/BaseInputMessageNode"
},
{
"$ref": "#/$defs/BaseLlmConfig"
},
{
"$ref": "#/$defs/BaseLlmNode"
},
{
"$ref": "#/$defs/BaseMCPTool"
},
{
"$ref": "#/$defs/BaseMapNode"
},
{
"$ref": "#/$defs/BaseNode"
},
{
"$ref": "#/$defs/BaseOciAgent"
},
{
"$ref": "#/$defs/BaseOciClientConfig"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithApiKey"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithInstancePrincipal"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithResourcePrincipal"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithSecurityToken"
},
{
"$ref": "#/$defs/BaseOciGenAiConfig"
},
{
"$ref": "#/$defs/BaseOllamaConfig"
},
{
"$ref": "#/$defs/BaseOpenAiAgent"
},
{
"$ref": "#/$defs/BaseOpenAiCompatibleConfig"
},
{
"$ref": "#/$defs/BaseOpenAiConfig"
},
{
"$ref": "#/$defs/BaseOutputMessageNode"
},
{
"$ref": "#/$defs/BaseRemoteAgent"
},
{
"$ref": "#/$defs/BaseRemoteTool"
},
{
"$ref": "#/$defs/BaseRemoteTransport"
},
{
"$ref": "#/$defs/BaseSSETransport"
},
{
"$ref": "#/$defs/BaseSSEmTLSTransport"
},
{
"$ref": "#/$defs/BaseServerTool"
},
{
"$ref": "#/$defs/BaseStartNode"
},
{
"$ref": "#/$defs/BaseStdioTransport"
},
{
"$ref": "#/$defs/BaseStreamableHTTPTransport"
},
{
"$ref": "#/$defs/BaseStreamableHTTPmTLSTransport"
},
{
"$ref": "#/$defs/BaseTool"
},
{
"$ref": "#/$defs/BaseToolNode"
},
{
"$ref": "#/$defs/BaseVllmConfig"
},
{
"$ref": "#/$defs/ComponentReferenceWithNestedReferences"
}
]
}
},
"ComponentReference": {
"type": "object",
"properties": {
"$component_ref": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"$component_ref"
]
},
"ComponentReferenceWithNestedReferences": {
"type": "object",
"properties": {
"$component_ref": {
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
}
},
"additionalProperties": false,
"required": [
"$component_ref",
"$referenced_components"
]
},
"AgentSpecVersionEnum": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
},
"VersionedApiNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseApiNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedClientTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseClientTool"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOpenAiConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedAgenticComponent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgenticComponent"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedRemoteAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteAgent"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedLlmNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseLlmNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciClientConfigWithSecurityToken": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithSecurityToken"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedVllmConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseVllmConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgent"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciClientConfigWithApiKey": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithApiKey"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedLlmConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseLlmConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciClientConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedStreamableHTTPmTLSTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStreamableHTTPmTLSTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOpenAiCompatibleConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiCompatibleConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciAgent"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedAgentNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseAgentNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedMapNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseMapNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedSSETransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseSSETransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOpenAiAgent": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOpenAiAgent"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciClientConfigWithInstancePrincipal": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithInstancePrincipal"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedStdioTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStdioTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedStreamableHTTPTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStreamableHTTPTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOllamaConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOllamaConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedFlow": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseFlow"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedFlowNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseFlowNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedToolNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseToolNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedServerTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseServerTool"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOutputMessageNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOutputMessageNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedRemoteTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteTool"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedStartNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseStartNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedEndNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseEndNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedComponentWithIO": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseComponentWithIO"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseTool"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedMCPTool": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseMCPTool"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedControlFlowEdge": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseControlFlowEdge"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedRemoteTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseRemoteTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedSSEmTLSTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseSSEmTLSTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedDataFlowEdge": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseDataFlowEdge"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedBranchingNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseBranchingNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedInputMessageNode": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseInputMessageNode"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedClientTransport": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseClientTransport"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciGenAiConfig": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciGenAiConfig"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedOciClientConfigWithResourcePrincipal": {
"anyOf": [
{
"$ref": "#/$defs/ComponentReference"
},
{
"$ref": "#/$defs/BaseOciClientConfigWithResourcePrincipal"
}
],
"properties": {
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
}
},
"VersionedComponentReferenceWithNestedReferences": {
"type": "object",
"properties": {
"$component_ref": {
"type": "string"
},
"$referenced_components": {
"$ref": "#/$defs/ReferencedComponents"
},
"agentspec_version": {
"enum": [
"25.4.1"
],
"title": "AgentSpecVersionEnum",
"type": "string"
}
},
"additionalProperties": false,
"required": [
"$component_ref",
"$referenced_components"
]
}
},
"anyOf": [
{
"$ref": "#/$defs/VersionedApiNode"
},
{
"$ref": "#/$defs/VersionedClientTool"
},
{
"$ref": "#/$defs/VersionedOpenAiConfig"
},
{
"$ref": "#/$defs/VersionedAgenticComponent"
},
{
"$ref": "#/$defs/VersionedRemoteAgent"
},
{
"$ref": "#/$defs/VersionedLlmNode"
},
{
"$ref": "#/$defs/VersionedOciClientConfigWithSecurityToken"
},
{
"$ref": "#/$defs/VersionedVllmConfig"
},
{
"$ref": "#/$defs/VersionedAgent"
},
{
"$ref": "#/$defs/VersionedOciClientConfigWithApiKey"
},
{
"$ref": "#/$defs/VersionedLlmConfig"
},
{
"$ref": "#/$defs/VersionedOciClientConfig"
},
{
"$ref": "#/$defs/VersionedStreamableHTTPmTLSTransport"
},
{
"$ref": "#/$defs/VersionedOpenAiCompatibleConfig"
},
{
"$ref": "#/$defs/VersionedOciAgent"
},
{
"$ref": "#/$defs/VersionedAgentNode"
},
{
"$ref": "#/$defs/VersionedMapNode"
},
{
"$ref": "#/$defs/VersionedSSETransport"
},
{
"$ref": "#/$defs/VersionedOpenAiAgent"
},
{
"$ref": "#/$defs/VersionedOciClientConfigWithInstancePrincipal"
},
{
"$ref": "#/$defs/VersionedStdioTransport"
},
{
"$ref": "#/$defs/VersionedStreamableHTTPTransport"
},
{
"$ref": "#/$defs/VersionedOllamaConfig"
},
{
"$ref": "#/$defs/VersionedFlow"
},
{
"$ref": "#/$defs/VersionedFlowNode"
},
{
"$ref": "#/$defs/VersionedToolNode"
},
{
"$ref": "#/$defs/VersionedServerTool"
},
{
"$ref": "#/$defs/VersionedOutputMessageNode"
},
{
"$ref": "#/$defs/VersionedRemoteTool"
},
{
"$ref": "#/$defs/VersionedStartNode"
},
{
"$ref": "#/$defs/VersionedEndNode"
},
{
"$ref": "#/$defs/VersionedNode"
},
{
"$ref": "#/$defs/VersionedComponentWithIO"
},
{
"$ref": "#/$defs/VersionedTool"
},
{
"$ref": "#/$defs/VersionedMCPTool"
},
{
"$ref": "#/$defs/VersionedControlFlowEdge"
},
{
"$ref": "#/$defs/VersionedRemoteTransport"
},
{
"$ref": "#/$defs/VersionedSSEmTLSTransport"
},
{
"$ref": "#/$defs/VersionedDataFlowEdge"
},
{
"$ref": "#/$defs/VersionedBranchingNode"
},
{
"$ref": "#/$defs/VersionedInputMessageNode"
},
{
"$ref": "#/$defs/VersionedClientTransport"
},
{
"$ref": "#/$defs/VersionedOciGenAiConfig"
},
{
"$ref": "#/$defs/VersionedOciClientConfigWithResourcePrincipal"
},
{
"$ref": "#/$defs/VersionedComponentReferenceWithNestedReferences"
}
]
}
Note about serialization of components#
Every Component
is supposed to be serialized with an additional field
called component_type
, which defines what type of component is being described.
The value of component_type
should coincide with the name of the specific component’s class.
Examples of JSON serialization for a few common Components follow.
// VllmConfig serialization
{
"id": "vllm",
"name": "VLLM Model",
"description": null,
"metadata": {},
"default_generation_parameters": {},
"url": "http://url.of.my.vllm",
"model_id": "vllm_model_id",
"component_type": "VllmConfig",
"agentspec_version": "25.4.1"
}
// ServerTool serialization
{
"id": "get_weather_tool",
"name": "get_weather",
"description": "Gets the weather in specified city",
"metadata": {},
"inputs": [
{
"title": "city_name",
"type": "string"
}
],
"outputs": [
{
"title": "forecast",
"type": "string"
}
],
"component_type": "ServerTool",
"agentspec_version": "25.4.1"
}
// Agent serialization
{
"id": "expert_agent_id",
"name": "Adaptive expert agent",
"description": null,
"metadata": {},
"inputs": [
{
"title": "domain_of_expertise",
"type": "string"
}
],
"outputs": [],
"llm_config": {
"id": "llama_model_id",
"name": "Llama 3.1 8B instruct",
"description": null,
"metadata": {},
"default_generation_parameters": {},
"url": "url.of.my.llm.deployment:12345",
"model_id": "meta-llama/Meta-Llama-3.1-8B-Instruct",
"component_type": "VllmConfig"
},
"system_prompt": "You are an expert in {{domain_of_expertise}}. Please help the users with their requests.",
"tools": [],
"component_type": "Agent",
"agentspec_version": "25.4.1"
}
Note about references#
To avoid duplicating the same component serialization in a document, we use references.
For this reason, we need two types for each component in the JSON schema specification of Agent Spec.
For example, Agent
becomes a union to specify that it can be replaced by a reference:
"Agent": {
"anyOf": [
{ "$component_ref": "#/$defs/ComponentReference" },
{ "$component_ref": "#/$defs/RawAgent" }
]
}
The ComponentReference
is the same for every component, and it represents the way component references
are specified according to the Agent Spec language specification.
"ComponentReference": {
"type": "object",
"properties": {
"$component_ref": {"type": "string"}
}
}
RawAgent
is the un-changed version with the exception that some reference like #/$defs/LlmConfig
now are pointing to the type of the schema that can be potentially replaced by a ref
"RawAgent": {
"description": "An agent is a component that can do se.... ",
"properties": { }
}
JSON Example#
Here’s an example of a Flow’s definition in Python, and the respective representation generated in JSON. We use PyAgentSpec in order to define the Agent Spec’s Flow.
Python Flow example
input_1 = FloatProperty(title="Input_1", default=0.2)
input_2 = DictProperty(
title="Input_2",
value_type=StringProperty(),
default={},
)
input_3 = UnionProperty(title="Input_3", any_of=[StringProperty(), FloatProperty()])
output_1 = ListProperty(
title="Output_1",
item_type=ListProperty(
item_type=StringProperty(),
),
)
output_2 = BooleanProperty(title="Output_2", default=True)
output_3 = FloatProperty(title="Output_3", default=1.2)
# VLLMConfig is a subclass of Component, we will define it more in detail later
# This Component does not have input/output schemas, the default should be an empty list
vllm = VllmConfig(
id="99asbdiugjk4b5",
name="LLama 3.1 8b",
description="llama 3.1 config",
model_id="llama3.1-8b-instruct",
url="url.to.my.llm.com/hostedllm:12345",
)
# Node is a subclass of Component, we will define it more in detail later
node_1 = StartNode(id="lniwuebjsdvkc", name="Node 1", inputs=[input_1])
node_2 = LlmNode(
id="nxbcwoiauhbjv",
name="Node 2",
llm_config=vllm,
prompt_template="This is the prompt! {{ Input_2 }} {{ Input_3 }}",
inputs=[input_2, input_3],
outputs=[output_2],
)
node_3 = EndNode(id="724893yhrj", name="Node 3", outputs=[output_2, output_3])
# Control flow edges
control_edge_1 = ControlFlowEdge(
id="nh32tewsaicjkl", name="ctrl_edge_1", from_node=node_1, to_node=node_2
)
control_edge_2 = ControlFlowEdge(
id="28yu3egh", name="ctrl_edge_2", from_node=node_2, to_node=node_3
)
# Data flow edges
data_edge_1 = DataFlowEdge(
id="buhdgsbjmn",
name="data_edge_1",
source_node=node_1,
source_output="Input_1",
destination_node=node_2,
destination_input="Input_3",
)
data_edge_2 = DataFlowEdge(
id="67uyh5423hje",
name="data_edge_2",
source_node=node_2,
source_output="Output_2",
destination_node=node_3,
destination_input="Output_2",
)
data_edge_3 = DataFlowEdge(
id="722njqbakhcsa",
name="data_edge_3",
source_node=node_1,
source_output="Input_1",
destination_node=node_3,
destination_input="Output_3",
)
# Flow is a subclass of Component, we will define it more in detail later
flow = Flow(
id="mmnhagawse",
name="Example test flow",
start_node=node_1,
nodes=[node_1, node_2, node_3],
control_flow_connections=[control_edge_1, control_edge_2],
data_flow_connections=[data_edge_1, data_edge_2, data_edge_3],
inputs=[input_1],
outputs=[output_2, output_3],
)
Flow's representation
{
"component_type": "Flow",
"id": "mmnhagawse",
"name": "Example test flow",
"description": null,
"metadata": {},
"inputs": [
{
"title": "Input_1",
"default": "input_1_default",
"type": "string"
}
],
"outputs": [
{
"title": "Output_2",
"default": true,
"type": "boolean"
},
{
"title": "Output_3",
"default": 1,
"type": "number"
}
],
"start_node": {
"$component_ref": "lniwuebjsdvkc"
},
"nodes": [
{
"$component_ref": "lniwuebjsdvkc"
},
{
"$component_ref": "nxbcwoiauhbjv"
},
{
"$component_ref": "724893yhrj"
}
],
"control_flow_connections": [
{
"component_type": "ControlFlowEdge",
"id": "nh32tewsaicjkl",
"name": "ctrl_edge_1",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "lniwuebjsdvkc"
},
"from_branch": null,
"to_node": {
"$component_ref": "nxbcwoiauhbjv"
}
},
{
"component_type": "ControlFlowEdge",
"id": "28yu3egh",
"name": "ctrl_edge_2",
"description": null,
"metadata": {},
"from_node": {
"$component_ref": "nxbcwoiauhbjv"
},
"from_branch": null,
"to_node": {
"$component_ref": "724893yhrj"
}
}
],
"data_flow_connections": [
{
"component_type": "DataFlowEdge",
"id": "buhdgsbjmn",
"name": "data_edge_1",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "lniwuebjsdvkc"
},
"source_output": "Input_1",
"destination_node": {
"$component_ref": "nxbcwoiauhbjv"
},
"destination_input": "Input_2"
},
{
"component_type": "DataFlowEdge",
"id": "67uyh5423hje",
"name": "data_edge_2",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "nxbcwoiauhbjv"
},
"source_output": "Output_2",
"destination_node": {
"$component_ref": "724893yhrj"
},
"destination_input": "Output_2"
},
{
"component_type": "DataFlowEdge",
"id": "722njqbakhcsa",
"name": "data_edge_3",
"description": null,
"metadata": {},
"source_node": {
"$component_ref": "lniwuebjsdvkc"
},
"source_output": "Input_1",
"destination_node": {
"$component_ref": "724893yhrj"
},
"destination_input": "Output_3"
}
],
"$referenced_components": {
"lniwuebjsdvkc": {
"component_type": "StartNode",
"id": "lniwuebjsdvkc",
"name": "Node 1",
"description": null,
"metadata": {},
"inputs": [
{
"title": "Input_1",
"default": "input_1_default",
"type": "string"
}
],
"outputs": [
{
"title": "Input_1",
"default": "input_1_default",
"type": "string"
}
],
"branches": [
"next"
]
},
"nxbcwoiauhbjv": {
"component_type": "LlmNode",
"id": "nxbcwoiauhbjv",
"name": "Node 2",
"description": null,
"metadata": {},
"inputs": [
{
"title": "Input_2",
"default": {},
"additionalProperties": {
"type": "string"
},
"properties": {},
"type": "object"
},
{
"title": "Input_3",
"type": "string"
}
],
"outputs": [
{
"title": "Output_2",
"default": true,
"type": "boolean"
}
],
"branches": [
"next"
],
"llm_config": {
"component_type": "VllmConfig",
"id": "99asbdiugjk4b5",
"name": "LLama 3.1 8b",
"description": "llama 3.1 config",
"metadata": {},
"default_generation_parameters": {},
"url": "url.to.my.llm.com/hostedllm:12345",
"model_id": "llama3.1-8b-instruct"
},
"prompt_template": "This is the prompt! {{ Input_2 }} {{ Input_3 }}"
},
"724893yhrj": {
"component_type": "EndNode",
"id": "724893yhrj",
"name": "Node 3",
"description": null,
"metadata": {},
"inputs": [
{
"title": "Output_2",
"default": true,
"type": "boolean"
},
{
"title": "Output_3",
"default": 1,
"type": "number"
}
],
"outputs": [
{
"title": "Output_2",
"default": true,
"type": "boolean"
},
{
"title": "Output_3",
"default": 1,
"type": "number"
}
],
"branches": [],
"branch_name": "next"
}
},
"agentspec_version": "25.4.1"
}
SDKs for consuming/producing Agent Spec#
A SDK for Agent Spec would be developed, to guarantee adherence to the specification, as well as providing easy to use APIs to serialize/deserialize Agent Spec representation, or create them from code.
All SDKs should provide the following:
classes to represent components
APIs to help with serialization/deserialization
PyAgentSpec represents the implementation of an Agent Spec SDK in python. The API documentation of PyAgentSpec is available at this link.
Serialization/deserialization APIs#
The serialization/deserialization would be served by the following APIs
class AgentSpecSerializer:
def __init__(self, plugins: Optional[List[ComponentSerializationPlugin]] = None) -> None:
...
def to_json(self, component: Component) -> str:
# gets the JSON string representation for the component
pass
class AgentSpecDeserializer:
def __init__(self, plugins: Optional[List[ComponentDeserializationPlugin]] = None) -> None:
...
def from_json(self, json_content: str) -> Component:
# creates a component, given its JSON string representation
pass
So that it is possible to execute the following code:
# Create a Python object Agent Spec flow
node_1 = StartNode(id="NODE_1", name="node_1")
node_2 = LlmNode(id="NODE_2", name="node_2", prompt_template="Hi!")
end_node = EndNode(id="end_node", name="End node")
control_flow_edges = [
ControlFlowEdge(id="1to2", name="1->2", from_node=node_1, to_node=node_2),
ControlFlowEdge(id="2toend", name="2->end", from_node=node_2, to_node=end_node),
]
flow = Flow(
id="FLOW_1",
name="My Flow",
start_node=node_1,
nodes=[node_1, node_2, end_node],
control_flow_connections=control_flow_edges,
data_flow_connections=[],
)
# Serialize it to JSON
serializer = AgentSpecSerializer()
serialized_flow = serializer.to_json(flow)
and the converse for deserialization.
The documentation of PyAgentSpec serialization is available at this link.