1d414c1383
- Added IPython-backed Python tool with streaming output and image/JSON rendering. - Implemented Jupyter kernel gateway integration with WebSocket communication. - Added Python prelude with 30+ shell-like utility functions for file operations. - Migrated environment variables from PI_ to OMP_ prefix with automatic migration. - Added streaming output system with automatic spill-to-disk for large outputs. - Reorganized settings interface into behavior, tools, display, voice, status, lsp, and exa tabs.
3.5 KiB
3.5 KiB
IPython Kernel REPL Tool (coding-agent)
Implementation Status: COMPLETE
The Python REPL tool has been implemented using Jupyter Kernel Gateway for IPC instead of direct ZeroMQ connections. This avoids Bun's incompatibility with the zeromq NAPI module (libuv uv_async_init not supported).
Architecture
TypeScript (coding-agent)
│
├── REST API (kernel lifecycle)
│ POST /api/kernels → create kernel
│ DELETE /api/kernels/{id} → shutdown kernel
│ POST /api/kernels/{id}/interrupt → interrupt execution
│
└── WebSocket (message passing)
ws://host:port/api/kernels/{id}/channels
└── Multiplexed Jupyter protocol (shell, iopub, stdin, control)
│
▼
Jupyter Kernel Gateway (Python process)
│
└── ZeroMQ (internal, handled by pyzmq)
│
▼
ipykernel (Python kernel)
Key Files
packages/coding-agent/src/core/python-kernel.ts- Kernel Gateway clientpackages/coding-agent/src/core/python-executor.ts- Execution wrapperpackages/coding-agent/src/core/tools/python.ts- Tool definition
Dependencies
Python (user must install):
pip install jupyter_kernel_gateway ipykernel
TypeScript: No native dependencies. Uses standard WebSocket API.
WebSocket Wire Protocol
The Jupyter Kernel Gateway uses a binary WebSocket protocol:
┌─────────────┬──────────┬──────────┬─────┬─────────┬──────────┬─────┐
│ offset_count│ offset_0 │ offset_1 │ ... │ msg │ buffer_0 │ ... │
│ (4 bytes) │ (4 bytes)│ (4 bytes)│ │ (JSON) │ (binary) │ │
└─────────────┴──────────┴──────────┴─────┴─────────┴──────────┴─────┘
Message JSON structure:
{
"channel": "shell|iopub|stdin|control",
"header": { "msg_id", "session", "username", "date", "msg_type", "version" },
"parent_header": {},
"metadata": {},
"content": {}
}
Kernel Lifecycle
- Start Gateway: Spawn
python -m jupyter_kernel_gateway --port=<port> - Wait for Ready: Poll
GET /api/kernelspecsuntil 200 - Create Kernel:
POST /api/kernelswith{ "name": "python3" } - Connect WebSocket:
ws://host:port/api/kernels/{id}/channels - Execute Code: Send
execute_requeston shell channel - Receive Output: Handle
stream,execute_result,display_data,erroron iopub - Shutdown:
DELETE /api/kernels/{id}, then kill gateway process
Settings
| Setting | Values | Default | Description |
|---|---|---|---|
python.toolMode |
ipy-only, bash-only, both |
ipy-only |
How Python code is executed |
python.kernelMode |
session, per-call |
session |
Whether to keep kernel alive |
Previous Approach (Deprecated)
The original plan used direct ZeroMQ connections from TypeScript to ipykernel. This was abandoned because:
- The
zeromqnpm package uses NAPI with libuv internals - Bun doesn't support
uv_async_init(see https://github.com/oven-sh/bun/issues/18546) - No pure-JS ZeroMQ implementation exists
Jupyter Kernel Gateway solves this by handling ZeroMQ internally (via Python's pyzmq) and exposing a standard HTTP/WebSocket interface.