mirror of
https://github.com/langgenius/dify.git
synced 2026-09-03 15:27:49 +08:00
80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
"""Provider-independent trace entities emitted by the unified trace builder."""
|
|
|
|
from datetime import datetime
|
|
from enum import StrEnum
|
|
from typing import Any, Self
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
|
|
from core.helper.trace_id_helper import ParentTraceContext
|
|
|
|
|
|
class CanonicalSpanKind(StrEnum):
|
|
CHAIN = "chain"
|
|
LLM = "llm"
|
|
RETRIEVER = "retriever"
|
|
TOOL = "tool"
|
|
AGENT = "agent"
|
|
|
|
|
|
class CanonicalSpanStatus(StrEnum):
|
|
OK = "ok"
|
|
ERROR = "error"
|
|
|
|
|
|
class CanonicalSpan(BaseModel):
|
|
"""One provider-neutral operation with an explicit parent."""
|
|
|
|
id: str
|
|
parent_id: str | None
|
|
name: str
|
|
kind: CanonicalSpanKind
|
|
start_time: datetime
|
|
end_time: datetime | None
|
|
inputs: Any = None
|
|
outputs: Any = None
|
|
status: CanonicalSpanStatus
|
|
error: str | None = None
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
synthetic: bool = False
|
|
can_parent_workflow: bool = False
|
|
publishes_parent_context: bool = False
|
|
links: tuple[str, ...] = ()
|
|
|
|
model_config = ConfigDict(extra="forbid", frozen=True)
|
|
|
|
|
|
class CanonicalTrace(BaseModel):
|
|
"""A parent-before-child span tree ready for a provider adapter."""
|
|
|
|
trace_id: str
|
|
session_id: str
|
|
root_span_id: str
|
|
spans: tuple[CanonicalSpan, ...]
|
|
external_parent: ParentTraceContext | None = None
|
|
required_parent_context_id: str | None = None
|
|
|
|
model_config = ConfigDict(extra="forbid", frozen=True)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_fragment(self) -> Self:
|
|
if self.external_parent is not None and self.required_parent_context_id is not None:
|
|
raise ValueError("canonical trace cannot require two external parent modes")
|
|
|
|
seen: set[str] = set()
|
|
root_seen = False
|
|
for span in self.spans:
|
|
if span.id in seen:
|
|
raise ValueError(f"duplicate canonical span id: {span.id}")
|
|
if span.id == self.root_span_id:
|
|
root_seen = True
|
|
if span.parent_id is not None:
|
|
raise ValueError("canonical trace root cannot have a local parent")
|
|
elif span.parent_id is None or span.parent_id not in seen:
|
|
raise ValueError(f"canonical span parent must appear first: {span.id}")
|
|
seen.add(span.id)
|
|
|
|
if not root_seen:
|
|
raise ValueError("canonical trace root is missing")
|
|
return self
|