Skip to content
Open
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
a5eabde
deps: remove conditions for opentelemetry & obersvability dependencies
CasperGN Dec 18, 2025
672803f
feat: extract secrets and config from agent-secretstore and agent-run…
CasperGN Dec 18, 2025
67ece73
feat: if opentelemetry config found init otel instrumentation of agent
CasperGN Dec 18, 2025
645a28f
chore: formatting
CasperGN Dec 18, 2025
6c814d3
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Dec 18, 2025
cb902cc
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Dec 18, 2025
7203244
chore: remove f string as no variables inputted
CasperGN Dec 18, 2025
83f3049
fix: correct ref to secret
CasperGN Dec 18, 2025
bd16ef2
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Dec 18, 2025
bf6258c
fix: return self.appid after merge-failure
CasperGN Dec 18, 2025
8e8fb54
Merge branch 'main' into feat/310-default-agent-conf
yaron2 Dec 18, 2025
e5662f6
chore: align naming of secret var to conf vars
CasperGN Dec 18, 2025
983f3d1
Update dapr_agents/agents/components.py
CasperGN Dec 18, 2025
ad89bed
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Dec 18, 2025
a48fe82
fix: remove skip_dep_check as it is now redundant
CasperGN Dec 19, 2025
38d4b63
feat: remove conditional checks on deps as they're part of core deps now
CasperGN Dec 19, 2025
3cca6c8
chore: remove skip_dep_check from quickstarts
CasperGN Dec 19, 2025
fa8bcb8
Update dapr_agents/agents/components.py
CasperGN Dec 19, 2025
3ec5d3a
Update dapr_agents/agents/components.py
CasperGN Dec 19, 2025
ffc1745
Update dapr_agents/agents/components.py
CasperGN Dec 19, 2025
7570118
fix: align naming of runtime with rest of components
CasperGN Dec 19, 2025
167427e
chore: formatting
CasperGN Dec 19, 2025
a76bef9
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Dec 19, 2025
146baa3
fix: #336
CasperGN Dec 19, 2025
532e9f2
chore(deps): add dependencies needed for running quickstarts
CasperGN Dec 19, 2025
fdf311f
chore(test): rewire tests to have longer timeouts + naming
CasperGN Dec 19, 2025
57288d8
fix(exception): correctly catch timeout error
CasperGN Dec 19, 2025
c28e3df
chore: formatting
CasperGN Dec 19, 2025
4ef6655
feat: move client auto binding to AgentBase
CasperGN Dec 19, 2025
9391690
fix: ensure all std. components use component.name
CasperGN Dec 19, 2025
c22b7a7
fix: correct placement of config func call
CasperGN Dec 19, 2025
64c3e2e
fix: align naming to proposals in issues
CasperGN Dec 19, 2025
3405c96
feat: handle uninstrument + register self handling of grpc instrumentor
CasperGN Jan 6, 2026
d8d9a9b
fix: ensure closing dapr client and wf client if len of managed agent…
CasperGN Jan 6, 2026
0537b0b
chore: align example with needed setup
CasperGN Jan 6, 2026
b34ae7b
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Jan 7, 2026
5d10d9a
chore(format): ruff
CasperGN Jan 7, 2026
6bda2ef
feat(observability): add agent observability configuration
CasperGN Jan 7, 2026
d274c45
feat(observability): allow passing AgentObservabilityConfig to durabl…
CasperGN Jan 7, 2026
29ac598
feat(observability): allow passing AgentObservabilityConfig to AgentBase
CasperGN Jan 7, 2026
d88a1ca
feat(config): create agent configuration handler for observability wh…
CasperGN Jan 7, 2026
1b5de62
chore(format): ruff
CasperGN Jan 7, 2026
37a019a
feat(observability): use new AgentObservabilityConfig for quickstarter
CasperGN Jan 7, 2026
d6e7f88
fix(resilience): make merging properly resilient with false/true and …
CasperGN Jan 7, 2026
411b684
chore(format): ruff
CasperGN Jan 7, 2026
04a2cd8
fix(regression): return writing appid to metadata for the agent
CasperGN Jan 7, 2026
e0e1bbe
chore(deps): remove support for 3.10, add 3.14. 3.10 does not support…
CasperGN Jan 7, 2026
28cf442
chore(test): create test case for observability setup
CasperGN Jan 7, 2026
bf87816
Merge branch 'main' into feat/310-default-agent-conf
CasperGN Jan 7, 2026
6dccb37
fix(deps): we cannot support 3.14 yet due to dependencies. Numpy and …
CasperGN Jan 7, 2026
94805f3
fix(naming): correct registry name and remove unused import
CasperGN Jan 7, 2026
aa37351
fix(bug): correct order of super and base config to ensure statestore…
CasperGN Jan 7, 2026
c21000b
Update instrumentor.py
CasperGN Jan 7, 2026
ae1e08a
Update instrumentor.py
CasperGN Jan 7, 2026
638ceb3
Update instrumentor.py
CasperGN Jan 7, 2026
d5c0d1a
fix(shutdown): change order of shutdown to close wf_client before dap…
CasperGN Jan 8, 2026
803e034
chore(deps): remove unused import
CasperGN Jan 8, 2026
4ce5730
Update dapr_agents/agents/base.py
CasperGN Jan 8, 2026
ab85832
fix(bug): ensure agents without appid don't use uninitialized self.appid
CasperGN Jan 8, 2026
9839742
chore(devex): add default timeout of 10sec for empheral dapr client
CasperGN Jan 8, 2026
8029a99
chore(deps): add correct python-dotenv dep for quickstart
CasperGN Jan 8, 2026
8728f15
fix(bug): ensure call os._exit(0) when using agent runner + .run() to…
CasperGN Jan 8, 2026
3a339f1
chore(deps): add sentence-transformers dependency + bumps
CasperGN Jan 8, 2026
f44e80b
fix(bug): don't set appid from within agentComponents. It's always pa…
CasperGN Jan 8, 2026
218dcb0
fix(test): add http_timeout_seconds for MockDaprClient
CasperGN Jan 8, 2026
e17ee35
feat(metadata): encapsulate the agent content under agent metadatafie…
CasperGN Jan 8, 2026
1139b62
fix(test): patch mock client to accept kwargs
CasperGN Jan 8, 2026
0211aa8
fix(test): update assert to use nested under 'agents'
CasperGN Jan 8, 2026
b590d83
fix(bug): return name to metadata.agent.name
CasperGN Jan 8, 2026
b476e39
chore(func): skip using os._exit over just exit
CasperGN Jan 9, 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
6 changes: 3 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.10
- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.10"
python-version: "3.11"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -49,7 +49,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python_ver: ["3.10", "3.11", "3.12", "3.13"]
python_ver: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
376 changes: 359 additions & 17 deletions dapr_agents/agents/base.py

Large diffs are not rendered by default.

37 changes: 2 additions & 35 deletions dapr_agents/agents/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
from datetime import datetime, timezone
from typing import Any, Callable, Dict, Optional, Sequence

from dapr.clients import DaprClient
from dapr.clients.grpc._state import Concurrency, Consistency, StateOptions
from dapr.clients.grpc._response import GetMetadataResponse, RegisteredComponents

from pydantic import BaseModel, ValidationError

from dapr_agents.agents.configs import (
Expand All @@ -22,10 +21,10 @@
from dapr_agents.agents.schemas import AgentWorkflowEntry
from dapr_agents.storage.daprstores.stateservice import (
StateStoreError,
StateStoreService,
)
from dapr_agents.types.workflow import DaprWorkflowStatus


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -68,38 +67,6 @@ def __init__(
self.name = name
self._workflow_grpc_options = workflow_grpc_options

with DaprClient() as _client:
resp: GetMetadataResponse = _client.get_metadata()
self.appid = resp.application_id
if pubsub is None or state is None or registry is None:
components: Sequence[RegisteredComponents] = resp.registered_components
for component in components:
if (
"state" in component.type
and component.name == "agent-wfstatestore"
and state is None
):
state = AgentStateConfig(
store=StateStoreService(store_name=component.name),
state_key=f"{name.replace(' ', '-').lower() if name else 'default'}:workflow_state",
)
if component.name == "agent-registry" and registry is None:
registry = AgentRegistryConfig(
store=StateStoreService(store_name="agent-registry"),
team_name="default",
)
if (
"pubsub" in component.type
and component.name == "agent-pubsub"
and pubsub is None
):
logger.info(f"topic: {name}.topic")
pubsub = AgentPubSubConfig(
pubsub_name="agent-pubsub",
agent_topic=f"{name.replace(' ', '-').lower()}.topic",
broadcast_topic="agents.broadcast",
)

# -----------------------------
# Pub/Sub configuration (copy)
# -----------------------------
Expand Down
99 changes: 99 additions & 0 deletions dapr_agents/agents/configs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from __future__ import annotations

import re
from os import getenv
from enum import StrEnum
from dataclasses import dataclass, field
from typing import (
Any,
Expand Down Expand Up @@ -28,6 +30,10 @@ def _ensure_jinja_placeholders(text: str) -> str:
return _JINJA_PLACEHOLDER_PATTERN.sub(r"{{\1}}", text)


def _empty_headers() -> Dict[str, str]:
return {}


# Type hooks for state customization
EntryFactory = Callable[..., Any]
MessageCoercer = Callable[[Dict[str, Any]], Any]
Expand Down Expand Up @@ -295,3 +301,96 @@ class WorkflowRetryPolicy:
max_backoff_seconds: Optional[int] = 30
backoff_multiplier: Optional[float] = 1.5
retry_timeout: Optional[Union[int, None]] = None


class AgentTracingExporter(StrEnum):
"""
Supported tracing exporters for Dapr Agents observability.
"""

OTLP_GRPC = "otlp_grpc"
OTLP_HTTP = "otlp_http"
ZIPKIN = "zipkin"
CONSOLE = "console"


class AgentLoggingExporter(StrEnum):
"""
Supported logging exporters for Dapr Agents observability.
"""

CONSOLE = "console"
OTLP_GRPC = "otlp_grpc"
OTLP_HTTP = "otlp_http"


@dataclass
class AgentObservabilityConfig:
"""
Configuration settings for Dapr Agents observability features.

Attributes:
enabled: Enable/Disable observability.
headers: Optional headers for observability exporters.
auth_token: Optional authentication token for exporters.
endpoint: Optional endpoint URL for observability exporters.
service_name: Optional service name for observability data.
logging_enabled: Enable/disable logging observability.
logging_exporter: Logging exporter type.
tracing_enabled: Enable/disable tracing observability.
tracing_exporter: Tracing exporter type.
"""

enabled: Optional[bool] = None
headers: Dict[str, str] = field(default_factory=_empty_headers)
auth_token: Optional[str] = None
endpoint: Optional[str] = None
service_name: Optional[str] = None
logging_enabled: Optional[bool] = None
logging_exporter: Optional[AgentLoggingExporter] = None
tracing_enabled: Optional[bool] = None
tracing_exporter: Optional[AgentTracingExporter] = None

@classmethod
def from_env(cls) -> "AgentObservabilityConfig":
"""Create observability config from environment variables."""
headers: Dict[str, str] = {}
if token := getenv("OTEL_TOKEN"):
headers["Authorization"] = token

logging_exporter: Optional[AgentLoggingExporter] = None
if logging_exporter_str := getenv("OTEL_LOGGING_EXPORTER"):
try:
logging_exporter = AgentLoggingExporter(logging_exporter_str)
except (ValueError, KeyError):
logging_exporter = AgentLoggingExporter.CONSOLE

tracing_exporter: Optional[AgentTracingExporter] = None
if tracing_exporter_str := getenv("OTEL_TRACING_EXPORTER"):
try:
tracing_exporter = AgentTracingExporter(tracing_exporter_str)
except (ValueError, KeyError):
tracing_exporter = AgentTracingExporter.CONSOLE

enabled: Optional[bool] = None
if getenv("OTEL_ENABLED") is not None:
enabled = getenv("OTEL_ENABLED", "false").lower() == "true"

logging_enabled: Optional[bool] = None
if getenv("OTEL_LOGGING_ENABLED") is not None:
logging_enabled = getenv("OTEL_LOGGING_ENABLED", "false").lower() == "true"

tracing_enabled: Optional[bool] = None
if getenv("OTEL_TRACING_ENABLED") is not None:
tracing_enabled = getenv("OTEL_TRACING_ENABLED", "false").lower() == "true"

return cls(
enabled=enabled,
headers=headers,
endpoint=getenv("OTEL_ENDPOINT"),
service_name=getenv("OTEL_SERVICE_NAME"),
logging_enabled=logging_enabled,
logging_exporter=logging_exporter,
tracing_enabled=tracing_enabled,
tracing_exporter=tracing_exporter,
)
4 changes: 4 additions & 0 deletions dapr_agents/agents/durable.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
AgentStateConfig,
WorkflowGrpcOptions,
WorkflowRetryPolicy,
AgentObservabilityConfig,
)
from dapr_agents.agents.prompting import AgentProfileConfig
from dapr_agents.agents.schemas import (
Expand Down Expand Up @@ -79,6 +80,7 @@ def __init__(
workflow_grpc: Optional[WorkflowGrpcOptions] = None,
runtime: Optional[wf.WorkflowRuntime] = None,
retry_policy: WorkflowRetryPolicy = WorkflowRetryPolicy(),
agent_observability: Optional[AgentObservabilityConfig] = None,
) -> None:
"""
Initialize behavior, infrastructure, and workflow runtime.
Expand Down Expand Up @@ -108,6 +110,7 @@ def __init__(
workflow_grpc: Optional gRPC overrides for the workflow runtime channel.
runtime: Optional pre-existing workflow runtime to attach to.
retry_policy: Durable retry policy configuration.
agent_observability: Observability configuration for tracing/logging.
"""
super().__init__(
pubsub=pubsub,
Expand All @@ -127,6 +130,7 @@ def __init__(
llm=llm,
tools=tools,
prompt_template=prompt_template,
agent_observability=agent_observability,
)

apply_grpc_options(self.workflow_grpc_options)
Expand Down
1 change: 0 additions & 1 deletion dapr_agents/observability/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from .instrumentor import DaprAgentsInstrumentor


__all__ = [
"DaprAgentsInstrumentor",
]
Loading