coreason-manifest 0.9.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,8 +1,21 @@
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
+
1
11
  from datetime import datetime, timezone
2
- from typing import Any, Dict, Generic, Literal, Optional, Protocol, TypeVar, runtime_checkable
12
+ from typing import Annotated, Any, Dict, Generic, Literal, Optional, Protocol, TypeVar, Union, runtime_checkable
3
13
  from uuid import uuid4
4
14
 
5
- from pydantic import BaseModel, ConfigDict, Field
15
+ from pydantic import ConfigDict, Field
16
+
17
+ from coreason_manifest.definitions.base import CoReasonBaseModel
18
+ from coreason_manifest.definitions.topology import RuntimeVisualMetadata
6
19
 
7
20
  # --- CloudEvents v1.0 Implementation ---
8
21
 
@@ -14,7 +27,7 @@ class CloudEventSource(Protocol):
14
27
  def as_cloud_event_payload(self) -> Any: ...
15
28
 
16
29
 
17
- class CloudEvent(BaseModel, Generic[T]):
30
+ class CloudEvent(CoReasonBaseModel, Generic[T]):
18
31
  """Standard CloudEvent v1.0 Envelope."""
19
32
 
20
33
  model_config = ConfigDict(extra="allow", populate_by_name=True)
@@ -38,7 +51,7 @@ class CloudEvent(BaseModel, Generic[T]):
38
51
  # --- OTel Semantic Conventions ---
39
52
 
40
53
 
41
- class GenAIUsage(BaseModel):
54
+ class GenAIUsage(CoReasonBaseModel):
42
55
  """GenAI Usage metrics."""
43
56
 
44
57
  input_tokens: Optional[int] = Field(None, alias="input_tokens")
@@ -47,7 +60,7 @@ class GenAIUsage(BaseModel):
47
60
  model_config = ConfigDict(populate_by_name=True)
48
61
 
49
62
 
50
- class GenAIRequest(BaseModel):
63
+ class GenAIRequest(CoReasonBaseModel):
51
64
  """GenAI Request details."""
52
65
 
53
66
  model: Optional[str] = None
@@ -55,14 +68,14 @@ class GenAIRequest(BaseModel):
55
68
  top_p: Optional[float] = None
56
69
 
57
70
 
58
- class GenAICompletion(BaseModel):
71
+ class GenAICompletion(CoReasonBaseModel):
59
72
  """GenAI Completion details."""
60
73
 
61
74
  chunk: Optional[str] = None
62
75
  finish_reason: Optional[str] = None
63
76
 
64
77
 
65
- class GenAISemantics(BaseModel):
78
+ class GenAISemantics(CoReasonBaseModel):
66
79
  """OpenTelemetry GenAI Semantic Conventions."""
67
80
 
68
81
  system: Optional[str] = None
@@ -71,62 +84,10 @@ class GenAISemantics(BaseModel):
71
84
  completion: Optional[GenAICompletion] = None
72
85
 
73
86
 
74
- # --- Graph Event Wrapper ---
75
-
76
-
77
- class GraphEvent(BaseModel):
78
- """The atomic unit of communication between the Engine (MACO) and the UI (Flutter).
79
-
80
- Standardized IDs:
81
- - run_id: Workflow execution ID.
82
- - trace_id: OpenTelemetry Distributed Trace ID.
83
-
84
- Attributes:
85
- event_type: The type of the event.
86
- run_id: The unique ID of the workflow run.
87
- trace_id: The trace ID (defaults to "unknown").
88
- node_id: The ID of the node associated with the event.
89
- timestamp: The timestamp of the event.
90
- sequence_id: Optional sequence ID.
91
- payload: The event payload containing logic output.
92
- visual_metadata: Metadata for UI visualization.
93
- """
94
-
95
- model_config = ConfigDict(extra="forbid")
96
-
97
- event_type: Literal[
98
- "NODE_INIT",
99
- "NODE_START",
100
- "NODE_STREAM",
101
- "NODE_DONE",
102
- "NODE_SKIPPED",
103
- "EDGE_ACTIVE",
104
- "COUNCIL_VOTE",
105
- "ERROR",
106
- "NODE_RESTORED",
107
- "ARTIFACT_GENERATED",
108
- ]
109
- run_id: str
110
- trace_id: str = Field(
111
- default_factory=lambda: "unknown"
112
- ) # Default for compatibility if missing in some legacy calls
113
- node_id: str # Required per BRD and existing tests
114
- timestamp: float
115
- sequence_id: Optional[int] = None # Optional for internal use
116
-
117
- # The payload contains the actual reasoning/data
118
- payload: Dict[str, Any] = Field(..., description="The logic output")
119
-
120
- # Visual Metadata drives the Flutter animation engine
121
- visual_metadata: Dict[str, str] = Field(
122
- ..., description="Hints for UI: color='#00FF00', animation='pulse', progress='0.5'"
123
- )
124
-
125
-
126
87
  # --- Base Models ---
127
88
 
128
89
 
129
- class BaseNodePayload(BaseModel):
90
+ class BaseNodePayload(CoReasonBaseModel):
130
91
  """Base model for node-related events."""
131
92
 
132
93
  model_config = ConfigDict(extra="ignore")
@@ -243,7 +204,7 @@ class ArtifactGenerated(BaseNodePayload):
243
204
  url: str
244
205
 
245
206
 
246
- class EdgeTraversed(BaseModel):
207
+ class EdgeTraversed(CoReasonBaseModel):
247
208
  """Payload for EDGE_ACTIVE event."""
248
209
 
249
210
  model_config = ConfigDict(extra="ignore")
@@ -307,6 +268,101 @@ ArtifactGeneratedPayload = ArtifactGenerated
307
268
  CouncilVotePayload = CouncilVote
308
269
  WorkflowErrorPayload = WorkflowError
309
270
 
271
+
272
+ # --- Graph Event Wrapper ---
273
+
274
+
275
+ class BaseGraphEvent(CoReasonBaseModel):
276
+ """Base class for GraphEvents.
277
+
278
+ Standardized IDs:
279
+ - run_id: Workflow execution ID.
280
+ - trace_id: OpenTelemetry Distributed Trace ID.
281
+ """
282
+
283
+ model_config = ConfigDict(extra="forbid")
284
+
285
+ run_id: str
286
+ trace_id: str = Field(
287
+ default_factory=lambda: "unknown"
288
+ ) # Default for compatibility if missing in some legacy calls
289
+ node_id: str # Required per BRD and existing tests
290
+ timestamp: float
291
+ sequence_id: Optional[int] = None # Optional for internal use
292
+
293
+ # Visual Metadata drives the Flutter animation engine
294
+ visual_metadata: RuntimeVisualMetadata = Field(
295
+ ..., description="Hints for UI: color='#00FF00', animation='pulse', progress='0.5'"
296
+ )
297
+
298
+
299
+ class GraphEventNodeInit(BaseGraphEvent):
300
+ event_type: Literal["NODE_INIT"] = "NODE_INIT"
301
+ payload: NodeInit = Field(..., description="The logic output")
302
+
303
+
304
+ class GraphEventNodeStart(BaseGraphEvent):
305
+ event_type: Literal["NODE_START"] = "NODE_START"
306
+ payload: NodeStarted = Field(..., description="The logic output")
307
+
308
+
309
+ class GraphEventNodeStream(BaseGraphEvent):
310
+ event_type: Literal["NODE_STREAM"] = "NODE_STREAM"
311
+ payload: NodeStream = Field(..., description="The logic output")
312
+
313
+
314
+ class GraphEventNodeDone(BaseGraphEvent):
315
+ event_type: Literal["NODE_DONE"] = "NODE_DONE"
316
+ payload: NodeCompleted = Field(..., description="The logic output")
317
+
318
+
319
+ class GraphEventNodeSkipped(BaseGraphEvent):
320
+ event_type: Literal["NODE_SKIPPED"] = "NODE_SKIPPED"
321
+ payload: NodeSkipped = Field(..., description="The logic output")
322
+
323
+
324
+ class GraphEventEdgeActive(BaseGraphEvent):
325
+ event_type: Literal["EDGE_ACTIVE"] = "EDGE_ACTIVE"
326
+ payload: EdgeTraversed = Field(..., description="The logic output")
327
+
328
+
329
+ class GraphEventCouncilVote(BaseGraphEvent):
330
+ event_type: Literal["COUNCIL_VOTE"] = "COUNCIL_VOTE"
331
+ payload: CouncilVote = Field(..., description="The logic output")
332
+
333
+
334
+ class GraphEventError(BaseGraphEvent):
335
+ event_type: Literal["ERROR"] = "ERROR"
336
+ payload: WorkflowError = Field(..., description="The logic output")
337
+
338
+
339
+ class GraphEventNodeRestored(BaseGraphEvent):
340
+ event_type: Literal["NODE_RESTORED"] = "NODE_RESTORED"
341
+ payload: NodeRestored = Field(..., description="The logic output")
342
+
343
+
344
+ class GraphEventArtifactGenerated(BaseGraphEvent):
345
+ event_type: Literal["ARTIFACT_GENERATED"] = "ARTIFACT_GENERATED"
346
+ payload: ArtifactGenerated = Field(..., description="The logic output")
347
+
348
+
349
+ GraphEvent = Annotated[
350
+ Union[
351
+ GraphEventNodeInit,
352
+ GraphEventNodeStart,
353
+ GraphEventNodeStream,
354
+ GraphEventNodeDone,
355
+ GraphEventNodeSkipped,
356
+ GraphEventEdgeActive,
357
+ GraphEventCouncilVote,
358
+ GraphEventError,
359
+ GraphEventNodeRestored,
360
+ GraphEventArtifactGenerated,
361
+ ],
362
+ Field(discriminator="event_type", description="Polymorphic graph event definition."),
363
+ ]
364
+
365
+
310
366
  # --- Migration Logic ---
311
367
 
312
368
 
@@ -321,48 +377,23 @@ def migrate_graph_event_to_cloud_event(event: GraphEvent) -> CloudEvent[Any]:
321
377
  ce_type = ce_type_map.get(event.event_type, f"ai.coreason.legacy.{event.event_type.lower()}")
322
378
  ce_source = f"urn:node:{event.node_id}"
323
379
 
324
- # Prepare payload dict with node_id injected
325
- payload_dict = event.payload.copy()
326
- payload_dict["node_id"] = event.node_id
327
- # Inject timestamp if missing (required by some payloads like NodeStarted)
328
- if "timestamp" not in payload_dict:
329
- payload_dict["timestamp"] = event.timestamp
330
-
331
- # Mapping event types to their corresponding payload classes
332
- event_class_map: Dict[str, Any] = {
333
- "NODE_INIT": NodeInit,
334
- "NODE_START": NodeStarted,
335
- "NODE_DONE": NodeCompleted,
336
- "NODE_STREAM": NodeStream,
337
- "NODE_SKIPPED": NodeSkipped,
338
- "NODE_RESTORED": NodeRestored,
339
- "ERROR": WorkflowError,
340
- "ARTIFACT_GENERATED": ArtifactGenerated,
341
- "COUNCIL_VOTE": CouncilVote,
342
- "EDGE_ACTIVE": EdgeTraversed,
343
- }
344
-
345
380
  data: Any = None
346
- payload_class = event_class_map.get(event.event_type)
347
-
348
- if payload_class:
349
- try:
350
- # Instantiate the payload object
351
- payload_obj = payload_class(**payload_dict)
352
- if isinstance(payload_obj, CloudEventSource):
353
- data = payload_obj.as_cloud_event_payload()
354
- else:
355
- data = payload_obj # pragma: no cover
356
- except Exception:
357
- # Fallback if instantiation fails
358
- data = event.payload
381
+
382
+ # event.payload is already a strictly typed Pydantic model (from GraphEvent union).
383
+ # All supported payload models implement CloudEventSource protocol (duck-typed or via BaseNodePayload).
384
+ if isinstance(event.payload, CloudEventSource):
385
+ data = event.payload.as_cloud_event_payload()
359
386
  else:
387
+ # Fallback for models that might not implement the protocol (e.g. unknown future extensions)
360
388
  data = event.payload
361
389
 
362
390
  # UI Metadata as extension
391
+ payload_visual_cue = getattr(event.payload, "visual_cue", None)
392
+
393
+ visual_dict = event.visual_metadata.model_dump(exclude_none=True)
363
394
  extensions = {
364
- "com_coreason_ui_cue": event.visual_metadata.get("animation") or event.payload.get("visual_cue"),
365
- "com_coreason_ui_metadata": event.visual_metadata,
395
+ "com_coreason_ui_cue": event.visual_metadata.animation or payload_visual_cue,
396
+ "com_coreason_ui_metadata": visual_dict,
366
397
  }
367
398
 
368
399
  # Filter out None values in extensions
@@ -1,7 +1,22 @@
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
+ import functools
12
+ import json
13
+ import warnings
1
14
  from enum import Enum
2
- from typing import Any, Dict, List, Literal, Optional, Union
15
+ from typing import Annotated, Any, Dict, List, Literal, Optional, Union, cast
3
16
 
4
- from pydantic import BaseModel, ConfigDict, Field
17
+ from pydantic import ConfigDict, Field, model_validator
18
+
19
+ from coreason_manifest.definitions.base import CoReasonBaseModel
5
20
 
6
21
  # --- Enums ---
7
22
 
@@ -23,7 +38,7 @@ class Modality(str, Enum):
23
38
  # --- Message Parts ---
24
39
 
25
40
 
26
- class TextPart(BaseModel):
41
+ class TextPart(CoReasonBaseModel):
27
42
  """Represents text content sent to or received from the model."""
28
43
 
29
44
  model_config = ConfigDict(extra="ignore")
@@ -31,7 +46,7 @@ class TextPart(BaseModel):
31
46
  content: str
32
47
 
33
48
 
34
- class BlobPart(BaseModel):
49
+ class BlobPart(CoReasonBaseModel):
35
50
  """Represents blob binary data sent inline to the model."""
36
51
 
37
52
  model_config = ConfigDict(extra="ignore")
@@ -41,7 +56,7 @@ class BlobPart(BaseModel):
41
56
  mime_type: Optional[str] = None
42
57
 
43
58
 
44
- class FilePart(BaseModel):
59
+ class FilePart(CoReasonBaseModel):
45
60
  """Represents an external referenced file sent to the model by file id."""
46
61
 
47
62
  model_config = ConfigDict(extra="ignore")
@@ -51,7 +66,7 @@ class FilePart(BaseModel):
51
66
  mime_type: Optional[str] = None
52
67
 
53
68
 
54
- class UriPart(BaseModel):
69
+ class UriPart(CoReasonBaseModel):
55
70
  """Represents an external referenced file sent to the model by URI."""
56
71
 
57
72
  model_config = ConfigDict(extra="ignore")
@@ -61,17 +76,28 @@ class UriPart(BaseModel):
61
76
  mime_type: Optional[str] = None
62
77
 
63
78
 
64
- class ToolCallRequestPart(BaseModel):
79
+ class ToolCallRequestPart(CoReasonBaseModel):
65
80
  """Represents a tool call requested by the model."""
66
81
 
67
82
  model_config = ConfigDict(extra="ignore")
68
83
  type: Literal["tool_call"] = "tool_call"
69
84
  name: str
70
- arguments: Dict[str, Any] # Structured arguments
85
+ arguments: Union[Dict[str, Any], str] # Structured arguments or JSON string
71
86
  id: Optional[str] = None
72
87
 
88
+ @functools.cached_property
89
+ def parsed_arguments(self) -> Dict[str, Any]:
90
+ """Return arguments as a dictionary, parsing JSON if necessary."""
91
+ if isinstance(self.arguments, dict):
92
+ return self.arguments
93
+ try:
94
+ result = json.loads(self.arguments)
95
+ return cast(Dict[str, Any], result) if isinstance(result, dict) else {}
96
+ except (json.JSONDecodeError, TypeError):
97
+ return {}
98
+
73
99
 
74
- class ToolCallResponsePart(BaseModel):
100
+ class ToolCallResponsePart(CoReasonBaseModel):
75
101
  """Represents a tool call result sent to the model."""
76
102
 
77
103
  model_config = ConfigDict(extra="ignore")
@@ -80,7 +106,7 @@ class ToolCallResponsePart(BaseModel):
80
106
  id: Optional[str] = None
81
107
 
82
108
 
83
- class ReasoningPart(BaseModel):
109
+ class ReasoningPart(CoReasonBaseModel):
84
110
  """Represents reasoning/thinking content received from the model."""
85
111
 
86
112
  model_config = ConfigDict(extra="ignore")
@@ -90,12 +116,15 @@ class ReasoningPart(BaseModel):
90
116
 
91
117
  # --- Union of All Parts ---
92
118
 
93
- Part = Union[TextPart, BlobPart, FilePart, UriPart, ToolCallRequestPart, ToolCallResponsePart, ReasoningPart]
119
+ Part = Annotated[
120
+ Union[TextPart, BlobPart, FilePart, UriPart, ToolCallRequestPart, ToolCallResponsePart, ReasoningPart],
121
+ Field(discriminator="type"),
122
+ ]
94
123
 
95
124
  # --- Main Message Model ---
96
125
 
97
126
 
98
- class ChatMessage(BaseModel):
127
+ class ChatMessage(CoReasonBaseModel):
99
128
  """Represents a message in a conversation with an LLM."""
100
129
 
101
130
  model_config = ConfigDict(extra="ignore")
@@ -104,23 +133,56 @@ class ChatMessage(BaseModel):
104
133
  parts: List[Part] = Field(..., description="List of message parts that make up the message content.")
105
134
  name: Optional[str] = None
106
135
 
136
+ @classmethod
137
+ def user(cls, content: str, name: Optional[str] = None) -> "ChatMessage":
138
+ """Factory method to create a user message with text content."""
139
+ return cls(role=Role.USER, parts=[TextPart(content=content)], name=name)
140
+
141
+ @classmethod
142
+ def assistant(cls, content: str, name: Optional[str] = None) -> "ChatMessage":
143
+ """Factory method to create an assistant message with text content."""
144
+ return cls(role=Role.ASSISTANT, parts=[TextPart(content=content)], name=name)
145
+
146
+ @classmethod
147
+ def tool(cls, tool_call_id: str, content: Any) -> "ChatMessage":
148
+ """Factory method to create a tool message with the result."""
149
+ return cls(role=Role.TOOL, parts=[ToolCallResponsePart(id=tool_call_id, response=content)])
150
+
107
151
 
108
152
  # --- Backward Compatibility ---
109
153
 
110
154
 
111
- class FunctionCall(BaseModel):
155
+ class FunctionCall(CoReasonBaseModel):
112
156
  """Deprecated: Use ToolCallRequestPart instead."""
113
157
 
114
158
  name: str
115
159
  arguments: str
116
160
 
161
+ @model_validator(mode="after")
162
+ def warn_deprecated(self) -> "FunctionCall":
163
+ warnings.warn(
164
+ "FunctionCall is deprecated. Use ToolCallRequestPart instead.",
165
+ DeprecationWarning,
166
+ stacklevel=2,
167
+ )
168
+ return self
169
+
117
170
 
118
- class ToolCall(BaseModel):
171
+ class ToolCall(CoReasonBaseModel):
119
172
  """Deprecated: Use ToolCallRequestPart instead."""
120
173
 
121
174
  id: str
122
175
  type: str = "function"
123
176
  function: FunctionCall
124
177
 
178
+ @model_validator(mode="after")
179
+ def warn_deprecated(self) -> "ToolCall":
180
+ warnings.warn(
181
+ "ToolCall is deprecated. Use ToolCallRequestPart instead.",
182
+ DeprecationWarning,
183
+ stacklevel=2,
184
+ )
185
+ return self
186
+
125
187
 
126
188
  Message = ChatMessage
@@ -1,9 +1,28 @@
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
+
1
11
  from datetime import datetime
2
12
  from enum import Enum
3
- from typing import Any, Dict, List
13
+ from typing import Any, Dict, List, Optional
4
14
  from uuid import UUID
5
15
 
6
- from pydantic import BaseModel, Field
16
+ from pydantic import Field
17
+
18
+ from coreason_manifest.definitions.base import CoReasonBaseModel
19
+
20
+
21
+ class StepType(str, Enum):
22
+ """Type of the simulation step."""
23
+
24
+ INTERACTION = "interaction" # Normal User/Agent turn
25
+ SYSTEM_EVENT = "system_event" # Chaos injection, error, or info
7
26
 
8
27
 
9
28
  class ValidationLogic(str, Enum):
@@ -14,7 +33,7 @@ class ValidationLogic(str, Enum):
14
33
  CODE_EVAL = "code_eval"
15
34
 
16
35
 
17
- class SimulationScenario(BaseModel):
36
+ class SimulationScenario(CoReasonBaseModel):
18
37
  """Definition of a simulation scenario."""
19
38
 
20
39
  id: str = Field(..., description="Unique identifier for the scenario.")
@@ -25,26 +44,36 @@ class SimulationScenario(BaseModel):
25
44
  validation_logic: ValidationLogic = Field(..., description="Logic used to validate the outcome.")
26
45
 
27
46
 
28
- class SimulationStep(BaseModel):
47
+ class SimulationStep(CoReasonBaseModel):
29
48
  """The atomic unit of execution in a simulation."""
30
49
 
31
50
  step_id: UUID = Field(..., description="Atomic unit of execution ID.")
32
51
  timestamp: datetime = Field(..., description="Execution timestamp.")
52
+ type: StepType = Field(default=StepType.INTERACTION, description="Type of the step.")
33
53
  node_id: str = Field(..., description="The graph node executed.")
34
54
  inputs: Dict[str, Any] = Field(..., description="Snapshot of entry state.")
35
- thought: str = Field(..., description="The Chain-of-Thought reasoning.")
36
- action: Dict[str, Any] = Field(..., description="Tool calls or API requests.")
37
- observation: Dict[str, Any] = Field(..., description="Tool outputs.")
55
+ thought: Optional[str] = Field(None, description="The Chain-of-Thought reasoning.")
56
+ action: Optional[Dict[str, Any]] = Field(None, description="Tool calls or API requests.")
57
+ observation: Optional[Dict[str, Any]] = Field(None, description="Tool outputs.")
38
58
  snapshot: Dict[str, Any] = Field(
39
59
  default_factory=dict, description="Full copy of the graph state at the completion of this step."
40
60
  )
41
61
 
42
62
 
43
- class SimulationTrace(BaseModel):
63
+ class SimulationMetrics(CoReasonBaseModel):
64
+ """Metrics gathered during simulation."""
65
+
66
+ turn_count: int
67
+ total_tokens: Optional[int] = None
68
+ cost_usd: Optional[float] = None
69
+ duration_ms: Optional[float] = None
70
+
71
+
72
+ class SimulationTrace(CoReasonBaseModel):
44
73
  """Trace of a simulation execution."""
45
74
 
46
75
  trace_id: UUID = Field(..., description="Unique trace identifier.")
47
76
  agent_version: str = Field(..., description="Agent SemVer version.")
48
77
  steps: List[SimulationStep] = Field(..., description="List of execution steps.")
49
78
  outcome: Dict[str, Any] = Field(..., description="Final result.")
50
- metrics: Dict[str, Any] = Field(..., description="Execution metrics (e.g., token usage, cost).")
79
+ metrics: SimulationMetrics = Field(..., description="Execution metrics (e.g., token usage, cost).")
@@ -0,0 +1,46 @@
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
+
12
+ from typing import Optional
13
+
14
+ from pydantic import Field
15
+
16
+ from coreason_manifest.definitions.agent import Persona
17
+ from coreason_manifest.definitions.base import CoReasonBaseModel
18
+ from coreason_manifest.definitions.simulation import SimulationScenario
19
+
20
+
21
+ class AdversaryProfile(CoReasonBaseModel):
22
+ name: str
23
+ goal: str
24
+ strategy_model: str # e.g., "claude-3-opus"
25
+ attack_model: str # e.g., "llama-3-uncensored"
26
+ persona: Optional[Persona] = Field(None, description="The full persona definition (name, description, directives).")
27
+ # Potential future field: 'system_prompt_override'
28
+
29
+
30
+ class ChaosConfig(CoReasonBaseModel):
31
+ latency_ms: int = Field(default=0, ge=0)
32
+ error_rate: float = Field(default=0.0, ge=0.0, le=1.0)
33
+ noise_rate: float = Field(default=0.0, ge=0.0, le=1.0)
34
+ token_throttle: bool = False
35
+ exception_type: str = "RuntimeError"
36
+
37
+
38
+ class SimulationRequest(CoReasonBaseModel):
39
+ """
40
+ Standard payload for triggering a simulation.
41
+ This would replace the local 'SimulationRequest' in the Simulator.
42
+ """
43
+
44
+ scenario: SimulationScenario
45
+ profile: AdversaryProfile
46
+ chaos_config: ChaosConfig = Field(default_factory=ChaosConfig)