pixelgraph 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Дiegushko Хименес
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include LICENSE
2
+ include README.md
3
+ include requirements.txt
4
+ recursive-include pixelgraph/static *
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: pixelgraph
3
+ Version: 0.1.0
4
+ Summary: 8-bit visualization for LangGraph agents
5
+ Author-email: Diego <diego@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/diegonov1/PixelGraph
8
+ Project-URL: Repository, https://github.com/diegonov1/PixelGraph
9
+ Project-URL: Issues, https://github.com/diegonov1/PixelGraph/issues
10
+ Keywords: langgraph,langchain,visualization,8-bit,agents,ai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: fastapi>=0.104.0
23
+ Requires-Dist: uvicorn[standard]>=0.24.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: websockets>=12.0
26
+ Requires-Dist: langchain-core>=0.1.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
29
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
30
+ Requires-Dist: httpx>=0.25.0; extra == "dev"
31
+ Requires-Dist: black>=23.0.0; extra == "dev"
32
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
33
+ Provides-Extra: langgraph
34
+ Requires-Dist: langgraph>=0.0.40; extra == "langgraph"
35
+ Provides-Extra: openai
36
+ Requires-Dist: langchain-openai>=0.0.5; extra == "openai"
37
+ Provides-Extra: all
38
+ Requires-Dist: pixelgraph[dev,langgraph,openai]; extra == "all"
39
+ Dynamic: license-file
40
+
41
+ # PixelGraph
42
+
43
+ > 8-bit visualization for LangGraph agents
44
+
45
+ PixelGraph transforms your LangGraph agent interactions into a retro 8-bit game experience. Watch your AI agents think, speak, and use tools in a nostalgic pixel-art environment.
46
+
47
+ ## Features
48
+
49
+ - **Drop-in Integration**: Works with any existing LangGraph application
50
+ - **Real-time Visualization**: See agent thoughts, speech, and tool usage
51
+ - **8-bit Aesthetics**: Pixel art sprites and retro styling
52
+ - **WebSocket Communication**: Bidirectional real-time updates
53
+ - **Action Queue**: Smooth animation sequencing regardless of event speed
54
+
55
+ ## Quick Start
56
+
57
+ ### Installation
58
+
59
+ ```bash
60
+ # Clone the repository
61
+ git clone https://github.com/diegonov1/PixelGraph.git
62
+ cd PixelGraph
63
+
64
+ # Install Python dependencies
65
+ pip install -r requirements.txt
66
+
67
+ # Install frontend dependencies
68
+ cd frontend && npm install && cd ..
69
+ ```
70
+
71
+ ### Run Demo Mode
72
+
73
+ Without any LLM API key, you can run the demo:
74
+
75
+ ```bash
76
+ # Terminal 1: Start backend
77
+ python examples/simple_demo.py
78
+
79
+ # Terminal 2: Start frontend
80
+ cd frontend && npm run dev
81
+ ```
82
+
83
+ Open http://localhost:3000 in your browser.
84
+
85
+ ### Run with LangGraph
86
+
87
+ ```bash
88
+ # Set your OpenAI API key
89
+ export OPENAI_API_KEY=your-api-key
90
+
91
+ # Run the LangGraph example
92
+ python examples/langgraph_example.py
93
+ ```
94
+
95
+ ## Usage
96
+
97
+ Integrate PixelGraph with your existing LangGraph application:
98
+
99
+ ```python
100
+ from langgraph.graph import StateGraph
101
+ from pixelgraph import GameServer
102
+
103
+ # Your existing LangGraph code
104
+ graph = StateGraph(State)
105
+ # ... add nodes and edges ...
106
+ app = graph.compile()
107
+
108
+ # Add visualization with one line
109
+ server = GameServer(app)
110
+ server.serve()
111
+ ```
112
+
113
+ ### Visual Configuration
114
+
115
+ Customize how agents appear in the game:
116
+
117
+ ```python
118
+ from pixelgraph import GameServer
119
+ from pixelgraph.schemas.events import VisualConfig, AgentConfig
120
+
121
+ config = VisualConfig(
122
+ title="My Agent Team",
123
+ theme="dungeon",
124
+ nodes={
125
+ "researcher": AgentConfig(sprite="wizard", color="blue"),
126
+ "writer": AgentConfig(sprite="bard", color="red"),
127
+ }
128
+ )
129
+
130
+ server = GameServer(app, config=config)
131
+ server.serve()
132
+ ```
133
+
134
+ ## Architecture
135
+
136
+ ```
137
+ Frontend (React + Phaser) Backend (FastAPI + LangGraph)
138
+ ┌─────────────┐ ┌─────────────┐
139
+ │ Phaser │◄─WebSocket──►│ GameServer │
140
+ │ Canvas │ │ │
141
+ └─────────────┘ │ Callback │
142
+ ┌─────────────┐ │ Handler │
143
+ │ React │ │ ▲ │
144
+ │ HUD/Log │ │ │ │
145
+ └─────────────┘ │ LangGraph │
146
+ └─────────────┘
147
+ ```
148
+
149
+ ### Event Flow
150
+
151
+ 1. LangGraph emits events during execution
152
+ 2. `GameVisualizerCallbackHandler` captures and transforms events
153
+ 3. Events are sent via WebSocket to the frontend
154
+ 4. Frontend queues events in the `ActionQueue`
155
+ 5. Phaser consumes events one at a time, playing animations
156
+
157
+ ## Development
158
+
159
+ ### Project Structure
160
+
161
+ ```
162
+ pixelgraph/
163
+ ├── pixelgraph/ # Python package
164
+ │ ├── __init__.py # Package exports
165
+ │ ├── callback.py # LangChain callback handler
166
+ │ ├── server.py # FastAPI WebSocket server
167
+ │ ├── schemas/ # Pydantic event schemas
168
+ │ └── static/ # Built frontend (after npm build)
169
+ ├── frontend/ # React + Phaser frontend
170
+ │ ├── src/
171
+ │ │ ├── game/ # Phaser logic
172
+ │ │ │ ├── scenes/ # Game scenes
173
+ │ │ │ ├── entities/# Sprite classes
174
+ │ │ │ └── systems/ # Event bus, action queue
175
+ │ │ └── components/ # React UI components
176
+ │ └── public/assets/ # Sprites and assets
177
+ ├── examples/ # Usage examples
178
+ └── tests/ # Test suite
179
+ ```
180
+
181
+ ### Commands
182
+
183
+ ```bash
184
+ make install # Install all dependencies
185
+ make dev # Run both backend and frontend
186
+ make build # Build frontend for production
187
+ make test # Run tests
188
+ make docker-dev # Run with Docker (development)
189
+ make docker-prod # Run with Docker (production)
190
+ ```
191
+
192
+ ## Roadmap
193
+
194
+ - [ ] Multi-agent support with dynamic positioning
195
+ - [ ] Tool-specific animations (search, calculator, etc.)
196
+ - [ ] Speed control for event playback
197
+ - [ ] Custom sprite support
198
+ - [ ] Themes (dungeon, sci-fi, city)
199
+ - [ ] Export conversation as GIF
200
+
201
+ ## License
202
+
203
+ MIT
204
+
205
+ ## Contributing
206
+
207
+ Contributions welcome! Please read our contributing guidelines first.
@@ -0,0 +1,167 @@
1
+ # PixelGraph
2
+
3
+ > 8-bit visualization for LangGraph agents
4
+
5
+ PixelGraph transforms your LangGraph agent interactions into a retro 8-bit game experience. Watch your AI agents think, speak, and use tools in a nostalgic pixel-art environment.
6
+
7
+ ## Features
8
+
9
+ - **Drop-in Integration**: Works with any existing LangGraph application
10
+ - **Real-time Visualization**: See agent thoughts, speech, and tool usage
11
+ - **8-bit Aesthetics**: Pixel art sprites and retro styling
12
+ - **WebSocket Communication**: Bidirectional real-time updates
13
+ - **Action Queue**: Smooth animation sequencing regardless of event speed
14
+
15
+ ## Quick Start
16
+
17
+ ### Installation
18
+
19
+ ```bash
20
+ # Clone the repository
21
+ git clone https://github.com/diegonov1/PixelGraph.git
22
+ cd PixelGraph
23
+
24
+ # Install Python dependencies
25
+ pip install -r requirements.txt
26
+
27
+ # Install frontend dependencies
28
+ cd frontend && npm install && cd ..
29
+ ```
30
+
31
+ ### Run Demo Mode
32
+
33
+ Without any LLM API key, you can run the demo:
34
+
35
+ ```bash
36
+ # Terminal 1: Start backend
37
+ python examples/simple_demo.py
38
+
39
+ # Terminal 2: Start frontend
40
+ cd frontend && npm run dev
41
+ ```
42
+
43
+ Open http://localhost:3000 in your browser.
44
+
45
+ ### Run with LangGraph
46
+
47
+ ```bash
48
+ # Set your OpenAI API key
49
+ export OPENAI_API_KEY=your-api-key
50
+
51
+ # Run the LangGraph example
52
+ python examples/langgraph_example.py
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ Integrate PixelGraph with your existing LangGraph application:
58
+
59
+ ```python
60
+ from langgraph.graph import StateGraph
61
+ from pixelgraph import GameServer
62
+
63
+ # Your existing LangGraph code
64
+ graph = StateGraph(State)
65
+ # ... add nodes and edges ...
66
+ app = graph.compile()
67
+
68
+ # Add visualization with one line
69
+ server = GameServer(app)
70
+ server.serve()
71
+ ```
72
+
73
+ ### Visual Configuration
74
+
75
+ Customize how agents appear in the game:
76
+
77
+ ```python
78
+ from pixelgraph import GameServer
79
+ from pixelgraph.schemas.events import VisualConfig, AgentConfig
80
+
81
+ config = VisualConfig(
82
+ title="My Agent Team",
83
+ theme="dungeon",
84
+ nodes={
85
+ "researcher": AgentConfig(sprite="wizard", color="blue"),
86
+ "writer": AgentConfig(sprite="bard", color="red"),
87
+ }
88
+ )
89
+
90
+ server = GameServer(app, config=config)
91
+ server.serve()
92
+ ```
93
+
94
+ ## Architecture
95
+
96
+ ```
97
+ Frontend (React + Phaser) Backend (FastAPI + LangGraph)
98
+ ┌─────────────┐ ┌─────────────┐
99
+ │ Phaser │◄─WebSocket──►│ GameServer │
100
+ │ Canvas │ │ │
101
+ └─────────────┘ │ Callback │
102
+ ┌─────────────┐ │ Handler │
103
+ │ React │ │ ▲ │
104
+ │ HUD/Log │ │ │ │
105
+ └─────────────┘ │ LangGraph │
106
+ └─────────────┘
107
+ ```
108
+
109
+ ### Event Flow
110
+
111
+ 1. LangGraph emits events during execution
112
+ 2. `GameVisualizerCallbackHandler` captures and transforms events
113
+ 3. Events are sent via WebSocket to the frontend
114
+ 4. Frontend queues events in the `ActionQueue`
115
+ 5. Phaser consumes events one at a time, playing animations
116
+
117
+ ## Development
118
+
119
+ ### Project Structure
120
+
121
+ ```
122
+ pixelgraph/
123
+ ├── pixelgraph/ # Python package
124
+ │ ├── __init__.py # Package exports
125
+ │ ├── callback.py # LangChain callback handler
126
+ │ ├── server.py # FastAPI WebSocket server
127
+ │ ├── schemas/ # Pydantic event schemas
128
+ │ └── static/ # Built frontend (after npm build)
129
+ ├── frontend/ # React + Phaser frontend
130
+ │ ├── src/
131
+ │ │ ├── game/ # Phaser logic
132
+ │ │ │ ├── scenes/ # Game scenes
133
+ │ │ │ ├── entities/# Sprite classes
134
+ │ │ │ └── systems/ # Event bus, action queue
135
+ │ │ └── components/ # React UI components
136
+ │ └── public/assets/ # Sprites and assets
137
+ ├── examples/ # Usage examples
138
+ └── tests/ # Test suite
139
+ ```
140
+
141
+ ### Commands
142
+
143
+ ```bash
144
+ make install # Install all dependencies
145
+ make dev # Run both backend and frontend
146
+ make build # Build frontend for production
147
+ make test # Run tests
148
+ make docker-dev # Run with Docker (development)
149
+ make docker-prod # Run with Docker (production)
150
+ ```
151
+
152
+ ## Roadmap
153
+
154
+ - [ ] Multi-agent support with dynamic positioning
155
+ - [ ] Tool-specific animations (search, calculator, etc.)
156
+ - [ ] Speed control for event playback
157
+ - [ ] Custom sprite support
158
+ - [ ] Themes (dungeon, sci-fi, city)
159
+ - [ ] Export conversation as GIF
160
+
161
+ ## License
162
+
163
+ MIT
164
+
165
+ ## Contributing
166
+
167
+ Contributions welcome! Please read our contributing guidelines first.
@@ -0,0 +1,12 @@
1
+ """
2
+ PixelGraph - 8-bit visualization for LangGraph agents
3
+
4
+ A drop-in visualization library that transforms your LangGraph
5
+ agent interactions into an 8-bit game experience.
6
+ """
7
+
8
+ from pixelgraph.server import GameServer
9
+ from pixelgraph.callback import GameVisualizerCallbackHandler, GameEventType
10
+
11
+ __version__ = "0.1.0"
12
+ __all__ = ["GameServer", "GameVisualizerCallbackHandler", "GameEventType"]
@@ -0,0 +1,199 @@
1
+ """
2
+ GameVisualizerCallbackHandler - The bridge between LangGraph and the visualization.
3
+
4
+ This callback handler captures events from LangChain/LangGraph execution
5
+ and transforms them into game events for the 8-bit frontend.
6
+ """
7
+
8
+ import asyncio
9
+ from datetime import datetime
10
+ from typing import Any, Optional
11
+ from uuid import UUID, uuid4
12
+
13
+ from langchain_core.callbacks import BaseCallbackHandler
14
+ from langchain_core.outputs import LLMResult, ChatGeneration
15
+
16
+
17
+ class GameEventType:
18
+ """Event types that the frontend (Phaser) understands."""
19
+
20
+ AGENT_THINK_START = "AGENT_THINK_START"
21
+ AGENT_SPEAK = "AGENT_SPEAK"
22
+ TOOL_START = "TOOL_START"
23
+ TOOL_END = "TOOL_END"
24
+ AGENT_IDLE = "AGENT_IDLE"
25
+ ERROR = "ERROR"
26
+
27
+
28
+ class GameVisualizerCallbackHandler(BaseCallbackHandler):
29
+ """
30
+ Captures LangGraph/LangChain events and sends them to an async queue
31
+ for consumption by a WebSocket connection.
32
+
33
+ This handler acts as a "spy" that observes the execution flow without
34
+ interfering with it, transforming internal events into visual instructions.
35
+ """
36
+
37
+ def __init__(self, event_queue: asyncio.Queue, default_agent: str = "agent"):
38
+ """
39
+ Initialize the callback handler.
40
+
41
+ Args:
42
+ event_queue: Async queue where events will be pushed
43
+ default_agent: Default agent name when none is specified in metadata
44
+ """
45
+ super().__init__()
46
+ self.queue = event_queue
47
+ self.current_active_agent = default_agent
48
+ self._loop = None
49
+
50
+ def _get_loop(self) -> asyncio.AbstractEventLoop:
51
+ """Get or create the event loop."""
52
+ if self._loop is None or self._loop.is_closed():
53
+ try:
54
+ self._loop = asyncio.get_running_loop()
55
+ except RuntimeError:
56
+ self._loop = asyncio.new_event_loop()
57
+ return self._loop
58
+
59
+ def _emit_event_sync(
60
+ self, event_type: str, agent_name: str, payload: dict[str, Any] | None = None
61
+ ):
62
+ """Synchronously emit an event to the queue."""
63
+ event = {
64
+ "event_id": str(uuid4()),
65
+ "timestamp": datetime.utcnow().isoformat(),
66
+ "type": event_type,
67
+ "agent_id": agent_name,
68
+ "data": payload or {},
69
+ }
70
+
71
+ loop = self._get_loop()
72
+ if loop.is_running():
73
+ asyncio.run_coroutine_threadsafe(self.queue.put(event), loop)
74
+ else:
75
+ self.queue.put_nowait(event)
76
+
77
+ async def _emit_event(
78
+ self, event_type: str, agent_name: str, payload: dict[str, Any] | None = None
79
+ ):
80
+ """Asynchronously emit an event to the queue."""
81
+ event = {
82
+ "event_id": str(uuid4()),
83
+ "timestamp": datetime.utcnow().isoformat(),
84
+ "type": event_type,
85
+ "agent_id": agent_name,
86
+ "data": payload or {},
87
+ }
88
+ await self.queue.put(event)
89
+
90
+ # --- Synchronous Callback Methods (for sync execution) ---
91
+
92
+ def on_chat_model_start(
93
+ self,
94
+ serialized: dict[str, Any],
95
+ messages: list[list[Any]],
96
+ *,
97
+ run_id: UUID,
98
+ parent_run_id: Optional[UUID] = None,
99
+ tags: Optional[list[str]] = None,
100
+ metadata: Optional[dict[str, Any]] = None,
101
+ **kwargs: Any,
102
+ ) -> Any:
103
+ """
104
+ Triggered when the model receives a prompt and starts processing.
105
+ Visual: Thought bubble '...' appears over the character.
106
+ """
107
+ metadata = metadata or {}
108
+ agent_name = metadata.get("agent_name", self.current_active_agent)
109
+ self.current_active_agent = agent_name
110
+
111
+ self._emit_event_sync(
112
+ GameEventType.AGENT_THINK_START, agent_name, {"status": "processing"}
113
+ )
114
+
115
+ def on_llm_end(
116
+ self,
117
+ response: LLMResult,
118
+ *,
119
+ run_id: UUID,
120
+ parent_run_id: Optional[UUID] = None,
121
+ **kwargs: Any,
122
+ ) -> Any:
123
+ """
124
+ Triggered when the model has finished generating a response.
125
+ Visual: Speech bubble with the response text.
126
+ """
127
+ text_content = ""
128
+ if response.generations:
129
+ generation = response.generations[0][0]
130
+ if isinstance(generation, ChatGeneration):
131
+ text_content = generation.message.content
132
+ else:
133
+ text_content = generation.text
134
+
135
+ self._emit_event_sync(
136
+ GameEventType.AGENT_SPEAK,
137
+ self.current_active_agent,
138
+ {"content": text_content},
139
+ )
140
+
141
+ self._emit_event_sync(GameEventType.AGENT_IDLE, self.current_active_agent)
142
+
143
+ def on_tool_start(
144
+ self,
145
+ serialized: dict[str, Any],
146
+ input_str: str,
147
+ *,
148
+ run_id: UUID,
149
+ parent_run_id: Optional[UUID] = None,
150
+ tags: Optional[list[str]] = None,
151
+ metadata: Optional[dict[str, Any]] = None,
152
+ **kwargs: Any,
153
+ ) -> Any:
154
+ """
155
+ Triggered when an agent decides to use a tool.
156
+ Visual: Character shows an icon (e.g., magnifying glass for web search).
157
+ """
158
+ tool_name = serialized.get("name", "generic_tool")
159
+ metadata = metadata or {}
160
+ agent_name = metadata.get("agent_name", self.current_active_agent)
161
+
162
+ self._emit_event_sync(
163
+ GameEventType.TOOL_START,
164
+ agent_name,
165
+ {"tool_name": tool_name, "input_args": input_str[:100]},
166
+ )
167
+
168
+ def on_tool_end(
169
+ self,
170
+ output: str,
171
+ *,
172
+ run_id: UUID,
173
+ parent_run_id: Optional[UUID] = None,
174
+ **kwargs: Any,
175
+ ) -> Any:
176
+ """
177
+ Triggered when a tool finishes its work.
178
+ Visual: Icon disappears or character nods.
179
+ """
180
+ self._emit_event_sync(
181
+ GameEventType.TOOL_END,
182
+ self.current_active_agent,
183
+ {"result_preview": output[:50] + "..." if len(output) > 50 else output},
184
+ )
185
+
186
+ def on_chain_error(
187
+ self,
188
+ error: BaseException,
189
+ *,
190
+ run_id: UUID,
191
+ parent_run_id: Optional[UUID] = None,
192
+ **kwargs: Any,
193
+ ) -> Any:
194
+ """Triggered when an error occurs in the chain."""
195
+ self._emit_event_sync(
196
+ GameEventType.ERROR,
197
+ self.current_active_agent,
198
+ {"error": str(error)},
199
+ )