coreason-manifest 0.7.0__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,98 @@
1
- from .definitions.agent import AgentDefinition
1
+ # Copyright (c) 2025 CoReason, Inc.
2
+ #
3
+ # This software is proprietary and dual-licensed.
4
+ # Licensed under the Prosperity Public License 3.0 (the "License").
5
+ # A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
6
+ # For details, see the LICENSE file.
7
+ # Commercial use beyond a 30-day trial requires a separate license.
8
+ #
9
+ # Source Code: https://github.com/CoReason-AI/coreason-manifest
10
+
11
+ from .definitions.agent import AgentDefinition, Persona
2
12
  from .definitions.audit import AuditLog
3
- from .definitions.simulation import SimulationScenario, SimulationTrace, SimulationTurn
4
- from .definitions.topology import Edge, Node, Topology
13
+ from .definitions.events import (
14
+ ArtifactGenerated,
15
+ CloudEvent,
16
+ CouncilVote,
17
+ EdgeTraversed,
18
+ GraphEvent,
19
+ GraphEventArtifactGenerated,
20
+ GraphEventCouncilVote,
21
+ GraphEventEdgeActive,
22
+ GraphEventError,
23
+ GraphEventNodeDone,
24
+ GraphEventNodeInit,
25
+ GraphEventNodeRestored,
26
+ GraphEventNodeSkipped,
27
+ GraphEventNodeStart,
28
+ GraphEventNodeStream,
29
+ NodeCompleted,
30
+ NodeInit,
31
+ NodeRestored,
32
+ NodeSkipped,
33
+ NodeStarted,
34
+ NodeStream,
35
+ WorkflowError,
36
+ migrate_graph_event_to_cloud_event,
37
+ )
38
+ from .definitions.simulation import (
39
+ SimulationMetrics,
40
+ SimulationScenario,
41
+ SimulationStep,
42
+ SimulationTrace,
43
+ StepType,
44
+ )
45
+ from .definitions.simulation_config import AdversaryProfile, ChaosConfig, SimulationRequest
46
+ from .definitions.topology import (
47
+ AgentNode,
48
+ Edge,
49
+ GraphTopology,
50
+ Node,
51
+ StateDefinition,
52
+ Topology,
53
+ )
5
54
  from .recipes import RecipeManifest
6
55
 
7
56
  __all__ = [
8
57
  "AgentDefinition",
58
+ "Persona",
9
59
  "Topology",
60
+ "GraphTopology",
10
61
  "Node",
62
+ "AgentNode",
11
63
  "Edge",
64
+ "StateDefinition",
65
+ "GraphEvent",
66
+ "CloudEvent",
67
+ "GraphEventNodeInit",
68
+ "GraphEventNodeStart",
69
+ "GraphEventNodeDone",
70
+ "GraphEventNodeStream",
71
+ "GraphEventNodeSkipped",
72
+ "GraphEventNodeRestored",
73
+ "GraphEventEdgeActive",
74
+ "GraphEventCouncilVote",
75
+ "GraphEventError",
76
+ "GraphEventArtifactGenerated",
77
+ "NodeInit",
78
+ "NodeStarted",
79
+ "NodeCompleted",
80
+ "NodeStream",
81
+ "NodeSkipped",
82
+ "NodeRestored",
83
+ "WorkflowError",
84
+ "CouncilVote",
85
+ "ArtifactGenerated",
86
+ "EdgeTraversed",
87
+ "migrate_graph_event_to_cloud_event",
12
88
  "SimulationScenario",
13
89
  "SimulationTrace",
14
- "SimulationTurn",
90
+ "SimulationStep",
91
+ "SimulationMetrics",
92
+ "StepType",
93
+ "AdversaryProfile",
94
+ "ChaosConfig",
95
+ "SimulationRequest",
15
96
  "AuditLog",
16
97
  "RecipeManifest",
17
98
  ]
@@ -0,0 +1,60 @@
1
+ # Copyright (c) 2025 CoReason, Inc.
2
+ #
3
+ # This software is proprietary and dual-licensed.
4
+ # Licensed under the Prosperity Public License 3.0 (the "License").
5
+ # A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
6
+ # For details, see the LICENSE file.
7
+ # Commercial use beyond a 30-day trial requires a separate license.
8
+ #
9
+ # Source Code: https://github.com/CoReason-AI/coreason-manifest
10
+
11
+ from .agent import AgentDefinition, AgentRuntimeConfig, Persona
12
+ from .events import (
13
+ ArtifactGenerated,
14
+ ArtifactGeneratedPayload,
15
+ CouncilVote,
16
+ CouncilVotePayload,
17
+ EdgeTraversed,
18
+ EdgeTraversedPayload,
19
+ GraphEvent,
20
+ NodeCompleted,
21
+ NodeCompletedPayload,
22
+ NodeInit,
23
+ # Export Aliases too
24
+ NodeInitPayload,
25
+ NodeRestored,
26
+ NodeSkipped,
27
+ NodeSkippedPayload,
28
+ NodeStarted,
29
+ NodeStartedPayload,
30
+ NodeStream,
31
+ NodeStreamPayload,
32
+ WorkflowError,
33
+ WorkflowErrorPayload,
34
+ )
35
+
36
+ __all__ = [
37
+ "AgentRuntimeConfig",
38
+ "AgentDefinition",
39
+ "Persona",
40
+ "GraphEvent",
41
+ "NodeInit",
42
+ "NodeStarted",
43
+ "NodeCompleted",
44
+ "NodeRestored",
45
+ "NodeSkipped",
46
+ "NodeStream",
47
+ "ArtifactGenerated",
48
+ "EdgeTraversed",
49
+ "CouncilVote",
50
+ "WorkflowError",
51
+ "NodeInitPayload",
52
+ "NodeStartedPayload",
53
+ "NodeCompletedPayload",
54
+ "NodeSkippedPayload",
55
+ "NodeStreamPayload",
56
+ "EdgeTraversedPayload",
57
+ "ArtifactGeneratedPayload",
58
+ "CouncilVotePayload",
59
+ "WorkflowErrorPayload",
60
+ ]
@@ -1,4 +1,13 @@
1
- # Prosperity-3.0
1
+ # Copyright (c) 2025 CoReason, Inc.
2
+ #
3
+ # This software is proprietary and dual-licensed.
4
+ # Licensed under the Prosperity Public License 3.0 (the "License").
5
+ # A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
6
+ # For details, see the LICENSE file.
7
+ # Commercial use beyond a 30-day trial requires a separate license.
8
+ #
9
+ # Source Code: https://github.com/CoReason-AI/coreason-manifest
10
+
2
11
  """Pydantic models for the Coreason Manifest system.
3
12
 
4
13
  These models define the structure and validation rules for the Agent Manifest
@@ -8,14 +17,14 @@ These models define the structure and validation rules for the Agent Manifest
8
17
  from __future__ import annotations
9
18
 
10
19
  from datetime import datetime
20
+ from enum import Enum
11
21
  from types import MappingProxyType
12
- from typing import Any, Dict, List, Mapping, Optional, Tuple
22
+ from typing import Any, Dict, List, Literal, Mapping, Optional, Tuple, Union
13
23
  from uuid import UUID
14
24
 
15
25
  from pydantic import (
16
26
  AfterValidator,
17
27
  AnyUrl,
18
- BaseModel,
19
28
  ConfigDict,
20
29
  Field,
21
30
  PlainSerializer,
@@ -24,6 +33,9 @@ from pydantic import (
24
33
  )
25
34
  from typing_extensions import Annotated
26
35
 
36
+ from coreason_manifest.definitions.base import CoReasonBaseModel
37
+ from coreason_manifest.definitions.topology import Edge, Node, validate_edge_integrity
38
+
27
39
  # SemVer Regex pattern (simplified for standard SemVer)
28
40
  # Modified to accept optional 'v' or 'V' prefix (multiple allowed) for input normalization
29
41
  SEMVER_REGEX = (
@@ -69,7 +81,7 @@ StrictUri = Annotated[
69
81
  ]
70
82
 
71
83
 
72
- class AgentMetadata(BaseModel):
84
+ class AgentMetadata(CoReasonBaseModel):
73
85
  """Metadata for the Agent.
74
86
 
75
87
  Attributes:
@@ -90,77 +102,113 @@ class AgentMetadata(BaseModel):
90
102
  requires_auth: bool = Field(default=False, description="Whether the agent requires user authentication.")
91
103
 
92
104
 
93
- class AgentInterface(BaseModel):
94
- """Interface definition for the Agent.
105
+ class Persona(CoReasonBaseModel):
106
+ """Definition of an Agent Persona.
95
107
 
96
108
  Attributes:
97
- inputs: Typed arguments the agent accepts (JSON Schema).
98
- outputs: Typed structure of the result.
109
+ name: Name of the persona.
110
+ description: Description of the persona.
111
+ directives: List of specific instructions or directives.
99
112
  """
100
113
 
101
114
  model_config = ConfigDict(extra="forbid", frozen=True)
102
115
 
103
- inputs: ImmutableDict = Field(..., description="Typed arguments the agent accepts (JSON Schema).")
104
- outputs: ImmutableDict = Field(..., description="Typed structure of the result.")
105
- injected_params: List[str] = Field(default_factory=list, description="List of parameters injected by the system.")
116
+ name: str = Field(..., description="Name of the persona.")
117
+ description: str = Field(..., description="Description of the persona.")
118
+ directives: List[str] = Field(..., description="List of specific instructions or directives.")
106
119
 
107
120
 
108
- class Step(BaseModel):
109
- """A single step in the execution graph.
121
+ class AgentInterface(CoReasonBaseModel):
122
+ """Interface definition for the Agent.
110
123
 
111
124
  Attributes:
112
- id: Unique identifier for the step.
113
- description: Description of the step.
125
+ inputs: Typed arguments the agent accepts (JSON Schema).
126
+ outputs: Typed structure of the result.
114
127
  """
115
128
 
116
129
  model_config = ConfigDict(extra="forbid", frozen=True)
117
130
 
118
- id: str = Field(..., min_length=1, description="Unique identifier for the step.")
119
- description: Optional[str] = Field(None, description="Description of the step.")
131
+ inputs: ImmutableDict = Field(..., description="Typed arguments the agent accepts (JSON Schema).")
132
+ outputs: ImmutableDict = Field(..., description="Typed structure of the result.")
133
+ injected_params: List[str] = Field(default_factory=list, description="List of parameters injected by the system.")
120
134
 
121
135
 
122
- class ModelConfig(BaseModel):
136
+ class ModelConfig(CoReasonBaseModel):
123
137
  """LLM Configuration parameters.
124
138
 
125
139
  Attributes:
126
140
  model: The LLM model identifier.
127
141
  temperature: Temperature for generation.
142
+ system_prompt: The default system prompt/persona for the agent.
143
+ persona: The full persona definition (name, description, directives).
128
144
  """
129
145
 
130
146
  model_config = ConfigDict(extra="forbid", frozen=True)
131
147
 
132
148
  model: str = Field(..., description="The LLM model identifier.")
133
149
  temperature: float = Field(..., ge=0.0, le=2.0, description="Temperature for generation.")
150
+ system_prompt: Optional[str] = Field(None, description="The default system prompt/persona for the agent.")
151
+ persona: Optional[Persona] = Field(None, description="The full persona definition (name, description, directives).")
134
152
 
135
153
 
136
- class AgentTopology(BaseModel):
137
- """Topology of the Agent execution.
154
+ class AgentRuntimeConfig(CoReasonBaseModel):
155
+ """Configuration of the Agent execution.
138
156
 
139
157
  Attributes:
140
- steps: A directed acyclic graph (DAG) of execution steps.
158
+ nodes: A collection of execution units (Agents, Tools, Logic).
159
+ edges: Directed connections defining control flow.
160
+ entry_point: The ID of the starting node.
141
161
  llm_config: Specific LLM parameters.
142
162
  """
143
163
 
144
164
  model_config = ConfigDict(extra="forbid", frozen=True)
145
165
 
146
- steps: Tuple[Step, ...] = Field(..., description="A directed acyclic graph (DAG) of execution steps.")
166
+ nodes: List[Node] = Field(default_factory=list, description="A collection of execution units.")
167
+ edges: List[Edge] = Field(default_factory=list, description="Directed connections defining control flow.")
168
+ entry_point: Optional[str] = Field(None, description="The ID of the starting node.")
147
169
  llm_config: ModelConfig = Field(..., alias="model_config", description="Specific LLM parameters.")
170
+ system_prompt: Optional[str] = Field(None, description="The global system prompt/instruction for the agent.")
171
+
172
+ @model_validator(mode="after")
173
+ def validate_topology_or_atomic(self) -> AgentRuntimeConfig:
174
+ """Ensure valid configuration: either a Graph or an Atomic Agent."""
175
+ has_nodes = len(self.nodes) > 0
176
+ has_entry = self.entry_point is not None
177
+
178
+ if has_nodes:
179
+ if not has_entry:
180
+ raise ValueError("Graph execution requires an 'entry_point'.")
181
+ else:
182
+ # Atomic Agent: Must have a system prompt (either global or in model_config)
183
+ has_global_prompt = self.system_prompt is not None
184
+ has_model_prompt = self.llm_config.system_prompt is not None
185
+
186
+ if not (has_global_prompt or has_model_prompt):
187
+ raise ValueError("Atomic Agents require a system_prompt (global or in model_config).")
148
188
 
149
- @field_validator("steps")
189
+ return self
190
+
191
+ @model_validator(mode="after")
192
+ def validate_topology_integrity(self) -> AgentRuntimeConfig:
193
+ """Ensure that edges connect existing nodes."""
194
+ validate_edge_integrity(self.nodes, self.edges)
195
+ return self
196
+
197
+ @field_validator("nodes")
150
198
  @classmethod
151
- def validate_unique_step_ids(cls, v: Tuple[Step, ...]) -> Tuple[Step, ...]:
152
- """Ensure all step IDs are unique.
199
+ def validate_unique_node_ids(cls, v: List[Node]) -> List[Node]:
200
+ """Ensure all node IDs are unique.
153
201
 
154
202
  Args:
155
- v: The tuple of steps to validate.
203
+ v: The list of nodes to validate.
156
204
 
157
205
  Returns:
158
- The validated tuple of steps.
206
+ The validated list of nodes.
159
207
 
160
208
  Raises:
161
- ValueError: If duplicate step IDs are found.
209
+ ValueError: If duplicate node IDs are found.
162
210
  """
163
- ids = [step.id for step in v]
211
+ ids = [node.id for node in v]
164
212
  if len(ids) != len(set(ids)):
165
213
  # Find duplicates
166
214
  seen = set()
@@ -169,35 +217,121 @@ class AgentTopology(BaseModel):
169
217
  if x in seen:
170
218
  dupes.add(x)
171
219
  seen.add(x)
172
- raise ValueError(f"Duplicate step IDs found: {', '.join(dupes)}")
220
+ raise ValueError(f"Duplicate node IDs found: {', '.join(dupes)}")
173
221
  return v
174
222
 
175
223
 
176
- class AgentDependencies(BaseModel):
224
+ class ToolRiskLevel(str, Enum):
225
+ """Risk level for the tool."""
226
+
227
+ SAFE = "safe"
228
+ STANDARD = "standard"
229
+ CRITICAL = "critical"
230
+
231
+
232
+ class ToolRequirement(CoReasonBaseModel):
233
+ """Requirement for an MCP tool.
234
+
235
+ Attributes:
236
+ uri: The MCP endpoint URI.
237
+ hash: Integrity check for the tool definition (SHA256).
238
+ scopes: List of permissions required.
239
+ risk_level: The risk level of the tool.
240
+ """
241
+
242
+ model_config = ConfigDict(extra="forbid", frozen=True)
243
+
244
+ uri: StrictUri = Field(..., description="The MCP endpoint URI.")
245
+ hash: str = Field(
246
+ ..., pattern=r"^[a-fA-F0-9]{64}$", description="Integrity check for the tool definition (SHA256)."
247
+ )
248
+ scopes: List[str] = Field(..., description="List of permissions required.")
249
+ risk_level: ToolRiskLevel = Field(..., description="The risk level of the tool.")
250
+
251
+
252
+ class InlineToolDefinition(CoReasonBaseModel):
253
+ """Definition of an inline tool.
254
+
255
+ Attributes:
256
+ name: Name of the tool.
257
+ description: Description of the tool.
258
+ parameters: JSON Schema of parameters.
259
+ type: The type of the tool (must be 'function').
260
+ """
261
+
262
+ model_config = ConfigDict(extra="forbid", frozen=True)
263
+
264
+ name: str = Field(..., description="Name of the tool.")
265
+ description: str = Field(..., description="Description of the tool.")
266
+ parameters: Dict[str, Any] = Field(..., description="JSON Schema of parameters.")
267
+ type: Literal["function"] = Field("function", description="The type of the tool (must be 'function').")
268
+
269
+
270
+ class AgentDependencies(CoReasonBaseModel):
177
271
  """External dependencies for the Agent.
178
272
 
179
273
  Attributes:
180
- tools: List of MCP capability URIs required.
274
+ tools: List of MCP tool requirements.
181
275
  libraries: List of Python packages required (if code execution is allowed).
182
276
  """
183
277
 
184
278
  model_config = ConfigDict(extra="forbid", frozen=True)
185
279
 
186
- # Use AnyUrl to enforce strictly valid URIs
187
- # Changed to List[StrictUri] to strictly enforce valid URI formatting and string serialization
188
- tools: List[StrictUri] = Field(default_factory=list, description="List of MCP capability URIs required.")
280
+ tools: List[Union[ToolRequirement, InlineToolDefinition]] = Field(
281
+ default_factory=list, description="List of MCP tool requirements."
282
+ )
189
283
  libraries: Tuple[str, ...] = Field(
190
284
  default_factory=tuple, description="List of Python packages required (if code execution is allowed)."
191
285
  )
192
286
 
193
287
 
194
- class AgentDefinition(BaseModel):
288
+ class PolicyConfig(CoReasonBaseModel):
289
+ """Governance policy configuration.
290
+
291
+ Attributes:
292
+ budget_caps: Dictionary defining budget limits (e.g., {"total_cost": 10.0, "total_tokens": 1000}).
293
+ human_in_the_loop: List of Node IDs that require human approval.
294
+ allowed_domains: List of allowed domains for external access.
295
+ """
296
+
297
+ model_config = ConfigDict(extra="forbid", frozen=True)
298
+
299
+ budget_caps: Dict[str, float] = Field(default_factory=dict, description="Budget limits.")
300
+ human_in_the_loop: List[str] = Field(default_factory=list, description="Node IDs requiring human approval.")
301
+ allowed_domains: List[str] = Field(default_factory=list, description="Allowed domains for external access.")
302
+
303
+
304
+ class TraceLevel(str, Enum):
305
+ """Level of tracing detail."""
306
+
307
+ FULL = "full"
308
+ METADATA_ONLY = "metadata_only"
309
+ NONE = "none"
310
+
311
+
312
+ class ObservabilityConfig(CoReasonBaseModel):
313
+ """Observability configuration.
314
+
315
+ Attributes:
316
+ trace_level: Level of tracing detail.
317
+ retention_policy: Retention policy identifier (e.g., '30_days').
318
+ encryption_key_id: Optional ID of the key used for log encryption.
319
+ """
320
+
321
+ model_config = ConfigDict(extra="forbid", frozen=True)
322
+
323
+ trace_level: TraceLevel = Field(default=TraceLevel.FULL, description="Level of tracing detail.")
324
+ retention_policy: str = Field(default="30_days", description="Retention policy identifier.")
325
+ encryption_key_id: Optional[str] = Field(None, description="Optional ID of the key used for log encryption.")
326
+
327
+
328
+ class AgentDefinition(CoReasonBaseModel):
195
329
  """The Root Object for the CoReason Agent Manifest.
196
330
 
197
331
  Attributes:
198
332
  metadata: Metadata for the Agent.
199
333
  interface: Interface definition for the Agent.
200
- topology: Topology of the Agent execution.
334
+ config: Configuration of the Agent execution.
201
335
  dependencies: External dependencies for the Agent.
202
336
  integrity_hash: SHA256 hash of the source code.
203
337
  """
@@ -214,8 +348,13 @@ class AgentDefinition(BaseModel):
214
348
 
215
349
  metadata: AgentMetadata
216
350
  interface: AgentInterface
217
- topology: AgentTopology
351
+ config: AgentRuntimeConfig
218
352
  dependencies: AgentDependencies
353
+ policy: Optional[PolicyConfig] = Field(None, description="Governance policy configuration.")
354
+ observability: Optional[ObservabilityConfig] = Field(None, description="Observability configuration.")
355
+ custom_metadata: Optional[Dict[str, Any]] = Field(
356
+ None, description="Container for arbitrary metadata extensions without breaking validation."
357
+ )
219
358
  integrity_hash: str = Field(
220
359
  ...,
221
360
  pattern=r"^[a-fA-F0-9]{64}$",
@@ -1,7 +1,181 @@
1
- from pydantic import BaseModel
1
+ # Copyright (c) 2025 CoReason, Inc.
2
+ #
3
+ # This software is proprietary and dual-licensed.
4
+ # Licensed under the Prosperity Public License 3.0 (the "License").
5
+ # A copy of the license is available at https://prosperitylicense.com/versions/3.0.0
6
+ # For details, see the LICENSE file.
7
+ # Commercial use beyond a 30-day trial requires a separate license.
8
+ #
9
+ # Source Code: https://github.com/CoReason-AI/coreason-manifest
2
10
 
11
+ import hashlib
12
+ import json
13
+ import uuid
14
+ from datetime import datetime
15
+ from enum import Enum
16
+ from typing import Any, Dict, List, Optional
17
+ from uuid import UUID
3
18
 
4
- class AuditLog(BaseModel):
5
- """Audit log entry."""
19
+ from pydantic import ConfigDict, Field
6
20
 
7
- pass
21
+ from coreason_manifest.definitions.base import CoReasonBaseModel
22
+
23
+ from .message import ChatMessage
24
+
25
+
26
+ class GenAITokenUsage(CoReasonBaseModel):
27
+ """Token consumption stats aligned with OTel conventions."""
28
+
29
+ model_config = ConfigDict(extra="ignore")
30
+
31
+ input: int = Field(0, description="Number of input tokens (prompt).")
32
+ output: int = Field(0, description="Number of output tokens (completion).")
33
+ total: int = Field(0, description="Total number of tokens used.")
34
+
35
+ # Backward compatibility fields (mapped to new fields in logic if needed, but kept for schema)
36
+ prompt_tokens: int = 0
37
+ completion_tokens: int = 0
38
+ total_tokens: int = 0
39
+ details: Dict[str, Any] = Field(default_factory=dict)
40
+
41
+ def __add__(self, other: "GenAITokenUsage") -> "GenAITokenUsage":
42
+ """Add two TokenUsage objects."""
43
+ new_details = self.details.copy()
44
+ new_details.update(other.details)
45
+ return GenAITokenUsage(
46
+ input=self.input + other.input,
47
+ output=self.output + other.output,
48
+ total=self.total + other.total,
49
+ prompt_tokens=self.prompt_tokens + other.prompt_tokens,
50
+ completion_tokens=self.completion_tokens + other.completion_tokens,
51
+ total_tokens=self.total_tokens + other.total_tokens,
52
+ details=new_details,
53
+ )
54
+
55
+ def __iadd__(self, other: "GenAITokenUsage") -> "GenAITokenUsage":
56
+ """In-place add two TokenUsage objects."""
57
+ self.input += other.input
58
+ self.output += other.output
59
+ self.total += other.total
60
+ self.prompt_tokens += other.prompt_tokens
61
+ self.completion_tokens += other.completion_tokens
62
+ self.total_tokens += other.total_tokens
63
+ self.details.update(other.details)
64
+ return self
65
+
66
+
67
+ class GenAIOperation(CoReasonBaseModel):
68
+ """An atomic operation in the reasoning process (e.g., one LLM call), aligning with OTel Spans."""
69
+
70
+ model_config = ConfigDict(extra="ignore")
71
+
72
+ span_id: str = Field(..., description="Unique identifier for the operation/span.")
73
+ trace_id: str = Field(..., description="Trace ID this operation belongs to.")
74
+ parent_id: Optional[str] = Field(None, description="Parent span ID.")
75
+
76
+ operation_name: str = Field(..., description="Name of the operation (e.g., chat, embedding).")
77
+ provider: str = Field(..., description="GenAI provider (e.g., openai, anthropic).")
78
+ model: str = Field(..., description="Model name used.")
79
+
80
+ start_time: datetime = Field(default_factory=datetime.now)
81
+ end_time: Optional[datetime] = None
82
+ duration_ms: float = 0.0
83
+
84
+ # Context
85
+ input_messages: List[ChatMessage] = Field(default_factory=list)
86
+ output_messages: List[ChatMessage] = Field(default_factory=list)
87
+
88
+ # Metrics
89
+ token_usage: Optional[GenAITokenUsage] = None
90
+
91
+ # Metadata
92
+ status: str = "pending" # success, error
93
+ error_type: Optional[str] = None
94
+ metadata: Dict[str, Any] = Field(default_factory=dict)
95
+
96
+ @classmethod
97
+ def thought(cls, content: str, **kwargs: Any) -> "GenAIOperation":
98
+ """Factory method to create a simplified thought/reasoning step."""
99
+ defaults = {
100
+ "span_id": str(uuid.uuid4()),
101
+ "trace_id": str(uuid.uuid4()),
102
+ "operation_name": "thought",
103
+ "provider": "internal",
104
+ "model": "internal",
105
+ }
106
+ defaults.update(kwargs)
107
+ # Ensure output_messages is not duplicated if passed in kwargs
108
+ defaults.pop("output_messages", None)
109
+ return cls(
110
+ **defaults,
111
+ output_messages=[ChatMessage.assistant(content)],
112
+ )
113
+
114
+
115
+ class ReasoningTrace(CoReasonBaseModel):
116
+ """The full audit trail of an Agent's execution session.
117
+
118
+ Aligned with OpenTelemetry for trace identification.
119
+ """
120
+
121
+ model_config = ConfigDict(extra="ignore")
122
+
123
+ trace_id: str = Field(..., description="Trace ID (OTel format).")
124
+ agent_id: str
125
+ session_id: Optional[str] = None
126
+
127
+ start_time: datetime
128
+ end_time: Optional[datetime] = None
129
+
130
+ # The chain of thought (Ordered list of operations)
131
+ steps: List[GenAIOperation] = Field(default_factory=list)
132
+
133
+ # Final outcome
134
+ status: str = "pending" # options: success, failure, pending
135
+ final_result: Optional[str] = None
136
+ error: Optional[str] = None
137
+
138
+ # Aggregated stats
139
+ total_tokens: GenAITokenUsage = Field(default_factory=GenAITokenUsage)
140
+ total_cost: float = 0.0
141
+
142
+ # Flexible metadata
143
+ metadata: Dict[str, Any] = Field(default_factory=dict)
144
+
145
+
146
+ class AuditEventType(str, Enum):
147
+ SYSTEM_CHANGE = "system_change"
148
+ PREDICTION = "prediction"
149
+ GUARDRAIL_TRIGGER = "guardrail_trigger"
150
+
151
+
152
+ class AuditLog(CoReasonBaseModel):
153
+ """Tamper-evident legal record.
154
+
155
+ IDs aligned with OpenTelemetry:
156
+ - audit_id: Unique record ID.
157
+ - trace_id: OTel Trace ID.
158
+ """
159
+
160
+ audit_id: UUID = Field(..., description="Unique identifier.")
161
+ trace_id: str = Field(..., description="Trace ID for OTel correlation.")
162
+ timestamp: datetime = Field(..., description="ISO8601 timestamp.")
163
+ actor: str = Field(..., description="User ID or Agent Component ID.")
164
+ event_type: AuditEventType = Field(..., description="Type of event.")
165
+ safety_metadata: Dict[str, Any] = Field(..., description="Safety metadata (e.g., PII detected).")
166
+ previous_hash: str = Field(..., description="Hash of the previous log entry.")
167
+ integrity_hash: str = Field(..., description="SHA256 hash of this record + previous_hash.")
168
+
169
+ def compute_hash(self) -> str:
170
+ """Computes the integrity hash of the record."""
171
+ # Use model_dump to get a dict, but exclude integrity_hash as it is the target
172
+ data = self.model_dump(exclude={"integrity_hash"}, mode="json")
173
+ # Ensure deterministic serialization
174
+ json_str = json.dumps(data, sort_keys=True, default=str)
175
+ return hashlib.sha256(json_str.encode("utf-8")).hexdigest()
176
+
177
+
178
+ # --- Backward Compatibility ---
179
+ # Adapters or Aliases
180
+ CognitiveStep = GenAIOperation
181
+ TokenUsage = GenAITokenUsage