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.
Files changed (50) hide show
  1. syntropy/__init__.py +39 -0
  2. syntropy/agent.py +75 -0
  3. syntropy/cli.py +151 -0
  4. syntropy/contract.py +486 -0
  5. syntropy/core/__init__.py +17 -0
  6. syntropy/core/connections.py +89 -0
  7. syntropy/core/contributions.py +56 -0
  8. syntropy/core/operations.py +111 -0
  9. syntropy/core/ordering.py +84 -0
  10. syntropy/core/routing.py +184 -0
  11. syntropy/core/scheduler.py +83 -0
  12. syntropy/core/structural.py +275 -0
  13. syntropy/interfaces.py +54 -0
  14. syntropy/lattice.py +856 -0
  15. syntropy/llm/__init__.py +7 -0
  16. syntropy/llm/mock.py +14 -0
  17. syntropy/llm/ollama.py +105 -0
  18. syntropy/llm/openai.py +129 -0
  19. syntropy/memory/__init__.py +5 -0
  20. syntropy/memory/in_memory.py +27 -0
  21. syntropy/observation/__init__.py +6 -0
  22. syntropy/observation/bus.py +60 -0
  23. syntropy/observation/events.py +246 -0
  24. syntropy/recommendation.py +36 -0
  25. syntropy/replay.py +71 -0
  26. syntropy/resources/__init__.py +1 -0
  27. syntropy/resources/shared/__init__.py +1 -0
  28. syntropy/resources/shared/auto-strategy-fixtures.json +89 -0
  29. syntropy/resources/shared/axioms.json +56 -0
  30. syntropy/resources/shared/connection-fixtures.json +107 -0
  31. syntropy/resources/shared/ema-fixtures.json +75 -0
  32. syntropy/resources/shared/ordering-fixtures.json +70 -0
  33. syntropy/resources/shared/replay-demo.json +361 -0
  34. syntropy/resources/shared/replay-fixtures.json +117 -0
  35. syntropy/resources/shared/routing-fixtures.json +108 -0
  36. syntropy/resources/shared/runtime-events.json +103 -0
  37. syntropy/resources/shared/runtime-scoring.json +27 -0
  38. syntropy/resources/shared/runtime-topology.json +13 -0
  39. syntropy/resources/shared/structural-decision-fixtures.json +220 -0
  40. syntropy/resources/shared/trust-policy.json +30 -0
  41. syntropy/runtime.py +92 -0
  42. syntropy/scanner.py +157 -0
  43. syntropy/settings.py +137 -0
  44. syntropy/task.py +62 -0
  45. syntropy/visualization/__init__.py +5 -0
  46. syntropy/visualization/lattice_renderer.py +16 -0
  47. syntropy_core-0.1.0.dist-info/METADATA +43 -0
  48. syntropy_core-0.1.0.dist-info/RECORD +50 -0
  49. syntropy_core-0.1.0.dist-info/WHEEL +4 -0
  50. 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()