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.
- coreason_manifest/__init__.py +84 -3
- coreason_manifest/definitions/__init__.py +12 -1
- coreason_manifest/definitions/agent.py +95 -17
- coreason_manifest/definitions/audit.py +66 -7
- coreason_manifest/definitions/base.py +47 -0
- coreason_manifest/definitions/events.py +128 -97
- coreason_manifest/definitions/message.py +76 -14
- coreason_manifest/definitions/simulation.py +38 -9
- coreason_manifest/definitions/simulation_config.py +46 -0
- coreason_manifest/definitions/topology.py +104 -18
- coreason_manifest/recipes.py +31 -23
- coreason_manifest/schemas/__init__.py +9 -1
- coreason_manifest/schemas/agent.schema.json +210 -8
- 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.9.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.9.0.dist-info → coreason_manifest-0.10.0.dist-info}/WHEEL +1 -1
- coreason_manifest-0.9.0.dist-info/RECORD +0 -18
- {coreason_manifest-0.9.0.dist-info → coreason_manifest-0.10.0.dist-info}/licenses/LICENSE +0 -0
- {coreason_manifest-0.9.0.dist-info → coreason_manifest-0.10.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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.
|
|
365
|
-
"com_coreason_ui_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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
36
|
-
action: Dict[str, Any] = Field(
|
|
37
|
-
observation: Dict[str, Any] = Field(
|
|
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
|
|
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:
|
|
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)
|