prompt_objects 0.4.0 → 0.5.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/CLAUDE.md +112 -44
- data/README.md +5 -0
- data/frontend/index.html +5 -1
- data/frontend/src/App.tsx +70 -78
- data/frontend/src/canvas/CanvasView.tsx +5 -5
- data/frontend/src/canvas/constants.ts +31 -31
- data/frontend/src/canvas/inspector/InspectorPanel.tsx +4 -4
- data/frontend/src/canvas/inspector/POInspector.tsx +35 -35
- data/frontend/src/canvas/inspector/ToolCallInspector.tsx +13 -13
- data/frontend/src/canvas/nodes/PONode.ts +2 -2
- data/frontend/src/components/ContextMenu.tsx +5 -4
- data/frontend/src/components/Inspector.tsx +232 -0
- data/frontend/src/components/MarkdownMessage.tsx +22 -20
- data/frontend/src/components/MethodList.tsx +90 -0
- data/frontend/src/components/ModelSelector.tsx +13 -14
- data/frontend/src/components/NotificationPanel.tsx +29 -33
- data/frontend/src/components/ObjectList.tsx +78 -0
- data/frontend/src/components/PaneSlot.tsx +30 -0
- data/frontend/src/components/SourcePane.tsx +202 -0
- data/frontend/src/components/SystemBar.tsx +74 -0
- data/frontend/src/components/Transcript.tsx +76 -0
- data/frontend/src/components/UsagePanel.tsx +27 -27
- data/frontend/src/components/Workspace.tsx +260 -0
- data/frontend/src/components/index.ts +10 -9
- data/frontend/src/hooks/useResize.ts +55 -0
- data/frontend/src/hooks/useWebSocket.ts +28 -0
- data/frontend/src/index.css +28 -10
- data/frontend/src/store/index.ts +4 -0
- data/frontend/src/types/index.ts +2 -0
- data/frontend/tailwind.config.js +28 -9
- data/lib/prompt_objects/capability.rb +23 -1
- data/lib/prompt_objects/connectors/mcp.rb +2 -16
- data/lib/prompt_objects/llm/openai_adapter.rb +22 -0
- data/lib/prompt_objects/mcp/tools/inspect_po.rb +1 -31
- data/lib/prompt_objects/mcp/tools/list_prompt_objects.rb +1 -6
- data/lib/prompt_objects/prompt_object.rb +126 -0
- data/lib/prompt_objects/server/api/routes.rb +3 -48
- data/lib/prompt_objects/server/public/assets/{index-xvyeb-5Z.js → index-D1myxE0l.js} +211 -211
- data/lib/prompt_objects/server/public/assets/index-DdCcwC-Z.css +1 -0
- data/lib/prompt_objects/server/public/index.html +7 -3
- data/lib/prompt_objects/server/websocket_handler.rb +23 -100
- data/lib/prompt_objects/server.rb +6 -62
- data/prompt_objects.gemspec +1 -1
- data/templates/arc-agi-1/primitives/find_objects.rb +1 -1
- data/templates/arc-agi-1/primitives/grid_diff.rb +2 -2
- data/templates/arc-agi-1/primitives/grid_info.rb +1 -1
- data/templates/arc-agi-1/primitives/grid_transform.rb +1 -1
- data/templates/arc-agi-1/primitives/render_grid.rb +1 -0
- data/templates/arc-agi-1/primitives/test_solution.rb +3 -0
- metadata +12 -13
- data/frontend/src/components/CapabilitiesPanel.tsx +0 -141
- data/frontend/src/components/ChatPanel.tsx +0 -296
- data/frontend/src/components/Dashboard.tsx +0 -83
- data/frontend/src/components/Header.tsx +0 -153
- data/frontend/src/components/MessageBus.tsx +0 -56
- data/frontend/src/components/POCard.tsx +0 -56
- data/frontend/src/components/PODetail.tsx +0 -124
- data/frontend/src/components/PromptPanel.tsx +0 -156
- data/frontend/src/components/SessionsPanel.tsx +0 -174
- data/frontend/src/components/ThreadsSidebar.tsx +0 -163
- data/lib/prompt_objects/server/public/assets/index-6y64NXFy.css +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6dd3c14942ef80d1979ded542802ad9d1a24b32cd479aa4ba0a08bb0bf2e349d
|
|
4
|
+
data.tar.gz: 3642d5424aa827754dfefde82a9e9e5c770935ebf08e36cfc429d8f86e5e8502
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f4e4449d2a8764a762c13ea14b6ccac17b07d1ae06a053a94e5b66ce7ebf38b8ca2903c140f0bb06810e09fa830bdac1dcfb8485d2f6f7fe32f7b0dffdf374bb
|
|
7
|
+
data.tar.gz: 1faa31a8c32f067cdfb133c06e6c3d45e55fec3381d86f649e8845b9d2c58bc367e2bed3821cbec4a92a18776b723ccf69c276f9e913347198816005c4608353
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to PromptObjects are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.0] - 2026-02-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Smalltalk System Browser redesign** — Complete frontend overhaul replacing the chat-app UI with a multi-pane object browser. POs are treated as live objects in a running image: permanent ObjectList (left pane), multi-pane Inspector with MethodList + SourcePane, REPL-style Workspace, and bottom Transcript. Warm charcoal + amber palette with Geist fonts. All panels resizable via drag handles.
|
|
10
|
+
- **Collapsible inspector top pane** — The Methods + Source pane has a thin header bar with a collapse/expand toggle. When collapsed, the Workspace fills the full inspector height. Collapse state persists across PO switches.
|
|
11
|
+
- **Source entry in method list** — A "Source" entry at the top of the method list provides a clear way to navigate back to the PO's prompt after inspecting a capability.
|
|
12
|
+
- **Dynamic Ollama model discovery** — LLM config now queries the Ollama API for installed models instead of using a static list.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **Capabilities disappearing on file save** — `po_modified` events were sending capabilities as plain string names instead of rich objects, overwriting the store. All serialization paths now emit consistent `{name, description, parameters}` objects.
|
|
17
|
+
- **Centralized PO serialization** — Moved duplicated state/message/session serialization from WebSocketHandler and API routes into `PromptObject` (`to_state_hash`, `to_summary_hash`, `to_inspect_hash`). Eliminates inconsistent serialization as a class of bug.
|
|
18
|
+
- **Missing items field in array tool schemas** — LLM APIs reject array parameters without an `items` field. Added a defensive sanitizer in `Capability#descriptor` as a fallback.
|
|
19
|
+
- **OpenAI adapter error details** — 4xx errors from Ollama now surface the actual rejection reason instead of just "status 400".
|
|
20
|
+
- **All WebSocket message types handled** — Added frontend handlers for `prompt_updated`, `llm_error`, `session_created`, and `session_switched`. Removed defensive normalization workarounds.
|
|
21
|
+
|
|
5
22
|
## [0.4.0] - 2026-02-11
|
|
6
23
|
|
|
7
24
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -6,17 +6,21 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
6
6
|
|
|
7
7
|
**PromptObjects** is a Ruby framework where markdown files with LLM-backed behavior act as first-class autonomous entities. The core insight: **everything is a capability**—primitives (Ruby code) and Prompt-Objects (markdown files) share the same interface, differing only in interpretation complexity.
|
|
8
8
|
|
|
9
|
-
**Current Status**:
|
|
9
|
+
**Current Status**: v0.5.0 — The core framework is fully implemented and functional. The original 6-phase implementation plan is complete. Active development is focused on visualization, developer experience, and exploring new primitives. See `CHANGELOG.md` for release history and `design-doc-v2.md` / `IMPLEMENTATION_PLAN.md` for original design context.
|
|
10
10
|
|
|
11
11
|
## Architecture
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
|
|
14
|
+
RUNTIME (Environment)
|
|
15
15
|
├── CAPABILITY REGISTRY
|
|
16
16
|
│ ├── PRIMITIVES (Ruby) - deterministic interpretation
|
|
17
|
-
│
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
│ ├── PROMPT-OBJECTS (Markdown) - semantic interpretation via LLM
|
|
18
|
+
│ └── UNIVERSAL CAPABILITIES - available to all POs automatically
|
|
19
|
+
├── MESSAGE BUS - routes messages, logs to SQLite for replay
|
|
20
|
+
├── SESSION STORE (SQLite) - persistent conversation threads, delegation tracking
|
|
21
|
+
├── HUMAN QUEUE - non-blocking ask_human requests
|
|
22
|
+
├── WEB SERVER (Sinatra + WebSocket) - serves React frontend
|
|
23
|
+
└── MCP SERVER - exposes POs as tools via Model Context Protocol
|
|
20
24
|
```
|
|
21
25
|
|
|
22
26
|
### Unified Capability Interface
|
|
@@ -53,56 +57,120 @@ You are a careful, thoughtful file reader...
|
|
|
53
57
|
Available to all Prompt-Objects automatically (no frontmatter declaration needed):
|
|
54
58
|
- `ask_human` - pause for human input/confirmation
|
|
55
59
|
- `think` - internal reasoning (not shown to human)
|
|
56
|
-
- `
|
|
60
|
+
- `create_capability` / `add_capability` / `remove_capability` - self-modification
|
|
61
|
+
- `list_capabilities` / `list_primitives` - introspection
|
|
62
|
+
- `create_primitive` / `add_primitive` / `delete_primitive` / `verify_primitive` / `modify_primitive` / `request_primitive` - primitive management
|
|
63
|
+
- `modify_prompt` - rewrite own system prompt at runtime
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- **Ruby** - core implementation
|
|
61
|
-
- **LLM APIs** - OpenAI, Anthropic, Gemini (adapter pattern)
|
|
62
|
-
- **Charm** - Terminal UI (Bubble Tea for interaction, Lipgloss for styling, Glamour for markdown)
|
|
63
|
-
- **MCP** - Model Context Protocol integration
|
|
65
|
+
### PO-to-PO Delegation
|
|
66
|
+
When a PO calls another PO, the system creates an isolated delegation thread in the target PO. The caller's context is tracked so messages show correct provenance. Delegation start/complete events are broadcast via WebSocket for real-time UI updates.
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
## Technology Stack
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
- **Ruby** (>= 3.2, tested through Ruby 4) - core implementation
|
|
71
|
+
- **LLM APIs** - OpenAI, Anthropic, Gemini, Ollama, OpenRouter (adapter pattern via `LLM::Factory`)
|
|
72
|
+
- **Sinatra** - web server for REST API and static file serving
|
|
73
|
+
- **faye-websocket** - real-time WebSocket communication
|
|
74
|
+
- **React + TypeScript** - web frontend (dashboard, chat, capabilities panel)
|
|
75
|
+
- **Three.js** - spatial canvas visualization (force-directed PO graph)
|
|
76
|
+
- **SQLite** - session persistence and event log storage
|
|
77
|
+
- **MCP** - Model Context Protocol server mode
|
|
68
78
|
|
|
69
|
-
##
|
|
79
|
+
## File Structure
|
|
70
80
|
|
|
71
81
|
```
|
|
72
82
|
prompt_objects/
|
|
73
|
-
├── exe/prompt_objects
|
|
83
|
+
├── exe/prompt_objects # CLI entrypoint
|
|
74
84
|
├── lib/
|
|
75
|
-
│ ├── prompt_objects.rb
|
|
85
|
+
│ ├── prompt_objects.rb # Main entry, requires all modules
|
|
76
86
|
│ └── prompt_objects/
|
|
77
|
-
│ ├── environment.rb
|
|
78
|
-
│ ├── capability.rb
|
|
79
|
-
│ ├── prompt_object.rb
|
|
80
|
-
│ ├── primitive.rb
|
|
81
|
-
│ ├── loader.rb
|
|
82
|
-
│ ├── registry.rb
|
|
83
|
-
│ ├── message_bus.rb
|
|
84
|
-
│ ├──
|
|
85
|
-
│ ├──
|
|
86
|
-
│ ├──
|
|
87
|
-
│ ├──
|
|
88
|
-
│
|
|
89
|
-
├──
|
|
90
|
-
|
|
87
|
+
│ ├── environment.rb # Runtime container (registry, bus, LLM, sessions)
|
|
88
|
+
│ ├── capability.rb # Base capability interface
|
|
89
|
+
│ ├── prompt_object.rb # PO implementation (LLM conversation loop)
|
|
90
|
+
│ ├── primitive.rb # Primitive tool wrapper
|
|
91
|
+
│ ├── loader.rb # Parses frontmatter + body from .md files
|
|
92
|
+
│ ├── registry.rb # Capability registration and lookup
|
|
93
|
+
│ ├── message_bus.rb # Message routing, logging, SQLite persistence
|
|
94
|
+
│ ├── human_queue.rb # Non-blocking human interaction queue
|
|
95
|
+
│ ├── cli.rb # CLI command definitions
|
|
96
|
+
│ ├── server.rb # Web server setup
|
|
97
|
+
│ ├── server/
|
|
98
|
+
│ │ ├── app.rb # Sinatra application
|
|
99
|
+
│ │ ├── api/routes.rb # REST API endpoints
|
|
100
|
+
│ │ ├── websocket_handler.rb # WebSocket event handling
|
|
101
|
+
│ │ └── file_watcher.rb # Live .md file change detection
|
|
102
|
+
│ ├── llm/
|
|
103
|
+
│ │ ├── factory.rb # Provider/model selection
|
|
104
|
+
│ │ ├── response.rb # Unified response object
|
|
105
|
+
│ │ ├── pricing.rb # Token cost calculation
|
|
106
|
+
│ │ ├── openai_adapter.rb # OpenAI + Ollama + OpenRouter
|
|
107
|
+
│ │ ├── anthropic_adapter.rb
|
|
108
|
+
│ │ └── gemini_adapter.rb
|
|
109
|
+
│ ├── primitives/ # Built-in: read_file, list_files, write_file, http_get
|
|
110
|
+
│ ├── universal/ # 14 universal capabilities (see list above)
|
|
111
|
+
│ ├── connectors/ # Interface adapters (base, mcp)
|
|
112
|
+
│ ├── mcp/ # MCP server and tool definitions
|
|
113
|
+
│ ├── session/
|
|
114
|
+
│ │ └── store.rb # SQLite session/thread persistence
|
|
115
|
+
│ └── environment/
|
|
116
|
+
│ ├── manager.rb # Create/list/clone environments
|
|
117
|
+
│ ├── manifest.rb # Environment metadata (manifest.yml)
|
|
118
|
+
│ ├── git.rb # Auto-commit integration
|
|
119
|
+
│ ├── exporter.rb # Environment export
|
|
120
|
+
│ └── importer.rb # Environment import
|
|
121
|
+
├── frontend/ # React + TypeScript web UI
|
|
122
|
+
│ └── src/
|
|
123
|
+
│ ├── App.tsx
|
|
124
|
+
│ ├── components/ # Dashboard, chat, capabilities panel
|
|
125
|
+
│ ├── canvas/ # Three.js spatial visualization
|
|
126
|
+
│ ├── hooks/ # WebSocket, state management hooks
|
|
127
|
+
│ ├── store/ # Frontend state
|
|
128
|
+
│ └── types/ # TypeScript type definitions
|
|
129
|
+
├── objects/ # Default POs: greeter, reader, coordinator
|
|
130
|
+
├── templates/ # Environment templates (basic, developer, writer, arc-agi-1, etc.)
|
|
131
|
+
├── tools/ # Development tooling
|
|
132
|
+
└── test/ # Unit and integration tests
|
|
91
133
|
```
|
|
92
134
|
|
|
93
|
-
## Implementation Phases
|
|
94
|
-
|
|
95
|
-
1. **Core Loop**: Capability base, PromptObject, Loader, single LLM adapter, simple REPL
|
|
96
|
-
2. **Primitives & Binding**: Primitive base, built-in primitives, Registry
|
|
97
|
-
3. **Multi-Capability**: Message bus with logging, PO↔PO communication
|
|
98
|
-
4. **Self-Modification**: Universal capabilities including create_capability
|
|
99
|
-
5. **Polish & UI**: Full Charm integration, all UI components
|
|
100
|
-
6. **Demo Ready**: Error handling, testing, practice runs
|
|
101
|
-
|
|
102
135
|
## Key Concepts
|
|
103
136
|
|
|
104
137
|
- **Semantic Binding**: Natural language → capability call (visible in message log)
|
|
105
|
-
- **PO↔PO Communication**: Prompt-Objects
|
|
106
|
-
- **Self-Modification**:
|
|
107
|
-
- **Human-in-the-Loop**: POs
|
|
108
|
-
- **
|
|
138
|
+
- **PO↔PO Communication**: Prompt-Objects call each other as capabilities through isolated delegation threads
|
|
139
|
+
- **Self-Modification**: POs can create new POs and primitives at runtime (with human approval)
|
|
140
|
+
- **Human-in-the-Loop**: POs use `ask_human` to pause and queue notifications; human responds asynchronously via the web UI
|
|
141
|
+
- **Environments**: Isolated collections of POs with their own sessions, git history, and configuration. Created from templates via CLI.
|
|
142
|
+
- **Thread Export**: Conversation threads (including delegation chains) exportable as Markdown or JSON
|
|
143
|
+
|
|
144
|
+
## Development
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Install dependencies
|
|
148
|
+
bundle install
|
|
149
|
+
cd frontend && npm install && cd ..
|
|
150
|
+
|
|
151
|
+
# Run tests
|
|
152
|
+
bundle exec rake test
|
|
153
|
+
|
|
154
|
+
# Serve an environment with web UI
|
|
155
|
+
prompt_objects serve <env-name> --open
|
|
156
|
+
|
|
157
|
+
# Environment management
|
|
158
|
+
prompt_objects env create <name> --template basic
|
|
159
|
+
prompt_objects env list
|
|
160
|
+
prompt_objects env info <name>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Releases
|
|
164
|
+
|
|
165
|
+
Always tag releases. Pushing a version tag triggers the Discord notification workflow (`.github/workflows/discord-release.yml`), which extracts the matching section from `CHANGELOG.md` and posts it.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# 1. Update version in prompt_objects.gemspec
|
|
169
|
+
# 2. Add changelog entry under ## [X.Y.Z] - YYYY-MM-DD
|
|
170
|
+
# 3. Commit: "Release vX.Y.Z — short description"
|
|
171
|
+
# 4. Tag and push:
|
|
172
|
+
git tag vX.Y.Z
|
|
173
|
+
git push && git push origin vX.Y.Z
|
|
174
|
+
# 5. Publish gem:
|
|
175
|
+
gem build prompt_objects.gemspec && gem push prompt_objects-X.Y.Z.gem
|
|
176
|
+
```
|
data/README.md
CHANGED
|
@@ -12,6 +12,11 @@ Prompt Objects applies this to AI. Instead of treating LLMs as external APIs you
|
|
|
12
12
|
|
|
13
13
|
This is a new computing primitive: semantic late binding at runtime, where natural language becomes the interface between intelligent components.
|
|
14
14
|
|
|
15
|
+
Blog Posts
|
|
16
|
+
==========
|
|
17
|
+
|
|
18
|
+
- [What if we took message passing seriously?](https://worksonmymachine.ai/p/what-if-we-took-message-passing-seriously) — The origin story and motivation behind Prompt Objects.
|
|
19
|
+
|
|
15
20
|
Who
|
|
16
21
|
===
|
|
17
22
|
|
data/frontend/index.html
CHANGED
|
@@ -4,9 +4,13 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
|
|
8
|
+
<link href="https://cdn.jsdelivr.net/fontsource/fonts/geist@latest/latin-400-normal.woff2" as="font" type="font/woff2" crossorigin />
|
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-sans/style.css" rel="stylesheet" />
|
|
10
|
+
<link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-mono/style.css" rel="stylesheet" />
|
|
7
11
|
<title>PromptObjects</title>
|
|
8
12
|
</head>
|
|
9
|
-
<body class="bg-po-bg text-
|
|
13
|
+
<body class="bg-po-bg text-po-text-primary font-ui">
|
|
10
14
|
<div id="root"></div>
|
|
11
15
|
<script type="module" src="/src/main.tsx"></script>
|
|
12
16
|
</body>
|
data/frontend/src/App.tsx
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
1
|
import { useWebSocket } from './hooks/useWebSocket'
|
|
3
2
|
import { useStore, useSelectedPO } from './store'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { useResize } from './hooks/useResize'
|
|
4
|
+
import { SystemBar } from './components/SystemBar'
|
|
5
|
+
import { ObjectList } from './components/ObjectList'
|
|
6
|
+
import { Inspector } from './components/Inspector'
|
|
7
|
+
import { Transcript } from './components/Transcript'
|
|
8
8
|
import { NotificationPanel } from './components/NotificationPanel'
|
|
9
|
-
import { ThreadsSidebar } from './components/ThreadsSidebar'
|
|
10
9
|
import { UsagePanel } from './components/UsagePanel'
|
|
11
10
|
import { CanvasView } from './canvas/CanvasView'
|
|
12
11
|
|
|
@@ -15,89 +14,82 @@ export default function App() {
|
|
|
15
14
|
useWebSocket()
|
|
16
15
|
const { selectedPO, busOpen, notifications, usageData, clearUsageData, currentView } = useStore()
|
|
17
16
|
const selectedPOData = useSelectedPO()
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
const objectListResize = useResize({
|
|
19
|
+
direction: 'horizontal',
|
|
20
|
+
initialSize: 192,
|
|
21
|
+
minSize: 120,
|
|
22
|
+
maxSize: 320,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const transcriptResize = useResize({
|
|
26
|
+
direction: 'vertical',
|
|
27
|
+
initialSize: 180,
|
|
28
|
+
minSize: 80,
|
|
29
|
+
maxSize: 400,
|
|
30
|
+
inverted: true,
|
|
31
|
+
})
|
|
19
32
|
|
|
20
33
|
return (
|
|
21
34
|
<div className="h-screen flex flex-col bg-po-bg">
|
|
22
|
-
<
|
|
35
|
+
<SystemBar switchLLM={switchLLM} />
|
|
23
36
|
|
|
24
|
-
<div className="flex-1 flex overflow-hidden">
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
<h2 className="text-sm font-medium text-gray-400">Prompt Objects</h2>
|
|
36
|
-
<button
|
|
37
|
-
onClick={() => setSplitView(false)}
|
|
38
|
-
className="text-xs text-gray-500 hover:text-white"
|
|
39
|
-
title="Hide sidebar"
|
|
40
|
-
>
|
|
41
|
-
✕
|
|
42
|
-
</button>
|
|
43
|
-
</div>
|
|
44
|
-
<div className="flex-1 overflow-auto">
|
|
45
|
-
<Dashboard compact />
|
|
46
|
-
</div>
|
|
47
|
-
</aside>
|
|
48
|
-
|
|
49
|
-
{/* Threads List for selected PO */}
|
|
50
|
-
{selectedPOData && (
|
|
51
|
-
<aside className="w-56 border-r border-po-border bg-po-bg overflow-hidden">
|
|
52
|
-
<ThreadsSidebar
|
|
53
|
-
po={selectedPOData}
|
|
54
|
-
switchSession={switchSession}
|
|
55
|
-
createThread={createThread}
|
|
56
|
-
requestUsage={requestUsage}
|
|
57
|
-
exportThread={exportThread}
|
|
58
|
-
/>
|
|
59
|
-
</aside>
|
|
60
|
-
)}
|
|
61
|
-
</>
|
|
62
|
-
)}
|
|
37
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
38
|
+
{/* Main view area */}
|
|
39
|
+
<div className="flex-1 flex overflow-hidden">
|
|
40
|
+
{currentView === 'canvas' ? (
|
|
41
|
+
<CanvasView />
|
|
42
|
+
) : (
|
|
43
|
+
<>
|
|
44
|
+
{/* Object List - resizable */}
|
|
45
|
+
<div style={{ width: objectListResize.size }} className="flex-shrink-0">
|
|
46
|
+
<ObjectList />
|
|
47
|
+
</div>
|
|
63
48
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
onClick={() => setSplitView(true)}
|
|
70
|
-
className="absolute left-2 top-16 z-10 bg-po-surface border border-po-border rounded px-2 py-1 text-xs text-gray-400 hover:text-white hover:border-po-accent transition-colors"
|
|
71
|
-
title="Show dashboard sidebar"
|
|
72
|
-
>
|
|
73
|
-
☰ POs
|
|
74
|
-
</button>
|
|
75
|
-
)}
|
|
49
|
+
{/* Resize handle */}
|
|
50
|
+
<div
|
|
51
|
+
className="resize-handle"
|
|
52
|
+
onMouseDown={objectListResize.onMouseDown}
|
|
53
|
+
/>
|
|
76
54
|
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
55
|
+
{/* Main content */}
|
|
56
|
+
<main className="flex-1 overflow-hidden flex flex-col">
|
|
57
|
+
{selectedPO && selectedPOData ? (
|
|
58
|
+
<Inspector
|
|
59
|
+
po={selectedPOData}
|
|
60
|
+
sendMessage={sendMessage}
|
|
61
|
+
createSession={createSession}
|
|
62
|
+
switchSession={switchSession}
|
|
63
|
+
createThread={createThread}
|
|
64
|
+
updatePrompt={updatePrompt}
|
|
65
|
+
requestUsage={requestUsage}
|
|
66
|
+
exportThread={exportThread}
|
|
67
|
+
/>
|
|
68
|
+
) : (
|
|
69
|
+
<div className="h-full flex items-center justify-center text-po-text-ghost">
|
|
70
|
+
<span className="font-mono text-xs">Select an object</span>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</main>
|
|
74
|
+
</>
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
91
77
|
|
|
92
|
-
{/*
|
|
78
|
+
{/* Transcript - resizable bottom pane, visible in both views */}
|
|
93
79
|
{busOpen && (
|
|
94
|
-
|
|
95
|
-
<
|
|
96
|
-
|
|
80
|
+
<>
|
|
81
|
+
<div
|
|
82
|
+
className="resize-handle-h"
|
|
83
|
+
onMouseDown={transcriptResize.onMouseDown}
|
|
84
|
+
/>
|
|
85
|
+
<div style={{ height: transcriptResize.size }} className="flex-shrink-0">
|
|
86
|
+
<Transcript />
|
|
87
|
+
</div>
|
|
88
|
+
</>
|
|
97
89
|
)}
|
|
98
90
|
</div>
|
|
99
91
|
|
|
100
|
-
{/* Notification panel */}
|
|
92
|
+
{/* Notification panel - floating */}
|
|
101
93
|
{notifications.length > 0 && (
|
|
102
94
|
<NotificationPanel respondToNotification={respondToNotification} />
|
|
103
95
|
)}
|
|
@@ -83,17 +83,17 @@ export function CanvasView() {
|
|
|
83
83
|
<div className="absolute top-3 left-3 flex gap-2 z-10">
|
|
84
84
|
<button
|
|
85
85
|
onClick={() => sceneRef.current?.fitAll()}
|
|
86
|
-
className="px-
|
|
86
|
+
className="px-2.5 py-1 text-xs bg-po-surface-2/80 backdrop-blur border border-po-border rounded hover:border-po-accent transition-colors duration-150 text-po-text-secondary hover:text-po-text-primary"
|
|
87
87
|
title="Fit all nodes (F)"
|
|
88
88
|
>
|
|
89
89
|
Fit All
|
|
90
90
|
</button>
|
|
91
91
|
<button
|
|
92
92
|
onClick={toggleLabels}
|
|
93
|
-
className={`px-
|
|
93
|
+
className={`px-2.5 py-1 text-xs backdrop-blur border rounded transition-colors duration-150 ${
|
|
94
94
|
showLabels
|
|
95
|
-
? 'bg-po-accent
|
|
96
|
-
: 'bg-po-surface/80 border-po-border text-
|
|
95
|
+
? 'bg-po-accent-wash border-po-accent text-po-accent'
|
|
96
|
+
: 'bg-po-surface-2/80 border-po-border text-po-text-secondary hover:text-po-text-primary'
|
|
97
97
|
}`}
|
|
98
98
|
title="Toggle labels"
|
|
99
99
|
>
|
|
@@ -102,7 +102,7 @@ export function CanvasView() {
|
|
|
102
102
|
</div>
|
|
103
103
|
|
|
104
104
|
{/* Help hint */}
|
|
105
|
-
<div className="absolute bottom-3 left-3 text-
|
|
105
|
+
<div className="absolute bottom-3 left-3 text-2xs text-po-text-ghost z-10 font-mono">
|
|
106
106
|
Scroll to zoom · Shift+drag to pan · F to fit · Click node to inspect
|
|
107
107
|
</div>
|
|
108
108
|
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
// Canvas visualization constants
|
|
2
2
|
|
|
3
|
-
// Colors (hex values matching po-* palette)
|
|
3
|
+
// Colors (hex values matching warm po-* palette)
|
|
4
4
|
export const COLORS = {
|
|
5
5
|
// Node colors
|
|
6
|
-
background:
|
|
7
|
-
surface:
|
|
8
|
-
border:
|
|
9
|
-
accent:
|
|
10
|
-
accentHover:
|
|
11
|
-
success:
|
|
12
|
-
warning:
|
|
13
|
-
error:
|
|
6
|
+
background: 0x1a1918,
|
|
7
|
+
surface: 0x222120,
|
|
8
|
+
border: 0x3d3a37,
|
|
9
|
+
accent: 0xd4952a,
|
|
10
|
+
accentHover: 0xe0a940,
|
|
11
|
+
success: 0x3b9a6e,
|
|
12
|
+
warning: 0xd4952a,
|
|
13
|
+
error: 0xc45c4a,
|
|
14
14
|
|
|
15
15
|
// Status colors
|
|
16
|
-
statusIdle:
|
|
17
|
-
statusThinking:
|
|
18
|
-
statusCallingTool:
|
|
16
|
+
statusIdle: 0x78726a,
|
|
17
|
+
statusThinking: 0xd4952a,
|
|
18
|
+
statusCallingTool: 0x3b9a6e,
|
|
19
19
|
|
|
20
20
|
// Canvas-specific
|
|
21
|
-
nodeFill:
|
|
22
|
-
nodeGlow:
|
|
23
|
-
toolCallFill:
|
|
24
|
-
arcColor:
|
|
25
|
-
particleColor:
|
|
26
|
-
gridColor:
|
|
21
|
+
nodeFill: 0x222120,
|
|
22
|
+
nodeGlow: 0xd4952a,
|
|
23
|
+
toolCallFill: 0x3b9a6e,
|
|
24
|
+
arcColor: 0xd4952a,
|
|
25
|
+
particleColor: 0xe0a940,
|
|
26
|
+
gridColor: 0x222120,
|
|
27
27
|
} as const
|
|
28
28
|
|
|
29
29
|
// CSS color strings (for CSS2DRenderer elements)
|
|
30
30
|
export const CSS_COLORS = {
|
|
31
|
-
accent: '#
|
|
32
|
-
accentHover: '#
|
|
33
|
-
warning: '#
|
|
34
|
-
success: '#
|
|
35
|
-
error: '#
|
|
36
|
-
textPrimary: '#
|
|
37
|
-
textSecondary: '#
|
|
38
|
-
textMuted: '#
|
|
39
|
-
surface: '#
|
|
40
|
-
border: '#
|
|
41
|
-
statusIdle: '#
|
|
42
|
-
statusThinking: '#
|
|
43
|
-
statusCallingTool: '#
|
|
31
|
+
accent: '#d4952a',
|
|
32
|
+
accentHover: '#e0a940',
|
|
33
|
+
warning: '#d4952a',
|
|
34
|
+
success: '#3b9a6e',
|
|
35
|
+
error: '#c45c4a',
|
|
36
|
+
textPrimary: '#e8e2da',
|
|
37
|
+
textSecondary: '#a8a29a',
|
|
38
|
+
textMuted: '#78726a',
|
|
39
|
+
surface: '#222120',
|
|
40
|
+
border: '#3d3a37',
|
|
41
|
+
statusIdle: '#78726a',
|
|
42
|
+
statusThinking: '#d4952a',
|
|
43
|
+
statusCallingTool: '#3b9a6e',
|
|
44
44
|
} as const
|
|
45
45
|
|
|
46
46
|
// Node dimensions
|
|
@@ -9,14 +9,14 @@ export function InspectorPanel() {
|
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
11
|
<aside className="w-80 border-l border-po-border bg-po-surface overflow-hidden flex flex-col">
|
|
12
|
-
<div className="
|
|
13
|
-
<
|
|
12
|
+
<div className="h-8 bg-po-surface-2 border-b border-po-border flex items-center px-3">
|
|
13
|
+
<span className="text-2xs font-medium text-po-text-ghost uppercase tracking-wider flex-1">Inspector</span>
|
|
14
14
|
<button
|
|
15
15
|
onClick={() => useCanvasStore.getState().selectNode(null)}
|
|
16
|
-
className="text-
|
|
16
|
+
className="text-2xs text-po-text-ghost hover:text-po-text-secondary transition-colors duration-150"
|
|
17
17
|
title="Close inspector"
|
|
18
18
|
>
|
|
19
|
-
|
|
19
|
+
{'\u2715'}
|
|
20
20
|
</button>
|
|
21
21
|
</div>
|
|
22
22
|
<div className="flex-1 overflow-auto">
|