Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c5de46e
feat(metadata): create pydantic model for agent metadata
CasperGN Jan 15, 2026
08b785d
feat(metadata): consume new model for agent metadata
CasperGN Jan 15, 2026
d8a1a61
fix(test): update test cases to support the new pydantic model setup
CasperGN Jan 15, 2026
b35a1e2
feat(schema): add schema generator script
CasperGN Jan 15, 2026
a1981b0
feat(schema): add schema for previous and upcoming version
CasperGN Jan 15, 2026
193c46d
Merge branch 'main' into fix(372)--agent-metadata-model
CasperGN Jan 19, 2026
aee53ec
feat: prepare metadata to be moved to python-sdk
CasperGN Jan 28, 2026
2304c09
chore(format): ruff
CasperGN Jan 28, 2026
db36cff
fix: remove schemas, agentschema model and script to generate new schema
CasperGN Jan 28, 2026
1c76468
chore: remove exports of removed funcs
CasperGN Jan 28, 2026
e5cc7ee
chore: remove imports of removed funcs
CasperGN Jan 28, 2026
e263b4b
fix: call to register for orchestrator and AgentBase
CasperGN Jan 28, 2026
d8ba294
Merge branch 'main' into fix(372)--agent-metadata-model
CasperGN Feb 3, 2026
eb3e06c
fix: correct call to metadata registration
CasperGN Feb 3, 2026
7544751
chore(format): ruff
CasperGN Feb 3, 2026
16da43c
Merge branch 'main' into fix(372)--agent-metadata-model
CasperGN Feb 12, 2026
7e6ccc6
fix: revert metadata back to dapr agents instead of python-sdk
CasperGN Feb 12, 2026
80bcead
feat(metadata): ensure agent deregisters upon shutdown
CasperGN Feb 23, 2026
5d32365
Merge remote-tracking branch 'origin/main' into fix(372)--agent-metad…
CasperGN Feb 23, 2026
ac4142c
fix: pre-commit trim
CasperGN Feb 23, 2026
6c1942c
fix: address pr comments
CasperGN Feb 23, 2026
3ca0ee5
feat(registry): rework agent registry to store agents as individual k…
CasperGN Feb 24, 2026
b92d9fd
chore(format): handle pre-commit
CasperGN Feb 24, 2026
d439001
Merge branch 'main' into fix(372)--agent-metadata-model
sicoyle Feb 24, 2026
152f874
chore: generate new metadata schema for changes
CasperGN Feb 25, 2026
74be3df
chore: pre-commit
CasperGN Feb 25, 2026
c708874
fix: address pr comments
CasperGN Feb 25, 2026
2422028
chore: pre-commit
CasperGN Feb 25, 2026
95a7d46
fix: enure orchestrator isn't hardcoded but rather infered
CasperGN Feb 25, 2026
25d069a
Merge branch 'main' into fix(372)--agent-metadata-model
CasperGN Feb 25, 2026
5bbc8d7
test(ci): include golden-file test for metadata schema. Break build i…
CasperGN Feb 25, 2026
059012c
chore(format): ruff
CasperGN Feb 25, 2026
bad176b
fix: ensure short/long term memory differ, formatting and import clea…
CasperGN Feb 26, 2026
cc83a47
chore(format): pre-commit
CasperGN Feb 26, 2026
f791fbc
fix(ci): ensure correct scoped token
CasperGN Feb 26, 2026
71b235a
fix(ci): we don't have access to the token on a pull_request trigger …
CasperGN Feb 26, 2026
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
10 changes: 9 additions & 1 deletion dapr_agents/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from importlib.metadata import version, PackageNotFoundError
from dapr_agents.agents.standalone import Agent
from dapr_agents.agents.durable import DurableAgent
from dapr_agents.executors import DockerCodeExecutor, LocalCodeExecutor
Expand All @@ -16,6 +17,7 @@
RandomOrchestrator,
RoundRobinOrchestrator,
)
from dapr_agents.agents import AgentMetadataSchema

__all__ = [
"Agent",
Expand All @@ -32,8 +34,14 @@
"OpenAIEmbeddingClient",
"AgentTool",
"tool",
"AgenticWorkflow",
"LLMOrchestrator",
"RandomOrchestrator",
"RoundRobinOrchestrator",
"AgentMetadataSchema",
]

try:
__version__ = version("dapr-agents")
except PackageNotFoundError:
# This should only happen during development
__version__ = "0.0.0.dev0"
22 changes: 21 additions & 1 deletion dapr_agents/agents/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
from .base import AgentBase
from .standalone import Agent
from .durable import DurableAgent
from .schemas import (
AgentMetadataSchema,
AgentMetadata,
LLMMetadata,
ToolMetadata,
RegistryMetadata,
MemoryMetadata,
PubSubMetadata,
)

__all__ = ["AgentBase", "Agent", "DurableAgent"]
__all__ = [
"AgentBase",
"Agent",
"DurableAgent",
"AgentMetadataSchema",
"AgentMetadata",
"LLMMetadata",
"ToolMetadata",
"RegistryMetadata",
"MemoryMetadata",
"PubSubMetadata",
]
160 changes: 86 additions & 74 deletions dapr_agents/agents/base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from __future__ import annotations

import asyncio
from decimal import __version__
import json
import logging
from datetime import datetime, timezone
from importlib.metadata import version, PackageNotFoundError
from typing import Any, Dict, Iterable, List, Optional, Sequence, Union, Coroutine

from dapr.clients import DaprClient
Expand All @@ -13,7 +15,15 @@
StateResponse,
GetBulkSecretResponse,
)

from dapr_agents.agents.schemas import (
AgentMetadataSchema,
RegistryMetadata,
LLMMetadata,
PubSubMetadata,
MemoryMetadata,
ToolMetadata,
AgentMetadata,
)
from dapr_agents.agents.components import AgentComponents
from dapr_agents.agents.configs import (
AgentLoggingExporter,
Expand Down Expand Up @@ -271,6 +281,12 @@ def __init__(
self.instrumentor: Optional[DaprAgentsInstrumentor] = None
self._setup_agent_runtime_configuration()

# -----------------------------
# Registry wiring
# -----------------------------

self._registry = registry

# -----------------------------
# Memory wiring
# -----------------------------
Expand Down Expand Up @@ -353,83 +369,79 @@ def __init__(
# -----------------------------
# Agent metadata & registry registration (from AgentComponents)
# -----------------------------
base_meta: Dict[str, Any] = {}
base_meta["agent"] = {
"appid": self.appid,
"orchestrator": False,
"role": self.profile.role,
"goal": self.profile.goal,
"name": self.profile.name,
"instructions": list(self.profile.instructions),
}

if self.profile.system_prompt:
base_meta["agent"]["system_prompt"] = self.profile.system_prompt

if self.pubsub is not None:
pubsub_meta: Dict[str, Any] = {}
pubsub_meta["agent_name"] = self.agent_topic_name
pubsub_meta["name"] = self.message_bus_name
base_meta["pubsub"] = pubsub_meta

if self.memory:
memory_meta: Dict[str, Any] = {}
memory_meta["type"] = type(self.memory).__name__
if getattr(self.memory, "store_name", None) is not None:
memory_meta["statestore"] = self.memory.store_name
if getattr(self.memory, "session_id", None) is not None:
memory_meta["session_id"] = self.memory.session_id
base_meta["memory"] = memory_meta

if self.llm:
llm_meta: Dict[str, Any] = {}
llm_meta["client"] = type(self.llm).__name__
llm_meta["provider"] = getattr(self.llm, "provider", "unknown")
llm_meta["api"] = getattr(self.llm, "api", "unknown")
llm_meta["model"] = getattr(self.llm, "model", "unknown")
if hasattr(self.llm, "component_name") and self.llm.component_name:
llm_meta["component_name"] = self.llm.component_name
# Include endpoint info (non-sensitive)
if hasattr(self.llm, "base_url") and self.llm.base_url:
llm_meta["base_url"] = self.llm.base_url
if hasattr(self.llm, "azure_endpoint") and self.llm.azure_endpoint:
llm_meta["azure_endpoint"] = self.llm.azure_endpoint
if hasattr(self.llm, "azure_deployment") and self.llm.azure_deployment:
llm_meta["azure_deployment"] = self.llm.azure_deployment
if self.llm.prompt_template is not None:
llm_meta["prompt_template"] = type(self.llm.prompt_template).__name__
if hasattr(self.llm, "prompty") and self.llm.prompty is not None:
llm_meta["prompty"] = self.llm.prompty
base_meta["llm"] = llm_meta

if self.execution:
if (
hasattr(self.execution, "max_iterations")
and self.execution.max_iterations is not None
):
base_meta["max_iterations"] = self.execution.max_iterations
if (
hasattr(self.execution, "tool_choice")
and self.execution.tool_choice is not None
):
base_meta["tool_choice"] = self.execution.tool_choice

if self.tools and len(self.tools) > 0:
tools_list = [
{
"tool_name": tool.name,
"tool_description": tool.description,
"tool_args": tool.args_schema,
}
try:
schema_version = version("dapr-agents")
except PackageNotFoundError:
schema_version = "0.0.0.dev0"

self.agent_metadata: AgentMetadataSchema = AgentMetadataSchema(
schema_version=schema_version,
agent=AgentMetadata(
appid=self.appid if self.appid is not None else "",
type=type(self).__name__,
orchestrator=False,
role=self.profile.role,
goal=self.profile.goal,
name=self.profile.name,
instructions=list(self.profile.instructions),
statestore=self._state.store.store_name
if self._state is not None
else "",
system_prompt=self.profile.system_prompt,
),
name=self.profile.name,
registered_at=datetime.now(timezone.utc).isoformat(),
pubsub=PubSubMetadata(
agent_name=self.agent_topic_name if self.agent_topic_name else "",
name=self.message_bus_name if self.message_bus_name else "",
broadcast_topic=self.broadcast_topic_name
if self.broadcast_topic_name
else "",
agent_topic=self.agent_topic_name if self.agent_topic_name else "",
),
memory=MemoryMetadata(
type=type(self.memory).__name__,
session_id=getattr(self.memory, "session_id", None),
statestore=getattr(self.memory, "store_name", None),
),
llm=LLMMetadata(
client=type(self.llm).__name__,
provider=getattr(self.llm, "provider", "unknown"),
api=getattr(self.llm, "api", "unknown"),
model=getattr(self.llm, "model", "unknown"),
component_name=getattr(self.llm, "component_name", None),
base_url=getattr(self.llm, "base_url", None),
azure_endpoint=getattr(self.llm, "azure_endpoint", None),
azure_deployment=getattr(self.llm, "azure_deployment", None),
prompt_template=type(self.llm.prompt_template).__name__,
prompty=self.llm.prompty
if hasattr(self.llm, "prompty") and self.llm.prompty is not None
else None,
),
registry=RegistryMetadata(
statestore=self._registry.store.store_name
if self._registry is not None
else None,
name=self._registry.team_name if self._registry is not None else None,
),
tools=[
ToolMetadata(
tool_name=tool.name,
tool_description=tool.description,
tool_args=json.dumps(tool.args_schema)
if tool.args_schema
else "{}",
)
for tool in self.tools
]
base_meta["tools"] = tools_list
],
max_iterations=self.execution.max_iterations,
tool_choice=self.execution.tool_choice,
agent_metadata=agent_metadata,
)

merged_meta = {**base_meta, **(agent_metadata or {})}
self.agent_metadata = merged_meta
if self.registry_state is not None:
try:
self.register_agentic_system(metadata=merged_meta)
self.register_agentic_system(metadata=self.agent_metadata)
except StateStoreError:
logger.warning(
"Could not register agent metadata; registry unavailable."
Expand Down
47 changes: 12 additions & 35 deletions dapr_agents/agents/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@
WorkflowGrpcOptions,
StateModelBundle,
)
from dapr_agents.agents.schemas import AgentWorkflowEntry
from dapr_agents.agents.schemas import (
AgentWorkflowEntry,
AgentMetadataSchema,
RegistryMetadata,
LLMMetadata,
PubSubMetadata,
MemoryMetadata,
ToolMetadata,
AgentMetadata,
)
from dapr_agents.storage.daprstores.stateservice import (
StateStoreError,
)
Expand Down Expand Up @@ -459,7 +468,7 @@ def _message_dict_to_message_model(self, message: Dict[str, Any]) -> Any:
def register_agentic_system(
self,
*,
metadata: Optional[Dict[str, Any]] = None,
metadata: Optional[AgentMetadataSchema] = None,
team: Optional[str] = None,
) -> None:
"""
Expand All @@ -475,42 +484,10 @@ def register_agentic_system(
)
return

payload = dict(metadata or {})
payload.setdefault("name", self.name)
if "agent" not in payload:
payload["agent"] = {}

payload["agent"]["type"] = type(self).__name__
payload.setdefault("registered_at", datetime.now(timezone.utc).isoformat())

if self._pubsub is not None:
if "pubsub" not in payload:
payload["pubsub"] = {}

payload["pubsub"]["agent_name"] = self.agent_topic_name
payload["pubsub"]["name"] = self.message_bus_name

if self.broadcast_topic_name:
payload["pubsub"]["broadcast_topic"] = self.broadcast_topic_name
if self._pubsub.agent_topic is not None:
payload["pubsub"]["agent_topic"] = self._pubsub.agent_topic

if self._state is not None:
payload["agent"]["statestore"] = self._state.store.store_name

if self._registry is not None:
if "registry" not in payload:
payload["registry"] = {}

payload["registry"]["statestore"] = self._registry.store.store_name

if self._registry.team_name is not None:
payload["registry"]["team"] = self._registry.team_name

self._upsert_agent_entry(
team=self._effective_team(team),
agent_name=self.name,
agent_metadata=payload,
agent_metadata=metadata.model_dump(mode="json") if metadata else {},
)

def deregister_agentic_system(self, *, team: Optional[str] = None) -> None:
Expand Down
Loading