Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public final class YamlAgentsDocument {

@JsonCreator
public YamlAgentsDocument(
@JsonProperty(value = "agents", required = true) List<AgentSpec> agents,
@JsonProperty("agents") List<AgentSpec> agents,
@JsonProperty("prompts") List<PromptSpec> prompts,
@JsonProperty("tools") List<ToolSpec> tools,
@JsonProperty("skills") List<SkillsSpec> skills,
Expand All @@ -54,7 +54,7 @@ public YamlAgentsDocument(
@JsonProperty("embedding_model_setups") List<DescriptorSpec> embeddingModelSetups,
@JsonProperty("vector_stores") List<DescriptorSpec> vectorStores,
@JsonProperty("mcp_servers") List<DescriptorSpec> mcpServers) {
this.agents = agents;
this.agents = orEmpty(agents);
this.prompts = orEmpty(prompts);
this.tools = orEmpty(tools);
this.skills = orEmpty(skills);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,14 @@ void sharedSectionsAtFileLevel() throws Exception {
assertThat(doc.getActions()).hasSize(1);
assertThat(doc.getActions().get(0).getName()).isEqualTo("shared_a");
}

@Test
void infraOnlyFile() throws Exception {
YamlAgentsDocument doc =
M.readValue(
"chat_model_connections:\n - name: x\n clazz: ollama\n",
YamlAgentsDocument.class);
assertThat(doc.getAgents()).isEmpty();
assertThat(doc.getChatModelConnections()).hasSize(1);
}
}
2 changes: 1 addition & 1 deletion docs/content/docs/development/yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ agentsEnv.loadYaml(Paths.get("./shared.yaml"));

{{< /tabs >}}

A common pattern is to split a topology file (the agents themselves) from an infrastructure file (chat-model connections, vector stores, ...). The infrastructure file can be swapped per environment (dev / staging / prod) without touching the agent definitions.
A common pattern is to split a topology file (the agents themselves) from an infrastructure file (chat-model connections, vector stores, ...). The infrastructure file can be swapped per environment (dev / staging / prod) without touching the agent definitions. The `agents:` block is optional, so an infrastructure-only file (no `agents:` block) is loaded as shared resources.

For an end-to-end runnable walkthrough that loads a YAML-declared agent and runs it on Flink, see [YAML Agent Quickstart]({{< ref "docs/get-started/quickstart/yaml_agent" >}}).

Expand Down
5 changes: 1 addition & 4 deletions docs/yaml-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@
}
},
"additionalProperties": false,
"description": "Top-level YAML document.\n\nAlways wraps one or more agents under ``agents:``. Resources and\nactions declared at the same level as ``agents:`` are shared:\nresources are registered on the environment; actions can be\nreferenced from any agent by name string.",
"description": "Top-level YAML document.\n\nAgents are declared under ``agents:``. The block is optional, so a\nfile may carry only shared infrastructure (chat-model connections,\nvector stores, ...) \u2014 useful for splitting a topology file from an\ninfrastructure file that can be swapped per environment. Resources\nand actions declared at the same level as ``agents:`` are shared:\nresources are registered on the environment; actions can be\nreferenced from any agent by name string.",
"properties": {
"actions": {
"items": {
Expand Down Expand Up @@ -480,9 +480,6 @@
"type": "array"
}
},
"required": [
"agents"
],
"title": "YamlAgentsDocument",
"type": "object"
}
9 changes: 6 additions & 3 deletions python/flink_agents/api/yaml/specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,18 @@ class AgentSpec(BaseModel):
class YamlAgentsDocument(BaseModel):
"""Top-level YAML document.

Always wraps one or more agents under ``agents:``. Resources and
actions declared at the same level as ``agents:`` are shared:
Agents are declared under ``agents:``. The block is optional, so a
file may carry only shared infrastructure (chat-model connections,
vector stores, ...) — useful for splitting a topology file from an
infrastructure file that can be swapped per environment. Resources
and actions declared at the same level as ``agents:`` are shared:
resources are registered on the environment; actions can be
referenced from any agent by name string.
"""

model_config = ConfigDict(extra="forbid")

agents: List[AgentSpec]
agents: List[AgentSpec] = Field(default_factory=list)

prompts: List[PromptSpec] = Field(default_factory=list)
tools: List[ToolSpec] = Field(default_factory=list)
Expand Down
9 changes: 6 additions & 3 deletions python/flink_agents/api/yaml/tests/test_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,12 @@ def test_agent_spec_action_can_be_string_reference() -> None:
assert isinstance(spec.actions[1], ActionSpec)


def test_yaml_document_requires_agents() -> None:
with pytest.raises(ValidationError):
YamlAgentsDocument.model_validate({})
def test_yaml_document_allows_infra_only_file() -> None:
doc = YamlAgentsDocument.model_validate(
{"chat_model_connections": [{"name": "x", "clazz": "ollama"}]}
)
assert doc.agents == []
assert doc.chat_model_connections[0].name == "x"


def test_yaml_document_minimal() -> None:
Expand Down
Loading