syntropy-core 0.1.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.
- syntropy/__init__.py +39 -0
- syntropy/agent.py +75 -0
- syntropy/cli.py +151 -0
- syntropy/contract.py +486 -0
- syntropy/core/__init__.py +17 -0
- syntropy/core/connections.py +89 -0
- syntropy/core/contributions.py +56 -0
- syntropy/core/operations.py +111 -0
- syntropy/core/ordering.py +84 -0
- syntropy/core/routing.py +184 -0
- syntropy/core/scheduler.py +83 -0
- syntropy/core/structural.py +275 -0
- syntropy/interfaces.py +54 -0
- syntropy/lattice.py +856 -0
- syntropy/llm/__init__.py +7 -0
- syntropy/llm/mock.py +14 -0
- syntropy/llm/ollama.py +105 -0
- syntropy/llm/openai.py +129 -0
- syntropy/memory/__init__.py +5 -0
- syntropy/memory/in_memory.py +27 -0
- syntropy/observation/__init__.py +6 -0
- syntropy/observation/bus.py +60 -0
- syntropy/observation/events.py +246 -0
- syntropy/recommendation.py +36 -0
- syntropy/replay.py +71 -0
- syntropy/resources/__init__.py +1 -0
- syntropy/resources/shared/__init__.py +1 -0
- syntropy/resources/shared/auto-strategy-fixtures.json +89 -0
- syntropy/resources/shared/axioms.json +56 -0
- syntropy/resources/shared/connection-fixtures.json +107 -0
- syntropy/resources/shared/ema-fixtures.json +75 -0
- syntropy/resources/shared/ordering-fixtures.json +70 -0
- syntropy/resources/shared/replay-demo.json +361 -0
- syntropy/resources/shared/replay-fixtures.json +117 -0
- syntropy/resources/shared/routing-fixtures.json +108 -0
- syntropy/resources/shared/runtime-events.json +103 -0
- syntropy/resources/shared/runtime-scoring.json +27 -0
- syntropy/resources/shared/runtime-topology.json +13 -0
- syntropy/resources/shared/structural-decision-fixtures.json +220 -0
- syntropy/resources/shared/trust-policy.json +30 -0
- syntropy/runtime.py +92 -0
- syntropy/scanner.py +157 -0
- syntropy/settings.py +137 -0
- syntropy/task.py +62 -0
- syntropy/visualization/__init__.py +5 -0
- syntropy/visualization/lattice_renderer.py +16 -0
- syntropy_core-0.1.0.dist-info/METADATA +43 -0
- syntropy_core-0.1.0.dist-info/RECORD +50 -0
- syntropy_core-0.1.0.dist-info/WHEEL +4 -0
- syntropy_core-0.1.0.dist-info/entry_points.txt +2 -0
syntropy/__init__.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Public API for the Syntropy Python scaffold."""
|
|
2
|
+
|
|
3
|
+
from .agent import Agent, AgentConnection, AgentScoreVector
|
|
4
|
+
from .interfaces import Embedder, EventExporter, LLMAdapter, MemoryStore
|
|
5
|
+
from .lattice import Lattice
|
|
6
|
+
from .llm import MockLLMAdapter, OllamaAdapter, OpenAIAdapter
|
|
7
|
+
from .recommendation import RecommendationEvidence, StructuralRecommendation
|
|
8
|
+
from .replay import LatticeSnapshot, ReplayAgentState, ReplayBundle, ReplayRecord
|
|
9
|
+
from .runtime import Runtime
|
|
10
|
+
from .settings import SyntropySettings
|
|
11
|
+
from .task import SelectionTraceEntry, Task, TaskResult, Thought
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Agent",
|
|
17
|
+
"AgentConnection",
|
|
18
|
+
"AgentScoreVector",
|
|
19
|
+
"Embedder",
|
|
20
|
+
"EventExporter",
|
|
21
|
+
"LLMAdapter",
|
|
22
|
+
"Lattice",
|
|
23
|
+
"SyntropySettings",
|
|
24
|
+
"LatticeSnapshot",
|
|
25
|
+
"MemoryStore",
|
|
26
|
+
"MockLLMAdapter",
|
|
27
|
+
"OllamaAdapter",
|
|
28
|
+
"OpenAIAdapter",
|
|
29
|
+
"RecommendationEvidence",
|
|
30
|
+
"ReplayAgentState",
|
|
31
|
+
"ReplayBundle",
|
|
32
|
+
"ReplayRecord",
|
|
33
|
+
"Runtime",
|
|
34
|
+
"SelectionTraceEntry",
|
|
35
|
+
"StructuralRecommendation",
|
|
36
|
+
"Task",
|
|
37
|
+
"TaskResult",
|
|
38
|
+
"Thought",
|
|
39
|
+
]
|
syntropy/agent.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Agent data structures for the Syntropy Python scaffold."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _clamp_score(value: float) -> float:
|
|
9
|
+
return max(0.0, min(1.0, value))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True, slots=True)
|
|
13
|
+
class AgentConnection:
|
|
14
|
+
"""Represents a weighted connection to another agent."""
|
|
15
|
+
|
|
16
|
+
target_agent_id: str
|
|
17
|
+
weight: float
|
|
18
|
+
interactions: int = 0
|
|
19
|
+
|
|
20
|
+
def __post_init__(self) -> None:
|
|
21
|
+
object.__setattr__(self, "weight", _clamp_score(self.weight))
|
|
22
|
+
object.__setattr__(self, "interactions", max(0, self.interactions))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, slots=True)
|
|
26
|
+
class AgentScoreVector:
|
|
27
|
+
"""Stores component scores used to compute lattice position."""
|
|
28
|
+
|
|
29
|
+
knowledge: float = 0.0
|
|
30
|
+
synthesis: float = 0.0
|
|
31
|
+
connections: float = 0.0
|
|
32
|
+
|
|
33
|
+
def __post_init__(self) -> None:
|
|
34
|
+
object.__setattr__(self, "knowledge", _clamp_score(self.knowledge))
|
|
35
|
+
object.__setattr__(self, "synthesis", _clamp_score(self.synthesis))
|
|
36
|
+
object.__setattr__(self, "connections", _clamp_score(self.connections))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True, slots=True)
|
|
40
|
+
class Agent:
|
|
41
|
+
"""Immutable agent state for lattice operations."""
|
|
42
|
+
|
|
43
|
+
id: str
|
|
44
|
+
name: str
|
|
45
|
+
perspective: str
|
|
46
|
+
knowledge_items: tuple[str, ...] = ()
|
|
47
|
+
score_vector: AgentScoreVector = field(default_factory=AgentScoreVector)
|
|
48
|
+
connections: tuple[AgentConnection, ...] = ()
|
|
49
|
+
position: float = 0.0
|
|
50
|
+
temporary: bool = False
|
|
51
|
+
parent_ids: tuple[str, ...] = ()
|
|
52
|
+
lineage_ids: tuple[str, ...] = ()
|
|
53
|
+
source_names: tuple[str, ...] = ()
|
|
54
|
+
perspective_labels: tuple[str, ...] = ()
|
|
55
|
+
|
|
56
|
+
def __post_init__(self) -> None:
|
|
57
|
+
object.__setattr__(self, "knowledge_items", tuple(self.knowledge_items))
|
|
58
|
+
object.__setattr__(self, "connections", tuple(self.connections))
|
|
59
|
+
object.__setattr__(self, "parent_ids", tuple(self.parent_ids))
|
|
60
|
+
object.__setattr__(
|
|
61
|
+
self,
|
|
62
|
+
"lineage_ids",
|
|
63
|
+
tuple(self.lineage_ids) if self.lineage_ids or self.parent_ids else (self.id,),
|
|
64
|
+
)
|
|
65
|
+
object.__setattr__(
|
|
66
|
+
self,
|
|
67
|
+
"source_names",
|
|
68
|
+
tuple(self.source_names) if self.source_names else (self.name,),
|
|
69
|
+
)
|
|
70
|
+
object.__setattr__(
|
|
71
|
+
self,
|
|
72
|
+
"perspective_labels",
|
|
73
|
+
tuple(self.perspective_labels) if self.perspective_labels else (self.perspective,),
|
|
74
|
+
)
|
|
75
|
+
object.__setattr__(self, "position", _clamp_score(self.position))
|
syntropy/cli.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from syntropy import __version__
|
|
7
|
+
from syntropy.scanner import scan_local_path
|
|
8
|
+
from syntropy.settings import load_settings
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(
|
|
11
|
+
name="syntropy",
|
|
12
|
+
help="Syntropy: Observable multi-agent execution runtime.",
|
|
13
|
+
add_completion=False,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def version_callback(value: bool) -> None:
|
|
17
|
+
if value:
|
|
18
|
+
typer.echo(f"Syntropy CLI version: {__version__}")
|
|
19
|
+
raise typer.Exit()
|
|
20
|
+
|
|
21
|
+
@app.callback()
|
|
22
|
+
def main(
|
|
23
|
+
version: bool | None = typer.Option(
|
|
24
|
+
None,
|
|
25
|
+
"--version",
|
|
26
|
+
callback=version_callback,
|
|
27
|
+
is_eager=True,
|
|
28
|
+
help="Show the version and exit.",
|
|
29
|
+
)
|
|
30
|
+
) -> None:
|
|
31
|
+
"""
|
|
32
|
+
Syntropy CLI
|
|
33
|
+
"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
@app.command()
|
|
37
|
+
def info() -> None:
|
|
38
|
+
"""
|
|
39
|
+
Show current environment configuration and active providers.
|
|
40
|
+
"""
|
|
41
|
+
settings = load_settings()
|
|
42
|
+
typer.echo("Syntropy Environment Info:")
|
|
43
|
+
typer.echo(f" LLM Provider: {settings.llm_provider}")
|
|
44
|
+
typer.echo(f" Effective Model: {settings.effective_model}")
|
|
45
|
+
typer.echo(f" Effective Base URL: {settings.effective_base_url}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@app.command()
|
|
49
|
+
def review(
|
|
50
|
+
path_or_url: str = typer.Argument(..., help="Local path or GitHub URL to review."),
|
|
51
|
+
goal: str = typer.Option(
|
|
52
|
+
"Find the safest next architecture move",
|
|
53
|
+
"--goal",
|
|
54
|
+
help="The review goal.",
|
|
55
|
+
),
|
|
56
|
+
output_format: str = typer.Option(
|
|
57
|
+
"markdown",
|
|
58
|
+
"--format",
|
|
59
|
+
help="Output format (markdown or json).",
|
|
60
|
+
),
|
|
61
|
+
) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Review a codebase and produce a source-grounded recommendation.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
# 1. Ingest
|
|
67
|
+
if path_or_url.startswith("http://") or path_or_url.startswith("https://"):
|
|
68
|
+
if output_format != "json":
|
|
69
|
+
typer.echo(f"[✓] Validating GitHub URL: {path_or_url}")
|
|
70
|
+
# Note: The platform does GitHub URL fetching. For the CLI communicating with Elixir,
|
|
71
|
+
# we might just pass repoUrl, but Elixir currently expects a source_review object.
|
|
72
|
+
# We will mock the context packet for the URL for now, or just raise NotImplementedError
|
|
73
|
+
# if the Python CLI strictly handles local.
|
|
74
|
+
typer.echo("Error: GitHub URL ingestion via CLI is delegated to the web platform for now.")
|
|
75
|
+
raise typer.Exit(code=1)
|
|
76
|
+
else:
|
|
77
|
+
if output_format != "json":
|
|
78
|
+
typer.echo(f"[✓] Scanning local repository: {path_or_url}")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
packet = scan_local_path(path_or_url, goal)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
typer.echo(f"Error scanning local path: {e}")
|
|
84
|
+
raise typer.Exit(code=1) from e
|
|
85
|
+
|
|
86
|
+
if output_format != "json":
|
|
87
|
+
typer.echo(f"[✓] Context packet built ({len(packet.file_inventory)} files indexed)")
|
|
88
|
+
|
|
89
|
+
# 2. Execute Local Review
|
|
90
|
+
if output_format != "json":
|
|
91
|
+
typer.echo("[*] Spinning up local Syntropy Lattice...")
|
|
92
|
+
|
|
93
|
+
from syntropy import Lattice, AgentScoreVector
|
|
94
|
+
import asyncio
|
|
95
|
+
|
|
96
|
+
lattice = Lattice()
|
|
97
|
+
lattice.add_agent(
|
|
98
|
+
"Architecture Reviewer",
|
|
99
|
+
perspective="architecture",
|
|
100
|
+
knowledge_items=("design patterns", "code organization", "dependencies"),
|
|
101
|
+
score_vector=AgentScoreVector(knowledge=0.8, synthesis=0.8, connections=0.5),
|
|
102
|
+
)
|
|
103
|
+
lattice.add_agent(
|
|
104
|
+
"Security Analyst",
|
|
105
|
+
perspective="security",
|
|
106
|
+
knowledge_items=("vulnerabilities", "auth", "data safety"),
|
|
107
|
+
score_vector=AgentScoreVector(knowledge=0.8, synthesis=0.7, connections=0.4),
|
|
108
|
+
)
|
|
109
|
+
lattice.add_agent(
|
|
110
|
+
"Performance Engineer",
|
|
111
|
+
perspective="performance",
|
|
112
|
+
knowledge_items=("efficiency", "hot paths", "resource usage"),
|
|
113
|
+
score_vector=AgentScoreVector(knowledge=0.7, synthesis=0.8, connections=0.4),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
prompt = f"Goal: {goal}\n\nRepository Snippets:\n"
|
|
117
|
+
for snippet in packet.evidence_snippets[:15]:
|
|
118
|
+
prompt += f"--- {snippet.path} ---\n{snippet.excerpt}\n\n"
|
|
119
|
+
prompt += "\nBased on the snippets above, provide a synthesis addressing the review goal."
|
|
120
|
+
|
|
121
|
+
if output_format != "json":
|
|
122
|
+
typer.echo("[*] Routing to agents and synthesizing...")
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
result = asyncio.run(lattice.submit(prompt, strategy="parallel", agent_count=3))
|
|
126
|
+
except Exception as e:
|
|
127
|
+
typer.echo(f"Error executing local Lattice: {e}")
|
|
128
|
+
raise typer.Exit(code=1) from e
|
|
129
|
+
|
|
130
|
+
if output_format == "json":
|
|
131
|
+
typer.echo(json.dumps({
|
|
132
|
+
"goal": goal,
|
|
133
|
+
"synthesis": result.synthesis,
|
|
134
|
+
"recommendation_ids": result.recommendation_ids,
|
|
135
|
+
"perspectives_used": [entry.agent_name for entry in result.selection_trace if entry.selected]
|
|
136
|
+
}, indent=2))
|
|
137
|
+
else:
|
|
138
|
+
typer.echo("\n[✓] Review complete!\n")
|
|
139
|
+
typer.echo("=== SYNTHESIS ===")
|
|
140
|
+
typer.echo(result.synthesis)
|
|
141
|
+
typer.echo("\n=== PERSPECTIVES USED ===")
|
|
142
|
+
for entry in result.selection_trace:
|
|
143
|
+
if entry.selected:
|
|
144
|
+
typer.echo(f"- {entry.agent_name}")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def cli_main() -> None:
|
|
148
|
+
app()
|
|
149
|
+
|
|
150
|
+
if __name__ == "__main__":
|
|
151
|
+
cli_main()
|