cortex-runtime 0.2.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.
- cortex/__init__.py +51 -0
- cortex/__main__.py +13 -0
- cortex/client.py +263 -0
- cortex/compat.py +20 -0
- cortex/exceptions.py +57 -0
- cortex/plugin.py +50 -0
- cortex/py.typed +1 -0
- cortex/schema/__init__.py +29 -0
- cortex/schema/events.py +127 -0
- cortex/tools/__init__.py +3 -0
- cortex/tools/cli/__init__.py +3 -0
- cortex/tools/cli/main.py +139 -0
- cortex/tools/cli/runner.py +94 -0
- cortex/tools/cli/scaffolder.py +109 -0
- cortex/tools/gen_test_bin.py +35 -0
- cortex/tools/kernel/__init__.py +3 -0
- cortex/tools/kernel/actors/__init__.py +3 -0
- cortex/tools/kernel/actors/executor.py +44 -0
- cortex/tools/kernel/actors/planner.py +38 -0
- cortex/tools/kernel/context.py +22 -0
- cortex/tools/kernel/drivers/__init__.py +3 -0
- cortex/tools/kernel/drivers/mock_robot.py +84 -0
- cortex/tools/kernel/drivers/rtl_verilator.py +49 -0
- cortex/tools/kernel/graph/__init__.py +3 -0
- cortex/tools/kernel/graph/analyzer.py +52 -0
- cortex/tools/kernel/graph/execution_graph.py +44 -0
- cortex/tools/kernel/mailbox.py +35 -0
- cortex/tools/kernel/plugin/__init__.py +3 -0
- cortex/tools/kernel/plugin/loader.py +87 -0
- cortex/tools/kernel/plugin/manifest.py +53 -0
- cortex/tools/kernel/registry.py +36 -0
- cortex/tools/kernel/schema/__init__.py +3 -0
- cortex/tools/kernel/schema/contract.py +16 -0
- cortex/tools/kernel/schema/event.py +54 -0
- cortex/tools/kernel/schema/message.py +105 -0
- cortex/tools/kernel/schema/workflow.py +38 -0
- cortex/tools/kernel/services/__init__.py +3 -0
- cortex/tools/kernel/services/event_store.py +25 -0
- cortex/tools/kernel/services/execution_intelligence.py +49 -0
- cortex/tools/kernel/services/graph_builder.py +81 -0
- cortex/tools/kernel/services/replay.py +50 -0
- cortex/tools/kernel/services/verification.py +85 -0
- cortex/tools/kernel/transport.py +50 -0
- cortex/tools/run_phase2_verification.sh +20 -0
- cortex/tools/verification/__init__.py +5 -0
- cortex/tools/verification/adapters/__init__.py +3 -0
- cortex/tools/verification/adapters/base.py +14 -0
- cortex/tools/verification/adapters/coq.py +73 -0
- cortex/tools/verification/adapters/rtl.py +77 -0
- cortex/tools/verification/adapters/rust.py +72 -0
- cortex/tools/verification/archive.py +58 -0
- cortex/tools/verification/bus.py +28 -0
- cortex/tools/verification/contract.py +70 -0
- cortex/tools/verification/engine.py +121 -0
- cortex/tools/verification/generator/__init__.py +3 -0
- cortex/tools/verification/generator/composer.py +36 -0
- cortex/tools/verification/generator/program.py +46 -0
- cortex/tools/verification/generator/state.py +54 -0
- cortex/tools/verification/invariants/__init__.py +3 -0
- cortex/tools/verification/invariants/capability.py +62 -0
- cortex/tools/verification/metrics/__init__.py +3 -0
- cortex/tools/verification/metrics/base.py +18 -0
- cortex/tools/verification/metrics/opcode.py +25 -0
- cortex/tools/verification/metrics/state_space.py +26 -0
- cortex/tools/verification/metrics/trap.py +26 -0
- cortex/tools/verification/mutation.py +48 -0
- cortex/tools/verification/oracle.py +164 -0
- cortex/tools/verification/schema/__init__.py +44 -0
- cortex/tools/verification/schema/event.py +44 -0
- cortex/tools/verification/shrink.py +26 -0
- cortex/tools/verify.py +64 -0
- cortex_runtime-0.2.0.dist-info/METADATA +220 -0
- cortex_runtime-0.2.0.dist-info/RECORD +76 -0
- cortex_runtime-0.2.0.dist-info/WHEEL +4 -0
- cortex_runtime-0.2.0.dist-info/entry_points.txt +2 -0
- cortex_runtime-0.2.0.dist-info/licenses/LICENSE +201 -0
cortex/tools/cli/main.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cortex Developer CLI Command Entrypoint
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
cortex init <project_name> [--type {app|plugin}]
|
|
6
|
+
cortex workflow run <workflow_file> [--output <file>]
|
|
7
|
+
cortex workflow inspect <workflow_id_or_file>
|
|
8
|
+
cortex workflow replay <workflow_id_or_file>
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
from typing import cast
|
|
16
|
+
|
|
17
|
+
from cortex.exceptions import CortexError
|
|
18
|
+
from cortex.tools.cli.runner import inspect_workflow, replay_workflow, run_workflow_file
|
|
19
|
+
from cortex.tools.cli.scaffolder import scaffold_project
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def cli_entrypoint() -> None:
|
|
23
|
+
"""Console script entrypoint for PyPI cortex-runtime executable."""
|
|
24
|
+
sys.exit(main())
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
28
|
+
"""Main CLI entrypoint for Cortex framework."""
|
|
29
|
+
if argv is None:
|
|
30
|
+
argv = sys.argv[1:]
|
|
31
|
+
|
|
32
|
+
parser = argparse.ArgumentParser(
|
|
33
|
+
prog="cortex",
|
|
34
|
+
description="Cortex Platform Developer CLI & Workflow Engine",
|
|
35
|
+
)
|
|
36
|
+
subparsers = parser.add_subparsers(dest="command", help="Command to execute")
|
|
37
|
+
|
|
38
|
+
# cortex init
|
|
39
|
+
init_parser = subparsers.add_parser("init", help="Scaffold a new Cortex plugin or application")
|
|
40
|
+
_ = init_parser.add_argument("project_name", help="Name of the project directory to create")
|
|
41
|
+
_ = init_parser.add_argument(
|
|
42
|
+
"--type",
|
|
43
|
+
choices=["app", "plugin"],
|
|
44
|
+
default="app",
|
|
45
|
+
help="Type of project to scaffold (default: app)",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# cortex workflow
|
|
49
|
+
wf_parser = subparsers.add_parser("workflow", help="Workflow execution and inspection management")
|
|
50
|
+
wf_sub = wf_parser.add_subparsers(dest="wf_command", help="Workflow subcommand")
|
|
51
|
+
|
|
52
|
+
# cortex workflow run
|
|
53
|
+
wf_run = wf_sub.add_parser("run", help="Trigger workflow execution from spec file")
|
|
54
|
+
_ = wf_run.add_argument("workflow_file", help="Path to workflow definition JSON file")
|
|
55
|
+
_ = wf_run.add_argument("--output", "-o", help="Optional path to save event journal JSON trace")
|
|
56
|
+
|
|
57
|
+
# cortex workflow inspect
|
|
58
|
+
wf_inspect = wf_sub.add_parser("inspect", help="Inspect execution graph and lineage for workflow ID or file")
|
|
59
|
+
_ = wf_inspect.add_argument("workflow_id", help="Workflow ID or path to event trace JSON file")
|
|
60
|
+
|
|
61
|
+
# cortex workflow replay
|
|
62
|
+
wf_replay = wf_sub.add_parser("replay", help="Deterministically replay workflow execution trace")
|
|
63
|
+
_ = wf_replay.add_argument("workflow_id", help="Workflow ID or path to event trace JSON file")
|
|
64
|
+
|
|
65
|
+
args = parser.parse_args(argv)
|
|
66
|
+
cmd = str(getattr(args, "command", ""))
|
|
67
|
+
wf_cmd = str(getattr(args, "wf_command", ""))
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
if cmd == "init":
|
|
71
|
+
p_name = str(getattr(args, "project_name", "my_cortex_app"))
|
|
72
|
+
p_type = str(getattr(args, "type", "app"))
|
|
73
|
+
path = scaffold_project(p_name, project_type=p_type)
|
|
74
|
+
print(f"[+] Successfully scaffolded Cortex {p_type} project at: {path}")
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
elif cmd == "workflow":
|
|
78
|
+
if wf_cmd == "run":
|
|
79
|
+
wf_file = str(getattr(args, "workflow_file", ""))
|
|
80
|
+
out_file = cast(str | None, getattr(args, "output", None))
|
|
81
|
+
res = run_workflow_file(wf_file, output_file=out_file)
|
|
82
|
+
print("[+] Workflow execution finished.")
|
|
83
|
+
print(f" ID: {res['workflow_id']}")
|
|
84
|
+
print(f" State: {res['state']}")
|
|
85
|
+
print(f" Events Log: {res['event_count']}")
|
|
86
|
+
print(f" Trace Saved: {res['output_file']}")
|
|
87
|
+
return 0
|
|
88
|
+
|
|
89
|
+
elif wf_cmd == "inspect":
|
|
90
|
+
wf_id = str(getattr(args, "workflow_id", ""))
|
|
91
|
+
res = inspect_workflow(wf_id)
|
|
92
|
+
causality_tree = cast(list[str], res.get("causality_tree", []))
|
|
93
|
+
failed_nodes = cast(list[dict[str, object]], res.get("failed_nodes", []))
|
|
94
|
+
|
|
95
|
+
print("=== Cortex Execution Graph Inspection ===")
|
|
96
|
+
print(f"Workflow ID: {res['workflow_id']}")
|
|
97
|
+
print(f"Name: {res['name']}")
|
|
98
|
+
print(f"Goal: {res['goal']}")
|
|
99
|
+
print(f"State: {res['state']}")
|
|
100
|
+
print(f"Total Nodes: {res['node_count']}")
|
|
101
|
+
print("\n--- Causality Tree ---")
|
|
102
|
+
for line in causality_tree:
|
|
103
|
+
print(f" {line}")
|
|
104
|
+
if failed_nodes:
|
|
105
|
+
print(f"\n[!] Verification Failures ({len(failed_nodes)}):")
|
|
106
|
+
for node in failed_nodes:
|
|
107
|
+
print(f" - Node {node['id']}: {node['payload']}")
|
|
108
|
+
else:
|
|
109
|
+
print("\n[+] Verification Status: ALL PASSED")
|
|
110
|
+
return 0
|
|
111
|
+
|
|
112
|
+
elif wf_cmd == "replay":
|
|
113
|
+
wf_id = str(getattr(args, "workflow_id", ""))
|
|
114
|
+
res = replay_workflow(wf_id)
|
|
115
|
+
print("=== Cortex Deterministic Replay Engine ===")
|
|
116
|
+
print(f"Workflow ID: {res['workflow_id']}")
|
|
117
|
+
print(f"Events Replayed: {res['events_replayed']}")
|
|
118
|
+
print(f"Status: {'SUCCESS' if res['deterministic'] else 'FAILED'}")
|
|
119
|
+
print(f"Result: {res['verification_result']}")
|
|
120
|
+
return 0 if res["deterministic"] else 1
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
wf_parser.print_help(sys.stderr)
|
|
124
|
+
return 1
|
|
125
|
+
|
|
126
|
+
else:
|
|
127
|
+
parser.print_help(sys.stderr)
|
|
128
|
+
return 1
|
|
129
|
+
|
|
130
|
+
except CortexError as err:
|
|
131
|
+
print(f"[!] Cortex Error: {err.message}", file=sys.stderr)
|
|
132
|
+
return err.exit_code
|
|
133
|
+
except Exception as err:
|
|
134
|
+
print(f"[!] Unexpected Error: {err}", file=sys.stderr)
|
|
135
|
+
return getattr(os, "EX_SOFTWARE", 1)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
sys.exit(main())
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Thin CLI Adapter Engine for Cortex Platform
|
|
3
|
+
|
|
4
|
+
Delegates workflow lifecycle execution, trace inspection, and deterministic
|
|
5
|
+
replay directly to the public CortexClient API. Contains zero state machine logic.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
from cortex.client import CortexClient
|
|
13
|
+
from cortex.exceptions import WorkflowExecutionError
|
|
14
|
+
from cortex.schema import IntentEvent, WorkflowPolicy
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def run_workflow_file(workflow_file: str, output_file: str | None = None) -> dict[str, str | int]:
|
|
18
|
+
"""Runs a workflow file by instantiating CortexClient thin wrapper."""
|
|
19
|
+
if not os.path.exists(workflow_file):
|
|
20
|
+
raise WorkflowExecutionError(f"Workflow file not found: {workflow_file}")
|
|
21
|
+
|
|
22
|
+
with open(workflow_file, "r", encoding="utf-8") as f:
|
|
23
|
+
if workflow_file.endswith(".yaml") or workflow_file.endswith(".yml"):
|
|
24
|
+
import yaml
|
|
25
|
+
data = cast(dict[str, object], yaml.safe_load(f)) or {}
|
|
26
|
+
else:
|
|
27
|
+
data = cast(dict[str, object], json.load(f))
|
|
28
|
+
|
|
29
|
+
client = CortexClient()
|
|
30
|
+
|
|
31
|
+
wf_name = str(data.get("name", "cli_workflow"))
|
|
32
|
+
wf_goal = str(data.get("goal", "Execute CLI workflow"))
|
|
33
|
+
policy_data = cast(dict[str, object], data.get("policy", {}))
|
|
34
|
+
|
|
35
|
+
policy = WorkflowPolicy(
|
|
36
|
+
timeout_seconds=float(str(policy_data.get("timeout_seconds", 300.0))),
|
|
37
|
+
max_retries=int(str(policy_data.get("max_retries", 3))),
|
|
38
|
+
abort_on_verification_failure=bool(policy_data.get("abort_on_verification_failure", True)),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
workflow = client.create_workflow(name=wf_name, goal=wf_goal, policy=policy)
|
|
42
|
+
|
|
43
|
+
intent_data = cast(dict[str, object], data.get("initial_intent", {}))
|
|
44
|
+
initial_intent = IntentEvent(
|
|
45
|
+
workflow_id=workflow.workflow_id,
|
|
46
|
+
goal=str(intent_data.get("goal", wf_goal)),
|
|
47
|
+
parameters=cast(dict[str, object], intent_data.get("parameters", {})),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
executed_wf = client.run_workflow(workflow, initial_intent=initial_intent)
|
|
51
|
+
|
|
52
|
+
if output_file is None:
|
|
53
|
+
cortex_dir = os.path.join(os.getcwd(), ".cortex", "events")
|
|
54
|
+
output_file = os.path.join(cortex_dir, f"{executed_wf.workflow_id}.json")
|
|
55
|
+
|
|
56
|
+
saved_path = client.save_trace(executed_wf.workflow_id, output_file, name=wf_name, goal=wf_goal)
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
"workflow_id": executed_wf.workflow_id,
|
|
60
|
+
"state": executed_wf.state.value,
|
|
61
|
+
"event_count": len(client.event_store.get_log()),
|
|
62
|
+
"output_file": saved_path,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def inspect_workflow(trace_path_or_id: str) -> dict[str, str | int | list[str] | list[dict[str, object]]]:
|
|
67
|
+
"""Delegates trace inspection to CortexClient."""
|
|
68
|
+
client = CortexClient()
|
|
69
|
+
res = client.inspect_workflow(trace_path_or_id)
|
|
70
|
+
causality_tree = cast(list[str], res.get("causality_tree", []))
|
|
71
|
+
failed_nodes = cast(list[dict[str, object]], res.get("failed_nodes", []))
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
"workflow_id": trace_path_or_id,
|
|
75
|
+
"name": cast(str, res.get("name", "Inspected Workflow")),
|
|
76
|
+
"goal": cast(str, res.get("goal", "Trace Inspection")),
|
|
77
|
+
"state": "FAILED" if failed_nodes else "COMPLETED",
|
|
78
|
+
"node_count": cast(int, res.get("node_count", 0)),
|
|
79
|
+
"total_events": cast(int, res.get("total_events", 0)),
|
|
80
|
+
"causality_tree": causality_tree,
|
|
81
|
+
"failed_nodes": failed_nodes,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def replay_workflow(trace_path_or_id: str) -> dict[str, str | int | bool]:
|
|
86
|
+
"""Delegates trace replay to CortexClient."""
|
|
87
|
+
client = CortexClient()
|
|
88
|
+
res = client.replay_workflow(trace_path_or_id)
|
|
89
|
+
return {
|
|
90
|
+
"workflow_id": trace_path_or_id,
|
|
91
|
+
"events_replayed": cast(int, res.get("replayed_count", 0)),
|
|
92
|
+
"deterministic": cast(bool, res.get("deterministic", False)),
|
|
93
|
+
"verification_result": cast(str, res.get("reason", "")),
|
|
94
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cortex Project Scaffolding Engine
|
|
3
|
+
|
|
4
|
+
Scaffolds a new Cortex application or plugin project template with declarative
|
|
5
|
+
manifests, workflow definitions, and sample handlers adhering to public Cortex standards.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def scaffold_project(project_name: str, project_type: str = "app", target_dir: str | None = None) -> str:
|
|
13
|
+
"""Scaffolds a standard Cortex application or plugin project directory structure."""
|
|
14
|
+
if target_dir is None:
|
|
15
|
+
target_dir = os.path.join(os.getcwd(), project_name)
|
|
16
|
+
|
|
17
|
+
os.makedirs(target_dir, exist_ok=True)
|
|
18
|
+
|
|
19
|
+
cortex_config: dict[str, str] = {
|
|
20
|
+
"name": project_name,
|
|
21
|
+
"type": project_type,
|
|
22
|
+
"version": "0.1.0",
|
|
23
|
+
"cortex_version": "0.2.0",
|
|
24
|
+
"entrypoint": "main.py" if project_type == "app" else "plugin.py",
|
|
25
|
+
}
|
|
26
|
+
with open(os.path.join(target_dir, "cortex.json"), "w", encoding="utf-8") as f:
|
|
27
|
+
json.dump(cortex_config, f, indent=2)
|
|
28
|
+
|
|
29
|
+
plugin_manifest: dict[str, str | list[str]] = {
|
|
30
|
+
"name": f"{project_name}-plugin",
|
|
31
|
+
"version": "0.1.0",
|
|
32
|
+
"description": f"Custom {project_type} plugin for {project_name}",
|
|
33
|
+
"consumes_events": ["IntentEvent"],
|
|
34
|
+
"produces_events": ["PlanGeneratedEvent", "CommandIssuedEvent"],
|
|
35
|
+
"required_capabilities": ["workflow.plan.create", "workflow.command.issue"],
|
|
36
|
+
}
|
|
37
|
+
with open(os.path.join(target_dir, "manifest.json"), "w", encoding="utf-8") as f:
|
|
38
|
+
json.dump(plugin_manifest, f, indent=2)
|
|
39
|
+
|
|
40
|
+
workflow_def: dict[str, object] = {
|
|
41
|
+
"name": f"{project_name}_workflow",
|
|
42
|
+
"goal": f"Execute default workflow for {project_name}",
|
|
43
|
+
"policy": {
|
|
44
|
+
"timeout_seconds": 300.0,
|
|
45
|
+
"max_retries": 3,
|
|
46
|
+
"abort_on_verification_failure": True,
|
|
47
|
+
},
|
|
48
|
+
"initial_intent": {
|
|
49
|
+
"goal": f"Initialize {project_name} execution",
|
|
50
|
+
"parameters": {"environment": "development"},
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
with open(os.path.join(target_dir, "workflow.json"), "w", encoding="utf-8") as f:
|
|
54
|
+
json.dump(workflow_def, f, indent=2)
|
|
55
|
+
|
|
56
|
+
code_content = _generate_sample_code(project_name, project_type)
|
|
57
|
+
code_filename = "main.py" if project_type == "app" else "plugin.py"
|
|
58
|
+
with open(os.path.join(target_dir, code_filename), "w", encoding="utf-8") as f:
|
|
59
|
+
_ = f.write(code_content)
|
|
60
|
+
|
|
61
|
+
return target_dir
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _generate_sample_code(project_name: str, project_type: str) -> str:
|
|
65
|
+
if project_type == "plugin":
|
|
66
|
+
return f'''"""
|
|
67
|
+
Plugin Handler for {project_name}
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
from cortex import BasePlugin, PluginManifest, IntentEvent, PlanGeneratedEvent
|
|
71
|
+
|
|
72
|
+
MANIFEST = PluginManifest(
|
|
73
|
+
name="{project_name}-plugin",
|
|
74
|
+
version="0.1.0",
|
|
75
|
+
description="Custom plugin for {project_name}",
|
|
76
|
+
consumes_events=["IntentEvent"],
|
|
77
|
+
produces_events=["PlanGeneratedEvent"],
|
|
78
|
+
required_capabilities=["workflow.plan.create"],
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
class CustomPlugin(BasePlugin):
|
|
82
|
+
def __init__(self):
|
|
83
|
+
super().__init__(MANIFEST)
|
|
84
|
+
|
|
85
|
+
def on_event(self, event):
|
|
86
|
+
if isinstance(event, IntentEvent) and self.context:
|
|
87
|
+
plan = PlanGeneratedEvent(
|
|
88
|
+
intent_id=event.intent_id,
|
|
89
|
+
workflow_id=event.workflow_id,
|
|
90
|
+
steps=[{{"step": 1, "action": "initialize"}}]
|
|
91
|
+
)
|
|
92
|
+
self.context.publish(plan)
|
|
93
|
+
'''
|
|
94
|
+
return f'''"""
|
|
95
|
+
Application Handler for {project_name}
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
from cortex import CortexClient, IntentEvent
|
|
99
|
+
|
|
100
|
+
def run_app():
|
|
101
|
+
client = CortexClient()
|
|
102
|
+
workflow = client.create_workflow(name="{project_name}_workflow", goal="Run autonomous task")
|
|
103
|
+
intent = IntentEvent(workflow_id=workflow.workflow_id, goal=workflow.goal)
|
|
104
|
+
executed = client.run_workflow(workflow, initial_intent=intent)
|
|
105
|
+
print(f"Workflow {{executed.workflow_id}} status: {{executed.state.value}}")
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
run_app()
|
|
109
|
+
'''
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import os
|
|
3
|
+
import struct
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def encode_inst(opcode: int, stcr_id: int, arg_reg: int, imm: int) -> int:
|
|
7
|
+
return ((opcode & 0x3F) << 26) | ((stcr_id & 0x1F) << 21) | ((arg_reg & 0x1F) << 16) | (imm & 0xFFFF)
|
|
8
|
+
|
|
9
|
+
def generate_canonical_test_bin(output_path: str):
|
|
10
|
+
MAGIC = b"CORTEX"
|
|
11
|
+
VERSION = 1
|
|
12
|
+
|
|
13
|
+
# Sequence of instructions exercising all SDS v1.0 refinement properties:
|
|
14
|
+
instructions = [
|
|
15
|
+
encode_inst(0x01, 0, 1, 0), # PC 0: invoke_cap STCR0, R1 -> Expected: COMMIT (Valid)
|
|
16
|
+
encode_inst(0x03, 0, 0, 0x4000), # PC 1: restrict_cap STCR0, READ (Bit 62) -> Expected: COMMIT
|
|
17
|
+
encode_inst(0x01, 0, 2, 0), # PC 2: invoke_cap STCR0, R2 -> Expected: COMMIT
|
|
18
|
+
encode_inst(0x05, 0, 0, 0), # PC 3: hec.inc -> Expected: COMMIT (Epoch = 1)
|
|
19
|
+
encode_inst(0x01, 0, 3, 0), # PC 4: invoke_cap STCR0, R3 -> Expected: EFF_TRAP (Epoch Expired if Max_Epoch == 0)
|
|
20
|
+
encode_inst(0x00, 0, 0, 0), # PC 5: Opcode 0x00 -> Expected: EFF_TRAP (Illegal/Reserved Opcode)
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
header = MAGIC + struct.pack(">H", VERSION) + struct.pack(">I", len(instructions))
|
|
24
|
+
payload = b"".join(struct.pack(">I", inst) for inst in instructions)
|
|
25
|
+
|
|
26
|
+
os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
|
|
27
|
+
with open(output_path, "wb") as f:
|
|
28
|
+
f.write(header + payload)
|
|
29
|
+
|
|
30
|
+
print(f"[+] Canonical test binary successfully generated at {output_path} ({len(header + payload)} bytes)")
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
import sys
|
|
34
|
+
out_path = sys.argv[1] if len(sys.argv) > 1 else "tests/canonical_test_program.bin"
|
|
35
|
+
generate_canonical_test_bin(out_path)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TaskExecutor Actor
|
|
3
|
+
|
|
4
|
+
Consumes: PlanGeneratedEvent
|
|
5
|
+
Produces: CommandIssuedEvent
|
|
6
|
+
|
|
7
|
+
Iterates over the steps within a PlanGeneratedEvent and issues
|
|
8
|
+
individual CommandIssuedEvent instances to the driver layer.
|
|
9
|
+
The executor has zero knowledge of which driver will consume
|
|
10
|
+
the command — it only knows the message contract.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
from typing import cast
|
|
15
|
+
|
|
16
|
+
from cortex.tools.kernel.context import RuntimeContext
|
|
17
|
+
from cortex.tools.kernel.schema.message import CommandIssuedEvent, PlanGeneratedEvent
|
|
18
|
+
from cortex.tools.kernel.transport import AnyEvent
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TaskExecutorActor:
|
|
22
|
+
context: RuntimeContext
|
|
23
|
+
publish_cb: Callable[[AnyEvent], object]
|
|
24
|
+
|
|
25
|
+
def __init__(self, context: RuntimeContext, publish_cb: Callable[[AnyEvent], object]):
|
|
26
|
+
self.context = context
|
|
27
|
+
self.publish_cb = publish_cb
|
|
28
|
+
|
|
29
|
+
def handle_plan(self, plan: PlanGeneratedEvent) -> list[CommandIssuedEvent]:
|
|
30
|
+
commands: list[CommandIssuedEvent] = []
|
|
31
|
+
for step in plan.steps:
|
|
32
|
+
action_val = str(step.get("action", "unknown"))
|
|
33
|
+
params_val = step.get("parameters", {})
|
|
34
|
+
params_dict = cast(dict[str, object], params_val) if isinstance(params_val, dict) else {}
|
|
35
|
+
|
|
36
|
+
cmd = CommandIssuedEvent(
|
|
37
|
+
plan_id=plan.plan_id,
|
|
38
|
+
correlation_id=plan.correlation_id,
|
|
39
|
+
action=action_val,
|
|
40
|
+
parameters=params_dict,
|
|
41
|
+
)
|
|
42
|
+
commands.append(cmd)
|
|
43
|
+
self.publish_cb(cmd)
|
|
44
|
+
return commands
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
IntentPlanner Actor
|
|
3
|
+
|
|
4
|
+
Consumes: IntentEvent
|
|
5
|
+
Produces: PlanGeneratedEvent
|
|
6
|
+
|
|
7
|
+
Decomposes a high-level goal intent into an ordered sequence of
|
|
8
|
+
actionable steps. The planner has zero knowledge of downstream
|
|
9
|
+
executors or drivers — it only knows the message contract.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from cortex.tools.kernel.context import RuntimeContext
|
|
16
|
+
from cortex.tools.kernel.schema.message import IntentEvent, PlanGeneratedEvent
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class IntentPlannerActor:
|
|
20
|
+
context: RuntimeContext
|
|
21
|
+
publish_cb: Callable[[Any], object]
|
|
22
|
+
|
|
23
|
+
def __init__(self, context: RuntimeContext, publish_cb: Callable[[Any], object]):
|
|
24
|
+
self.context = context
|
|
25
|
+
self.publish_cb = publish_cb
|
|
26
|
+
|
|
27
|
+
def handle_intent(self, intent: IntentEvent) -> PlanGeneratedEvent:
|
|
28
|
+
steps = [
|
|
29
|
+
{"action": "move_actuator", "parameters": {"actuator": "arm_joint_1", "delta": 10.0}},
|
|
30
|
+
{"action": "move_actuator", "parameters": {"actuator": "arm_joint_2", "delta": -5.0}},
|
|
31
|
+
]
|
|
32
|
+
plan = PlanGeneratedEvent(
|
|
33
|
+
intent_id=intent.intent_id,
|
|
34
|
+
correlation_id=intent.session_id,
|
|
35
|
+
steps=steps,
|
|
36
|
+
)
|
|
37
|
+
self.publish_cb(plan)
|
|
38
|
+
return plan
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Runtime Context Provided to Kernel Actors
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from cortex.tools.kernel.mailbox import Mailbox
|
|
6
|
+
from cortex.tools.kernel.transport import AnyEvent, InMemoryTransport
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RuntimeContext:
|
|
10
|
+
actor_id: str
|
|
11
|
+
session_id: str
|
|
12
|
+
mailbox: Mailbox
|
|
13
|
+
_transport: InMemoryTransport
|
|
14
|
+
|
|
15
|
+
def __init__(self, actor_id: str, session_id: str, transport: InMemoryTransport):
|
|
16
|
+
self.actor_id = actor_id
|
|
17
|
+
self.session_id = session_id
|
|
18
|
+
self.mailbox = Mailbox()
|
|
19
|
+
self._transport = transport
|
|
20
|
+
|
|
21
|
+
def publish(self, event: AnyEvent) -> None:
|
|
22
|
+
self._transport.publish(event)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock Robot Driver
|
|
3
|
+
|
|
4
|
+
Consumes: CommandIssuedEvent
|
|
5
|
+
Produces: DriverTelemetryEvent
|
|
6
|
+
|
|
7
|
+
Translates abstract commands into simulated actuator state changes
|
|
8
|
+
and emits raw telemetry facts. The driver has zero knowledge of
|
|
9
|
+
upstream planners or downstream verification services.
|
|
10
|
+
|
|
11
|
+
Also provides a legacy step_actuator() method for Stage 2
|
|
12
|
+
verification domain tests that operate through the event.py
|
|
13
|
+
MotorFeedbackEvent hierarchy.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
from typing import cast
|
|
18
|
+
|
|
19
|
+
from cortex.tools.kernel.context import RuntimeContext
|
|
20
|
+
from cortex.tools.kernel.schema.event import MotorFeedbackEvent
|
|
21
|
+
from cortex.tools.kernel.schema.message import CommandIssuedEvent, DriverTelemetryEvent
|
|
22
|
+
from cortex.tools.kernel.transport import AnyEvent
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MockRobotDriver:
|
|
26
|
+
context: RuntimeContext
|
|
27
|
+
actuator_id: str
|
|
28
|
+
publish_cb: Callable[[AnyEvent], object]
|
|
29
|
+
positions: dict[str, float]
|
|
30
|
+
position: float
|
|
31
|
+
velocity: float
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
context: RuntimeContext,
|
|
36
|
+
actuator_id_or_cb: str | Callable[[AnyEvent], object] = "arm_joint_1",
|
|
37
|
+
publish_cb: Callable[[AnyEvent], object] | None = None,
|
|
38
|
+
):
|
|
39
|
+
self.context = context
|
|
40
|
+
if callable(actuator_id_or_cb):
|
|
41
|
+
self.actuator_id = "arm_joint_1"
|
|
42
|
+
self.publish_cb = actuator_id_or_cb
|
|
43
|
+
else:
|
|
44
|
+
self.actuator_id = str(actuator_id_or_cb)
|
|
45
|
+
self.publish_cb = publish_cb or context.publish
|
|
46
|
+
|
|
47
|
+
self.positions = {"arm_joint_1": 0.0, "arm_joint_2": 0.0}
|
|
48
|
+
self.position = 0.0
|
|
49
|
+
self.velocity = 0.0
|
|
50
|
+
|
|
51
|
+
# -- Verification Domain (event.py hierarchy) --------------------------
|
|
52
|
+
|
|
53
|
+
def step_actuator(self, delta_pos: float, velocity: float) -> None:
|
|
54
|
+
"""Stage 2 verification interface emitting MotorFeedbackEvent."""
|
|
55
|
+
self.position += delta_pos
|
|
56
|
+
self.velocity = velocity
|
|
57
|
+
event = MotorFeedbackEvent(
|
|
58
|
+
session_id=self.context.session_id,
|
|
59
|
+
actuator_id=self.actuator_id,
|
|
60
|
+
position=self.position,
|
|
61
|
+
velocity=self.velocity,
|
|
62
|
+
)
|
|
63
|
+
_ = self.publish_cb(event)
|
|
64
|
+
|
|
65
|
+
# -- Kernel Runtime Domain (message.py hierarchy) ----------------------
|
|
66
|
+
|
|
67
|
+
def handle_command(self, cmd: CommandIssuedEvent) -> DriverTelemetryEvent:
|
|
68
|
+
"""Stage 4 kernel interface consuming CommandIssuedEvent."""
|
|
69
|
+
actuator = cast(str, cmd.parameters.get("actuator", "arm_joint_1"))
|
|
70
|
+
delta = float(cast(int | float, cmd.parameters.get("delta", 0.0)))
|
|
71
|
+
|
|
72
|
+
current = self.positions.get(actuator, 0.0) + delta
|
|
73
|
+
self.positions[actuator] = current
|
|
74
|
+
|
|
75
|
+
telemetry = DriverTelemetryEvent(
|
|
76
|
+
causation_id=cmd.command_id,
|
|
77
|
+
correlation_id=cmd.correlation_id,
|
|
78
|
+
root_id=cmd.plan_id,
|
|
79
|
+
driver_id=actuator,
|
|
80
|
+
status="ok",
|
|
81
|
+
payload={"actuator": actuator, "position": current, "delta": delta},
|
|
82
|
+
)
|
|
83
|
+
_ = self.publish_cb(telemetry)
|
|
84
|
+
return telemetry
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RTL Verilator Driver for Hardware Telemetry & Trace Ingestion
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
from cortex.tools.kernel.context import RuntimeContext
|
|
10
|
+
from cortex.tools.kernel.schema.event import RawRTLTraceEvent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RTLVerilatorDriver:
|
|
14
|
+
context: RuntimeContext
|
|
15
|
+
|
|
16
|
+
def __init__(self, context: RuntimeContext):
|
|
17
|
+
self.context = context
|
|
18
|
+
|
|
19
|
+
def ingest_trace_file(self, trace_json_path: str = "rtl_trace.json") -> int:
|
|
20
|
+
if not os.path.exists(trace_json_path):
|
|
21
|
+
fallback = "Research/artifacts/phase2/rtl_trace.json"
|
|
22
|
+
if os.path.exists(fallback):
|
|
23
|
+
trace_json_path = fallback
|
|
24
|
+
|
|
25
|
+
with open(trace_json_path, "r") as f:
|
|
26
|
+
data = cast(dict[str, object], json.load(f))
|
|
27
|
+
|
|
28
|
+
frames = cast(list[dict[str, object]], data.get("trace", []))
|
|
29
|
+
for frame in frames:
|
|
30
|
+
seq_num = int(cast(int | float, frame.get("step", 0)))
|
|
31
|
+
pc_val = int(cast(int | float, frame.get("pc", 0)))
|
|
32
|
+
raw_inst = str(frame.get("raw_instruction", "0x00000000"))
|
|
33
|
+
eff_trap = bool(frame.get("eff_trap", False))
|
|
34
|
+
trap_cause = int(cast(int | float, frame.get("trap_cause", 0)))
|
|
35
|
+
stcr_list = cast(list[object], frame.get("stcr_registers", []))
|
|
36
|
+
stcr_regs = {idx: str(val) for idx, val in enumerate(stcr_list)}
|
|
37
|
+
|
|
38
|
+
event = RawRTLTraceEvent(
|
|
39
|
+
session_id=self.context.session_id,
|
|
40
|
+
sequence_number=seq_num,
|
|
41
|
+
pc=pc_val,
|
|
42
|
+
raw_instruction=raw_inst,
|
|
43
|
+
eff_trap=eff_trap,
|
|
44
|
+
trap_cause=trap_cause,
|
|
45
|
+
stcr_registers=stcr_regs
|
|
46
|
+
)
|
|
47
|
+
self.context.publish(event)
|
|
48
|
+
|
|
49
|
+
return len(frames)
|