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.
- coreason_manifest/__init__.py +85 -4
- coreason_manifest/definitions/__init__.py +60 -0
- coreason_manifest/definitions/agent.py +177 -38
- coreason_manifest/definitions/audit.py +178 -4
- coreason_manifest/definitions/base.py +47 -0
- coreason_manifest/definitions/events.py +423 -0
- coreason_manifest/definitions/message.py +188 -0
- coreason_manifest/definitions/simulation.py +69 -9
- coreason_manifest/definitions/simulation_config.py +46 -0
- coreason_manifest/definitions/topology.py +210 -9
- coreason_manifest/recipes.py +53 -7
- coreason_manifest/schemas/__init__.py +9 -1
- coreason_manifest/schemas/agent.schema.json +855 -27
- coreason_manifest/schemas/recipe.schema.json +813 -0
- coreason_manifest/utils/__init__.py +10 -0
- coreason_manifest/utils/logger.py +10 -0
- coreason_manifest/v1/__init__.py +15 -0
- {coreason_manifest-0.7.0.dist-info → coreason_manifest-0.10.0.dist-info}/METADATA +91 -29
- coreason_manifest-0.10.0.dist-info/RECORD +22 -0
- {coreason_manifest-0.7.0.dist-info → coreason_manifest-0.10.0.dist-info}/WHEEL +1 -1
- coreason_manifest-0.7.0.dist-info/RECORD +0 -16
- {coreason_manifest-0.7.0.dist-info → coreason_manifest-0.10.0.dist-info}/licenses/LICENSE +0 -0
- {coreason_manifest-0.7.0.dist-info → coreason_manifest-0.10.0.dist-info}/licenses/NOTICE +0 -0
coreason_manifest/__init__.py
CHANGED
|
@@ -1,17 +1,98 @@
|
|
|
1
|
-
|
|
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.
|
|
4
|
-
|
|
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
|
-
"
|
|
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
|
-
#
|
|
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(
|
|
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
|
|
94
|
-
"""
|
|
105
|
+
class Persona(CoReasonBaseModel):
|
|
106
|
+
"""Definition of an Agent Persona.
|
|
95
107
|
|
|
96
108
|
Attributes:
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
109
|
-
"""
|
|
121
|
+
class AgentInterface(CoReasonBaseModel):
|
|
122
|
+
"""Interface definition for the Agent.
|
|
110
123
|
|
|
111
124
|
Attributes:
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
119
|
-
|
|
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(
|
|
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
|
|
137
|
-
"""
|
|
154
|
+
class AgentRuntimeConfig(CoReasonBaseModel):
|
|
155
|
+
"""Configuration of the Agent execution.
|
|
138
156
|
|
|
139
157
|
Attributes:
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
152
|
-
"""Ensure all
|
|
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
|
|
203
|
+
v: The list of nodes to validate.
|
|
156
204
|
|
|
157
205
|
Returns:
|
|
158
|
-
The validated
|
|
206
|
+
The validated list of nodes.
|
|
159
207
|
|
|
160
208
|
Raises:
|
|
161
|
-
ValueError: If duplicate
|
|
209
|
+
ValueError: If duplicate node IDs are found.
|
|
162
210
|
"""
|
|
163
|
-
ids = [
|
|
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
|
|
220
|
+
raise ValueError(f"Duplicate node IDs found: {', '.join(dupes)}")
|
|
173
221
|
return v
|
|
174
222
|
|
|
175
223
|
|
|
176
|
-
class
|
|
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
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5
|
-
"""Audit log entry."""
|
|
19
|
+
from pydantic import ConfigDict, Field
|
|
6
20
|
|
|
7
|
-
|
|
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
|