Compare commits
16 Commits
d89f971270
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d9d8a70e8 | |||
| cc6a651664 | |||
| e567223031 | |||
| a3c8d4b153 | |||
| e600d3fdcd | |||
| 266a67dcd9 | |||
| 2b73745cd9 | |||
| 51d05c15e0 | |||
| 9ddbcd2fd6 | |||
| c205c6d97c | |||
| 2ed9867e39 | |||
| f5d4913da2 | |||
| abe1c660ea | |||
| dd520dd4db | |||
| f6fe3baaf4 | |||
| 133fd60613 |
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: Fast, read-only agent for exploring the codebase structure
|
||||
mode: subagent
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/MiniMax-M2.7
|
||||
temperature: 0.2
|
||||
permission:
|
||||
edit: deny
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: General-purpose agent for researching complex questions and executing multi-step tasks
|
||||
mode: subagent
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/MiniMax-M2.7
|
||||
temperature: 0.3
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: Tier 1 Orchestrator for product alignment, high-level planning, and track initialization
|
||||
mode: primary
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/MiniMax-M2.7
|
||||
temperature: 0.5
|
||||
permission:
|
||||
edit: ask
|
||||
@@ -18,7 +18,7 @@ ONLY output the requested text. No pleasantries.
|
||||
|
||||
## Context Management
|
||||
|
||||
**MANUAL COMPACTION ONLY** — Never rely on automatic context summarization.
|
||||
**MANUAL COMPACTION ONLY** <EFBFBD> Never rely on automatic context summarization.
|
||||
Use `/compact` command explicitly when context needs reduction.
|
||||
Preserve full context during track planning and spec creation.
|
||||
|
||||
@@ -105,7 +105,7 @@ Use `manual-slop_py_get_code_outline`, `manual-slop_py_get_definition`,
|
||||
Document existing implementations with file:line references in a
|
||||
"Current State Audit" section in the spec.
|
||||
|
||||
**FAILURE TO AUDIT = TRACK FAILURE** — Previous tracks failed because specs
|
||||
**FAILURE TO AUDIT = TRACK FAILURE** <EFBFBD> Previous tracks failed because specs
|
||||
asked to implement features that already existed.
|
||||
|
||||
### 2. Identify Gaps, Not Features
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: Tier 2 Tech Lead for architectural design and track execution with persistent memory
|
||||
mode: primary
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/MiniMax-M2.7
|
||||
temperature: 0.4
|
||||
permission:
|
||||
edit: ask
|
||||
@@ -14,9 +14,9 @@ ONLY output the requested text. No pleasantries.
|
||||
|
||||
## Context Management
|
||||
|
||||
**MANUAL COMPACTION ONLY** — Never rely on automatic context summarization.
|
||||
**MANUAL COMPACTION ONLY** <EFBFBD> Never rely on automatic context summarization.
|
||||
Use `/compact` command explicitly when context needs reduction.
|
||||
You maintain PERSISTENT MEMORY throughout track execution — do NOT apply Context Amnesia to your own session.
|
||||
You maintain PERSISTENT MEMORY throughout track execution <EFBFBD> do NOT apply Context Amnesia to your own session.
|
||||
|
||||
## CRITICAL: MCP Tools Only (Native Tools Banned)
|
||||
|
||||
@@ -134,14 +134,14 @@ Before implementing:
|
||||
- Zero-assertion ban: Tests MUST have meaningful assertions
|
||||
- Delegate test creation to Tier 3 Worker via Task tool
|
||||
- Run tests and confirm they FAIL as expected
|
||||
- **CONFIRM FAILURE** — this is the Red phase
|
||||
- **CONFIRM FAILURE** <EFBFBD> this is the Red phase
|
||||
|
||||
### 3. Green Phase: Implement to Pass
|
||||
|
||||
- **Pre-delegation checkpoint**: Stage current progress (`git add .`)
|
||||
- Delegate implementation to Tier 3 Worker via Task tool
|
||||
- Run tests and confirm they PASS
|
||||
- **CONFIRM PASS** — this is the Green phase
|
||||
- **CONFIRM PASS** <EFBFBD> this is the Green phase
|
||||
|
||||
### 4. Refactor Phase (Optional)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: Stateless Tier 3 Worker for surgical code implementation and TDD
|
||||
mode: subagent
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/minimax-m2.7
|
||||
temperature: 0.3
|
||||
permission:
|
||||
edit: allow
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
---
|
||||
description: Stateless Tier 4 QA Agent for error analysis and diagnostics
|
||||
mode: subagent
|
||||
model: MiniMax-M2.5
|
||||
model: minimax-coding-plan/MiniMax-M2.7
|
||||
temperature: 0.2
|
||||
permission:
|
||||
edit: deny
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Project Tracks
|
||||
# Project Tracks
|
||||
|
||||
This file tracks all major tracks for the project. Each track has its own detailed plan in its respective folder.
|
||||
|
||||
@@ -38,6 +38,14 @@ This file tracks all major tracks for the project. Each track has its own detail
|
||||
8. [x] **Track: Rich Thinking Trace Handling** - *Parse and display AI thinking/reasoning traces*
|
||||
*Link: [./tracks/thinking_trace_handling_20260313/](./tracks/thinking_trace_handling_20260313/)*
|
||||
|
||||
9. [ ] **Track: Smarter Aggregation with Sub-Agent Summarization**
|
||||
*Link: [./tracks/aggregation_smarter_summaries_20260322/](./tracks/aggregation_smarter_summaries_20260322/)*
|
||||
*Goal: Sub-agent summarization during aggregation pass, hash-based caching for file summaries, smart outline generation for code vs text files.*
|
||||
|
||||
10. [ ] **Track: System Context Exposure**
|
||||
*Link: [./tracks/system_context_exposure_20260322/](./tracks/system_context_exposure_20260322/)*
|
||||
*Goal: Expose hidden _SYSTEM_PROMPT from ai_client.py to users for customization via AI Settings.*
|
||||
|
||||
---
|
||||
|
||||
### GUI Overhauls & Visualizations
|
||||
@@ -67,14 +75,18 @@ This file tracks all major tracks for the project. Each track has its own detail
|
||||
*Link: [./tracks/presets_ai_settings_ux_20260311/](./tracks/presets_ai_settings_ux_20260311/)*
|
||||
*Goal: Improve the layout, scaling, and control ergonomics of the Preset windows (Personas, Prompts, Tools) and AI Settings panel. Includes dual-control sliders and categorized tool management.*
|
||||
|
||||
8. [x] **Track: Session Context Snapshots & Visibility**
|
||||
8. [x] ~~**Track: Session Context Snapshots & Visibility**~~ (Archived 2026-03-22 - Replaced by discussion_hub_panel_reorganization)
|
||||
*Link: [./tracks/session_context_snapshots_20260311/](./tracks/session_context_snapshots_20260311/)*
|
||||
*Goal: Session-scoped context management, saving Context Presets, MMA assignment, and agent-focused session filtering in the UI.*
|
||||
|
||||
9. [x] **Track: Discussion Takes & Timeline Branching**
|
||||
9. [x] ~~**Track: Discussion Takes & Timeline Branching**~~ (Archived 2026-03-22 - Replaced by discussion_hub_panel_reorganization)
|
||||
*Link: [./tracks/discussion_takes_branching_20260311/](./tracks/discussion_takes_branching_20260311/)*
|
||||
*Goal: Non-linear discussion timelines via tabbed "takes", message branching, and synthesis generation workflows.*
|
||||
|
||||
12. [ ] **Track: Discussion Hub Panel Reorganization**
|
||||
*Link: [./tracks/discussion_hub_panel_reorganization_20260322/](./tracks/discussion_hub_panel_reorganization_20260322/)*
|
||||
*Goal: Properly merge Session Hub into Discussion Hub (4 tabs: Discussion | Context Composition | Snapshot | Takes), establish Files & Media as project-level inventory, deprecate ui_summary_only, implement Context Composition and DAW-style Takes.*
|
||||
|
||||
10. [ ] **Track: Undo/Redo History Support**
|
||||
*Link: [./tracks/undo_redo_history_20260311/](./tracks/undo_redo_history_20260311/)*
|
||||
*Goal: Robust, non-provider based undo/redo for text inputs, UI controls, discussion mutations, and context management. Includes hotkey support and a history list view.*
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "aggregation_smarter_summaries",
|
||||
"created": "2026-03-22",
|
||||
"status": "future",
|
||||
"priority": "medium",
|
||||
"affected_files": [
|
||||
"src/aggregate.py",
|
||||
"src/file_cache.py",
|
||||
"src/ai_client.py",
|
||||
"src/models.py"
|
||||
],
|
||||
"related_tracks": [
|
||||
"discussion_hub_panel_reorganization (in_progress)",
|
||||
"system_context_exposure (future)"
|
||||
],
|
||||
"notes": "Deferred from discussion_hub_panel_reorganization planning. Improves aggregation with sub-agent summarization and hash-based caching."
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# Implementation Plan: Smarter Aggregation with Sub-Agent Summarization
|
||||
|
||||
## Phase 1: Hash-Based Summary Cache
|
||||
Focus: Implement file hashing and cache storage
|
||||
|
||||
- [ ] Task: Research existing file hash implementations in codebase
|
||||
- [ ] Task: Design cache storage format (file-based vs project state)
|
||||
- [ ] Task: Implement hash computation for aggregation files
|
||||
- [ ] Task: Implement summary cache storage and retrieval
|
||||
- [ ] Task: Add cache invalidation when file content changes
|
||||
- [ ] Task: Write tests for hash computation and cache
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Hash-Based Summary Cache'
|
||||
|
||||
## Phase 2: Sub-Agent Summarization
|
||||
Focus: Implement sub-agent summarization during aggregation
|
||||
|
||||
- [ ] Task: Audit current aggregate.py flow
|
||||
- [ ] Task: Define summarization prompt strategy for code vs text files
|
||||
- [ ] Task: Implement sub-agent invocation during aggregation
|
||||
- [ ] Task: Handle provider-specific differences in sub-agent calls
|
||||
- [ ] Task: Write tests for sub-agent summarization
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 2: Sub-Agent Summarization'
|
||||
|
||||
## Phase 3: Tiered Aggregation Strategy
|
||||
Focus: Respect tier-level aggregation configuration
|
||||
|
||||
- [ ] Task: Audit how tiers receive context currently
|
||||
- [ ] Task: Implement tier-level aggregation strategy selection
|
||||
- [ ] Task: Connect tier strategy to Persona configuration
|
||||
- [ ] Task: Write tests for tiered aggregation
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 3: Tiered Aggregation Strategy'
|
||||
|
||||
## Phase 4: UI Integration
|
||||
Focus: Expose cache status and controls in UI
|
||||
|
||||
- [ ] Task: Add cache status indicator to Files & Media panel
|
||||
- [ ] Task: Add "Clear Summary Cache" button
|
||||
- [ ] Task: Add aggregation configuration to Project Settings or AI Settings
|
||||
- [ ] Task: Write tests for UI integration
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 4: UI Integration'
|
||||
|
||||
## Phase 5: Cache Persistence & Optimization
|
||||
Focus: Ensure cache persists and is performant
|
||||
|
||||
- [ ] Task: Implement persistent cache storage to disk
|
||||
- [ ] Task: Add cache size management (max entries, LRU)
|
||||
- [ ] Task: Performance testing with large codebases
|
||||
- [ ] Task: Write tests for persistence
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 5: Cache Persistence & Optimization'
|
||||
103
conductor/tracks/aggregation_smarter_summaries_20260322/spec.md
Normal file
103
conductor/tracks/aggregation_smarter_summaries_20260322/spec.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Specification: Smarter Aggregation with Sub-Agent Summarization
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This track improves the context aggregation system to use sub-agent passes for intelligent summarization and hash-based caching to avoid redundant work.
|
||||
|
||||
**Current Problem:**
|
||||
- Aggregation is a simple pass that either injects full file content or a basic skeleton
|
||||
- No intelligence applied to determine what level of detail is needed
|
||||
- Same files get re-summarized on every discussion start even if unchanged
|
||||
|
||||
**Goal:**
|
||||
- Use a sub-agent during aggregation pass for high-tier agents to generate succinct summaries
|
||||
- Cache summaries based on file hash - only re-summarize if file changed
|
||||
- Smart outline generation for code files, summary for text files
|
||||
|
||||
## 2. Current State Audit
|
||||
|
||||
### Existing Aggregation Behavior
|
||||
- `aggregate.py` handles context aggregation
|
||||
- `file_cache.py` provides AST parsing and skeleton generation
|
||||
- Per-file flags: `Auto-Aggregate` (summarize), `Force Full` (inject raw)
|
||||
- No caching of summarization results
|
||||
|
||||
### Provider API Considerations
|
||||
- Different providers have different prompt/caching mechanisms
|
||||
- Need to verify how each provider handles system context and caching
|
||||
- May need provider-specific aggregation strategies
|
||||
|
||||
## 3. Functional Requirements
|
||||
|
||||
### 3.1 Hash-Based Summary Cache
|
||||
- Generate SHA256 hash of file content
|
||||
- Store summaries in a cache (file-based or in project state)
|
||||
- Before summarizing, check if file hash matches cached summary
|
||||
- Cache invalidation when file content changes
|
||||
|
||||
### 3.2 Sub-Agent Summarization Pass
|
||||
- During aggregation, optionally invoke sub-agent for summarization
|
||||
- Sub-agent generates concise summary of file purpose and key points
|
||||
- Different strategies for:
|
||||
- Code files: AST-based outline + key function signatures
|
||||
- Text files: Paragraph-level summary
|
||||
- Config files: Key-value extraction
|
||||
|
||||
### 3.3 Tiered Aggregation Strategy
|
||||
- Tier 3/4 workers: Get skeleton outlines (fast, cheap)
|
||||
- Tier 2 (Tech Lead): Get summaries with key details
|
||||
- Tier 1 (Orchestrator): May get full content or enhanced summaries
|
||||
- Configurable per-agent via Persona
|
||||
|
||||
### 3.4 Cache Persistence
|
||||
- Summaries persist across sessions
|
||||
- Stored in project directory or centralized cache location
|
||||
- Manual cache clear option in UI
|
||||
|
||||
## 4. Data Model
|
||||
|
||||
### 4.1 Summary Cache Entry
|
||||
```python
|
||||
{
|
||||
"file_path": str,
|
||||
"file_hash": str, # SHA256 of content
|
||||
"summary": str,
|
||||
"outline": str, # For code files
|
||||
"generated_at": str, # ISO timestamp
|
||||
"generator_tier": str, # Which tier generated it
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Aggregation Config
|
||||
```toml
|
||||
[aggregation]
|
||||
default_mode = "summarize" # "full", "summarize", "outline"
|
||||
cache_enabled = true
|
||||
cache_dir = ".slop_cache"
|
||||
```
|
||||
|
||||
## 5. UI Changes
|
||||
|
||||
- Add "Clear Summary Cache" button in Files & Media or Context Composition
|
||||
- Show cached status indicator on files (similar to AST cache indicator)
|
||||
- Configuration in AI Settings or Project Settings
|
||||
|
||||
## 6. Acceptance Criteria
|
||||
|
||||
- [ ] File hash computed before summarization
|
||||
- [ ] Summary cache persists across app restarts
|
||||
- [ ] Sub-agent generates better summaries than basic skeleton
|
||||
- [ ] Aggregation respects tier-level configuration
|
||||
- [ ] Cache can be manually cleared
|
||||
- [ ] Provider APIs handle aggregated context correctly
|
||||
|
||||
## 7. Out of Scope
|
||||
- Changes to provider API internals
|
||||
- Vector store / embeddings for RAG (separate track)
|
||||
- Changes to Session Hub / Discussion Hub layout
|
||||
|
||||
## 8. Dependencies
|
||||
- `aggregate.py` - main aggregation logic
|
||||
- `file_cache.py` - AST parsing and caching
|
||||
- `ai_client.py` - sub-agent invocation
|
||||
- `models.py` - may need new config structures
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "discussion_hub_panel_reorganization",
|
||||
"created": "2026-03-22",
|
||||
"status": "in_progress",
|
||||
"priority": "high",
|
||||
"affected_files": [
|
||||
"src/gui_2.py",
|
||||
"src/models.py",
|
||||
"src/project_manager.py",
|
||||
"tests/test_gui_context_presets.py",
|
||||
"tests/test_discussion_takes.py"
|
||||
],
|
||||
"replaces": [
|
||||
"session_context_snapshots_20260311",
|
||||
"discussion_takes_branching_20260311"
|
||||
],
|
||||
"related_tracks": [
|
||||
"aggregation_smarter_summaries (future)",
|
||||
"system_context_exposure (future)"
|
||||
],
|
||||
"notes": "These earlier tracks were marked complete but the UI panel reorganization was not properly implemented. This track consolidates and properly executes the intended UX."
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Implementation Plan: Discussion Hub Panel Reorganization
|
||||
|
||||
## Phase 1: Cleanup & Project Settings Rename
|
||||
Focus: Remove redundant ui_summary_only, rename Context Hub, establish project-level vs discussion-level separation
|
||||
|
||||
- [x] Task: Audit current ui_summary_only usages and document behavior to deprecate [f6fe3ba] (embedded audit)
|
||||
- [x] Task: Remove ui_summary_only checkbox from _render_projects_panel (gui_2.py) [f5d4913]
|
||||
- [x] Task: Rename Context Hub to "Project Settings" in _gui_func tab bar [2ed9867]
|
||||
- [ ] Task: Remove Context Presets tab from Project Settings (Context Hub)
|
||||
- [ ] Task: Rename Context Hub to "Project Settings" in _gui_func tab bar
|
||||
- [x] Task: Remove Context Presets tab from Project Settings (Context Hub) [9ddbcd2]
|
||||
- [x] Task: Update references in show_windows dict and any help text [2ed9867] (renamed Context Hub -> Project Settings)
|
||||
- [x] Task: Write tests verifying ui_summary_only removal doesn't break existing functionality [f5d4913]
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Cleanup & Project Settings Rename'
|
||||
|
||||
## Phase 2: Merge Session Hub into Discussion Hub [checkpoint: 2b73745]
|
||||
Focus: Move Session Hub tabs into Discussion Hub, eliminate separate Session Hub window
|
||||
|
||||
- [x] Task: Audit Session Hub (_render_session_hub) tab content [documented above]
|
||||
- [x] Task: Add Snapshot tab to Discussion Hub containing Aggregate MD + System Prompt preview [2b73745]
|
||||
- [x] Task: Remove Session Hub window from _gui_func [2b73745]
|
||||
- [x] Task: Add Discussion Hub tab bar structure (Discussion | Context Composition | Snapshot | Takes) [2b73745]
|
||||
- [x] Task: Write tests for new tab structure rendering [2b73745]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 2: Merge Session Hub into Discussion Hub'
|
||||
|
||||
## Phase 3: Context Composition Tab [checkpoint: a3c8d4b]
|
||||
Focus: Per-discussion file filter with save/load preset functionality
|
||||
|
||||
- [x] Task: Write tests for Context Composition state management [a3c8d4b]
|
||||
- [x] Task: Create _render_context_composition_panel method [a3c8d4b]
|
||||
- [x] Task: Implement file/screenshot selection display (filtered from Files & Media) [a3c8d4b]
|
||||
- [x] Task: Implement per-file flags display (Auto-Aggregate, Force Full) [a3c8d4b]
|
||||
- [x] Task: Implement Save as Preset / Load Preset buttons [a3c8d4b]
|
||||
- [x] Task: Connect Context Presets storage to this panel [a3c8d4b]
|
||||
- [ ] Task: Update Persona editor to reference Context Composition presets (NOTE: already done via existing context_preset field in Persona)
|
||||
- [x] Task: Write tests for Context Composition preset save/load [a3c8d4b]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 3: Context Composition Tab'
|
||||
|
||||
## Phase 4: Takes Timeline Integration [checkpoint: cc6a651]
|
||||
Focus: DAW-style branching with proper visual timeline and synthesis
|
||||
|
||||
- [x] Task: Audit existing takes data structure and synthesis_formatter [documented above]
|
||||
- [ ] Task: Enhance takes data model with parent_entry and parent_take tracking (deferred - existing model sufficient)
|
||||
- [x] Task: Implement Branch from Entry action in discussion history [already existed]
|
||||
- [x] Task: Implement visual timeline showing take divergence [_render_takes_panel with table view]
|
||||
- [x] Task: Integrate synthesis panel into Takes tab [cc6a651]
|
||||
- [x] Task: Implement take selection for synthesis [cc6a651]
|
||||
- [x] Task: Write tests for take branching and synthesis [cc6a651]
|
||||
- [x] Task: Conductor - User Manual Verification 'Phase 4: Takes Timeline Integration'
|
||||
|
||||
## Phase 5: Final Integration & Cleanup
|
||||
Focus: Ensure all panels work together, remove dead code
|
||||
|
||||
- [ ] Task: Run full test suite to verify no regressions
|
||||
- [ ] Task: Remove dead code from ui_summary_only references
|
||||
- [ ] Task: Update conductor/tracks.md to mark old session_context_snapshots and discussion_takes_branching as archived/replaced
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 5: Final Integration & Cleanup'
|
||||
@@ -0,0 +1,137 @@
|
||||
# Specification: Discussion Hub Panel Reorganization
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This track addresses the fragmented implementation of Session Context Snapshots and Discussion Takes & Timeline Branching tracks (2026-03-11). Those tracks were marked complete but the UI panel layout was not properly reorganized.
|
||||
|
||||
**Goal:** Create a coherent Discussion Hub that absorbs Session Hub functionality, establishes Files & Media as project-level file inventory, and properly implements Context Composition and DAW-style Takes branching.
|
||||
|
||||
## 2. Current State Audit (as of 2026-03-22)
|
||||
|
||||
### Already Implemented (DO NOT re-implement)
|
||||
- `ui_summary_only` checkbox in Projects panel
|
||||
- Session Hub as separate window with tabs: Aggregate MD | System Prompt
|
||||
- Context Hub with tabs: Projects | Paths | Context Presets
|
||||
- Context Presets save/load mechanism in project TOML
|
||||
- `_render_synthesis_panel()` method (gui_2.py:2612-2643) - basic synthesis UI
|
||||
- Takes data structure in `project['discussion']['discussions']`
|
||||
- Per-file `Auto-Aggregate` and `Force Full` flags in Files & Media
|
||||
|
||||
### Gaps to Fill (This Track's Scope)
|
||||
1. `ui_summary_only` is redundant with per-file flags - deprecate it
|
||||
2. Context Hub renamed to "Project Settings" (remove Context Presets tab)
|
||||
3. Session Hub merged into Discussion Hub as tabs
|
||||
4. Files & Media stays separate as project-level inventory
|
||||
5. Context Composition tab in Discussion Hub for per-discussion filter
|
||||
6. Context Presets accessible via Context Composition (save/load filters)
|
||||
7. DAW-style Takes timeline properly integrated into Discussion Hub
|
||||
8. Synthesis properly integrated with Take selection
|
||||
|
||||
## 3. Panel Layout Target
|
||||
|
||||
| Panel | Location | Purpose |
|
||||
|-------|----------|---------|
|
||||
| **AI Settings** | Separate dockable | Provider, model, system prompts, tool presets, bias profiles |
|
||||
| **Files & Media** | Separate dockable | Project-level file inventory (addressable files) |
|
||||
| **Project Settings** | Context Hub → rename | Git dir, paths, project list (NO context stuff) |
|
||||
| **Discussion Hub** | Main hub | All discussion-related UI (tabs below) |
|
||||
| **MMA Dashboard** | Separate dockable | Multi-agent orchestration |
|
||||
| **Operations Hub** | Separate dockable | Tool calls, comms history, external tools |
|
||||
| **Diagnostics** | Separate dockable | Telemetry, logs |
|
||||
|
||||
**Discussion Hub Tabs:**
|
||||
1. **Discussion** - Main conversation view (current implementation)
|
||||
2. **Context Composition** - File/screenshot filter + presets (NEW)
|
||||
3. **Snapshot** - Aggregate MD + System Prompt preview (moved from Session Hub)
|
||||
4. **Takes** - DAW-style timeline branching + synthesis (integrated, not separate panel)
|
||||
|
||||
## 4. Functional Requirements
|
||||
|
||||
### 4.1 Deprecate ui_summary_only
|
||||
- Remove `ui_summary_only` checkbox from Projects panel
|
||||
- Per-file flags (`Auto-Aggregate`, `Force Full`) are the intended mechanism
|
||||
- Document migration path for users
|
||||
|
||||
### 4.2 Rename Context Hub → Project Settings
|
||||
- Context Hub tab bar: Projects | Paths
|
||||
- Remove "Context Presets" tab
|
||||
- All context-related functionality moves to Discussion Hub → Context Composition
|
||||
|
||||
### 4.3 Merge Session Hub into Discussion Hub
|
||||
- Session Hub window eliminated
|
||||
- Its content becomes tabs in Discussion Hub:
|
||||
- **Snapshot tab**: Aggregate MD preview, System Prompt preview, "Copy" buttons
|
||||
- These were previously in Session Hub
|
||||
|
||||
### 4.4 Context Composition Tab (NEW)
|
||||
- Shows currently selected files/screenshots for THIS discussion
|
||||
- Per-file flags: Auto-Aggregate, Force Full
|
||||
- **"Save as Preset"** / **"Load Preset"** buttons
|
||||
- Dropdown to select from saved presets
|
||||
- Relationship to Files & Media:
|
||||
- Files & Media = the inventory (project-level)
|
||||
- Context Composition = selected filter for current discussion
|
||||
|
||||
### 4.5 Takes Timeline (DAW-Style)
|
||||
- **New Take**: Start fresh discussion thread
|
||||
- **Branch Take**: Fork from any discussion entry
|
||||
- **Switch Take**: Make a take the active discussion
|
||||
- **Rename/Delete Take**
|
||||
- All takes share the same Files & Media (not duplicated)
|
||||
- Non-destructive branching
|
||||
- Visual timeline showing divergence points
|
||||
|
||||
### 4.6 Synthesis Integration
|
||||
- User selects 2+ takes via checkboxes
|
||||
- Click "Synthesize" button
|
||||
- AI generates "resolved" response considering all selected approaches
|
||||
- Result appears as new take
|
||||
- Accessible from Discussion Hub → Takes tab
|
||||
|
||||
## 5. Data Model Changes
|
||||
|
||||
### 5.1 Discussion State Structure
|
||||
```python
|
||||
# Per discussion in project['discussion']['discussions']
|
||||
{
|
||||
"name": str,
|
||||
"history": [
|
||||
{"role": "user"|"assistant", "content": str, "ts": str, "files_injected": [...]}
|
||||
],
|
||||
"parent_entry": Optional[int], # index of parent message if branched
|
||||
"parent_take": Optional[str], # name of parent take if branched
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Context Preset Format
|
||||
```toml
|
||||
[context_preset.my_filter]
|
||||
files = ["path/to/file_a.py"]
|
||||
auto_aggregate = true
|
||||
force_full = false
|
||||
screenshots = ["path/to/shot1.png"]
|
||||
```
|
||||
|
||||
## 6. Non-Functional Requirements
|
||||
- All changes must not break existing tests
|
||||
- New tests required for new functionality
|
||||
- Follow 1-space indentation Python code style
|
||||
- No comments unless explicitly requested
|
||||
|
||||
## 7. Acceptance Criteria
|
||||
|
||||
- [ ] `ui_summary_only` removed from Projects panel
|
||||
- [ ] Context Hub renamed to Project Settings
|
||||
- [ ] Session Hub window eliminated
|
||||
- [ ] Discussion Hub has 4 tabs: Discussion, Context Composition, Snapshot, Takes
|
||||
- [ ] Context Composition allows save/load of filter presets
|
||||
- [ ] Takes can be branched from any entry
|
||||
- [ ] Takes timeline shows divergence visually
|
||||
- [ ] Synthesis works with 2+ selected takes
|
||||
- [ ] All existing tests still pass
|
||||
- [ ] New tests cover new functionality
|
||||
|
||||
## 8. Out of Scope
|
||||
- Aggregation improvements (sub-agent summarization, hash-based caching) - separate future track
|
||||
- System prompt exposure (`_SYSTEM_PROMPT` in ai_client.py) - separate future track
|
||||
- Session sophistication (Session as container for multiple discussions) - deferred
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "system_context_exposure",
|
||||
"created": "2026-03-22",
|
||||
"status": "future",
|
||||
"priority": "medium",
|
||||
"affected_files": [
|
||||
"src/ai_client.py",
|
||||
"src/gui_2.py",
|
||||
"src/models.py"
|
||||
],
|
||||
"related_tracks": [
|
||||
"discussion_hub_panel_reorganization (in_progress)",
|
||||
"aggregation_smarter_summaries (future)"
|
||||
],
|
||||
"notes": "Deferred from discussion_hub_panel_reorganization planning. The _SYSTEM_PROMPT in ai_client.py is hidden from users - this exposes it for customization."
|
||||
}
|
||||
41
conductor/tracks/system_context_exposure_20260322/plan.md
Normal file
41
conductor/tracks/system_context_exposure_20260322/plan.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Implementation Plan: System Context Exposure
|
||||
|
||||
## Phase 1: Backend Changes
|
||||
Focus: Make _SYSTEM_PROMPT configurable
|
||||
|
||||
- [ ] Task: Audit ai_client.py system prompt flow
|
||||
- [ ] Task: Move _SYSTEM_PROMPT to configurable storage
|
||||
- [ ] Task: Implement load/save of base system prompt
|
||||
- [ ] Task: Modify _get_combined_system_prompt() to use config
|
||||
- [ ] Task: Write tests for configurable system prompt
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 1: Backend Changes'
|
||||
|
||||
## Phase 2: UI Implementation
|
||||
Focus: Add base prompt editor to AI Settings
|
||||
|
||||
- [ ] Task: Add UI controls to _render_system_prompts_panel
|
||||
- [ ] Task: Implement checkbox for "Use Default Base"
|
||||
- [ ] Task: Implement collapsible base prompt editor
|
||||
- [ ] Task: Add "Reset to Default" button
|
||||
- [ ] Task: Write tests for UI controls
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 2: UI Implementation'
|
||||
|
||||
## Phase 3: Persistence & Provider Testing
|
||||
Focus: Ensure persistence and cross-provider compatibility
|
||||
|
||||
- [ ] Task: Verify base prompt persists across app restarts
|
||||
- [ ] Task: Test with Gemini provider
|
||||
- [ ] Task: Test with Anthropic provider
|
||||
- [ ] Task: Test with DeepSeek provider
|
||||
- [ ] Task: Test with Gemini CLI adapter
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 3: Persistence & Provider Testing'
|
||||
|
||||
## Phase 4: Safety & Defaults
|
||||
Focus: Ensure users can recover from bad edits
|
||||
|
||||
- [ ] Task: Implement confirmation dialog before saving custom base
|
||||
- [ ] Task: Add validation for empty/invalid prompts
|
||||
- [ ] Task: Document the base prompt purpose in UI
|
||||
- [ ] Task: Add "Show Diff" between default and custom
|
||||
- [ ] Task: Write tests for safety features
|
||||
- [ ] Task: Conductor - User Manual Verification 'Phase 4: Safety & Defaults'
|
||||
120
conductor/tracks/system_context_exposure_20260322/spec.md
Normal file
120
conductor/tracks/system_context_exposure_20260322/spec.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Specification: System Context Exposure
|
||||
|
||||
## 1. Overview
|
||||
|
||||
This track exposes the hidden system prompt from `ai_client.py` to users for customization.
|
||||
|
||||
**Current Problem:**
|
||||
- `_SYSTEM_PROMPT` in `ai_client.py` (lines ~118-143) is hardcoded
|
||||
- It contains foundational instructions: "You are a helpful coding assistant with access to a PowerShell tool..."
|
||||
- Users can only see/appending their custom portion via `_custom_system_prompt`
|
||||
- The base prompt that defines core agent capabilities is invisible
|
||||
|
||||
**Goal:**
|
||||
- Make `_SYSTEM_PROMPT` visible and editable in the UI
|
||||
- Allow users to customize the foundational agent instructions
|
||||
- Maintain sensible defaults while enabling expert customization
|
||||
|
||||
## 2. Current State Audit
|
||||
|
||||
### Hidden System Prompt Location
|
||||
`src/ai_client.py`:
|
||||
```python
|
||||
_SYSTEM_PROMPT: str = (
|
||||
"You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). "
|
||||
"When calling file/directory tools, always use the 'path' parameter for the target path. "
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### Related State
|
||||
- `_custom_system_prompt` - user-defined append/injection
|
||||
- `_get_combined_system_prompt()` - merges both
|
||||
- `set_custom_system_prompt()` - setter for user portion
|
||||
|
||||
### UI Current State
|
||||
- AI Settings → System Prompts shows global and project prompts
|
||||
- These are injected as `[USER SYSTEM PROMPT]` after `_SYSTEM_PROMPT`
|
||||
- But `_SYSTEM_PROMPT` itself is never shown
|
||||
|
||||
## 3. Functional Requirements
|
||||
|
||||
### 3.1 Base System Prompt Visibility
|
||||
- Add "Base System Prompt" section in AI Settings
|
||||
- Display current `_SYSTEM_PROMPT` content
|
||||
- Allow editing with syntax highlighting (it's markdown text)
|
||||
|
||||
### 3.2 Default vs Custom Base
|
||||
- Maintain default base prompt as reference
|
||||
- User can reset to default if they mess it up
|
||||
- Show diff between default and custom
|
||||
|
||||
### 3.3 Persistence
|
||||
- Custom base prompt stored in config or project TOML
|
||||
- Loaded on app start
|
||||
- Applied before `_custom_system_prompt` in `_get_combined_system_prompt()`
|
||||
|
||||
### 3.4 Provider Considerations
|
||||
- Some providers handle system prompts differently
|
||||
- Verify behavior across Gemini, Anthropic, DeepSeek
|
||||
- May need provider-specific base prompts
|
||||
|
||||
## 4. Data Model
|
||||
|
||||
### 4.1 Config Storage
|
||||
```toml
|
||||
[ai_settings]
|
||||
base_system_prompt = """..."""
|
||||
use_default_base = true
|
||||
```
|
||||
|
||||
### 4.2 Combined Prompt Order
|
||||
1. `_SYSTEM_PROMPT` (or custom base if enabled)
|
||||
2. `[USER SYSTEM PROMPT]` (from AI Settings global/project)
|
||||
3. Tooling strategy (from bias engine)
|
||||
|
||||
## 5. UI Design
|
||||
|
||||
**Location:** AI Settings panel → System Prompts section
|
||||
|
||||
```
|
||||
┌─ System Prompts ──────────────────────────────┐
|
||||
│ ☑ Use Default Base System Prompt │
|
||||
│ │
|
||||
│ Base System Prompt (collapsed by default): │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ You are a helpful coding assistant... │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Show Editor] [Reset to Default] │
|
||||
│ │
|
||||
│ Global System Prompt: │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ [current global prompt content] │ │
|
||||
│ └──────────────────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
When "Show Editor" clicked:
|
||||
- Expand to full editor for base prompt
|
||||
- Syntax highlighting for markdown
|
||||
- Character count
|
||||
|
||||
## 6. Acceptance Criteria
|
||||
|
||||
- [ ] `_SYSTEM_PROMPT` visible in AI Settings
|
||||
- [ ] User can edit base system prompt
|
||||
- [ ] Changes persist across app restarts
|
||||
- [ ] "Reset to Default" restores original
|
||||
- [ ] Provider APIs receive modified prompt correctly
|
||||
- [ ] No regression in agent behavior with defaults
|
||||
|
||||
## 7. Out of Scope
|
||||
- Changes to actual agent behavior logic
|
||||
- Changes to tool definitions or availability
|
||||
- Changes to aggregation or context handling
|
||||
|
||||
## 8. Dependencies
|
||||
- `ai_client.py` - `_SYSTEM_PROMPT` and `_get_combined_system_prompt()`
|
||||
- `gui_2.py` - AI Settings panel rendering
|
||||
- `models.py` - Config structures
|
||||
19
config.toml
19
config.toml
@@ -1,6 +1,6 @@
|
||||
[ai]
|
||||
provider = "gemini_cli"
|
||||
model = "gemini-2.5-flash-lite"
|
||||
provider = "minimax"
|
||||
model = "MiniMax-M2.5"
|
||||
temperature = 0.0
|
||||
top_p = 1.0
|
||||
max_tokens = 32000
|
||||
@@ -10,14 +10,9 @@ system_prompt = "Overridden Prompt"
|
||||
|
||||
[projects]
|
||||
paths = [
|
||||
"C:/projects/gencpp/gencpp_sloppy.toml",
|
||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_livecontextsim.toml",
|
||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_liveaisettingssim.toml",
|
||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_livetoolssim.toml",
|
||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_liveexecutionsim.toml",
|
||||
"C:\\projects\\manual_slop\\tests\\artifacts\\temp_project.toml",
|
||||
"C:/projects/gencpp/.ai/gencpp_sloppy.toml",
|
||||
]
|
||||
active = "C:/projects/gencpp/gencpp_sloppy.toml"
|
||||
active = "C:/projects/gencpp/.ai/gencpp_sloppy.toml"
|
||||
|
||||
[gui]
|
||||
separate_message_panel = false
|
||||
@@ -34,7 +29,7 @@ separate_tier4 = false
|
||||
separate_external_tools = false
|
||||
|
||||
[gui.show_windows]
|
||||
"Context Hub" = true
|
||||
"Project Settings" = true
|
||||
"Files & Media" = true
|
||||
"AI Settings" = true
|
||||
"MMA Dashboard" = false
|
||||
@@ -53,7 +48,7 @@ separate_external_tools = false
|
||||
Message = false
|
||||
Response = false
|
||||
"Tool Calls" = false
|
||||
Theme = true
|
||||
Theme = false
|
||||
"Log Management" = false
|
||||
Diagnostics = false
|
||||
"External Tools" = false
|
||||
@@ -61,7 +56,7 @@ Diagnostics = false
|
||||
"Session Hub" = false
|
||||
|
||||
[theme]
|
||||
palette = "10x Dark"
|
||||
palette = "Nord Dark"
|
||||
font_path = "fonts/Inter-Regular.ttf"
|
||||
font_size = 16.0
|
||||
scale = 1.0
|
||||
|
||||
@@ -12,7 +12,7 @@ ViewportPos=43,95
|
||||
ViewportId=0x78C57832
|
||||
Size=897,649
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Files]
|
||||
ViewportPos=3125,170
|
||||
@@ -33,7 +33,7 @@ DockId=0x0000000A,0
|
||||
Pos=0,17
|
||||
Size=1680,730
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Provider]
|
||||
ViewportPos=43,95
|
||||
@@ -41,7 +41,7 @@ ViewportId=0x78C57832
|
||||
Pos=0,651
|
||||
Size=897,468
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Message]
|
||||
Pos=711,694
|
||||
@@ -57,7 +57,7 @@ Collapsed=0
|
||||
Pos=1028,1668
|
||||
Size=1397,340
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
DockId=0x0000000E,0
|
||||
|
||||
[Window][Comms History]
|
||||
ViewportPos=43,95
|
||||
@@ -74,10 +74,10 @@ Collapsed=0
|
||||
DockId=0xAFC85805,2
|
||||
|
||||
[Window][Theme]
|
||||
Pos=0,249
|
||||
Size=32,951
|
||||
Pos=0,975
|
||||
Size=1010,730
|
||||
Collapsed=0
|
||||
DockId=0x00000002,2
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][Text Viewer - Entry #7]
|
||||
Pos=379,324
|
||||
@@ -85,16 +85,15 @@ Size=900,700
|
||||
Collapsed=0
|
||||
|
||||
[Window][Diagnostics]
|
||||
Pos=2177,26
|
||||
Size=1162,1777
|
||||
Pos=1945,734
|
||||
Size=1211,713
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
|
||||
[Window][Context Hub]
|
||||
Pos=0,249
|
||||
Size=32,951
|
||||
Pos=0,975
|
||||
Size=1010,730
|
||||
Collapsed=0
|
||||
DockId=0x00000002,1
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][AI Settings Hub]
|
||||
Pos=406,17
|
||||
@@ -103,28 +102,28 @@ Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
|
||||
[Window][Discussion Hub]
|
||||
Pos=807,26
|
||||
Size=873,1174
|
||||
Pos=1126,24
|
||||
Size=1638,1608
|
||||
Collapsed=0
|
||||
DockId=0x00000013,0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Operations Hub]
|
||||
Pos=34,26
|
||||
Size=771,1174
|
||||
Pos=0,24
|
||||
Size=1124,1608
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
DockId=0x00000005,2
|
||||
|
||||
[Window][Files & Media]
|
||||
Pos=0,249
|
||||
Size=32,951
|
||||
Pos=1126,24
|
||||
Size=1638,1608
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][AI Settings]
|
||||
Pos=0,26
|
||||
Size=32,221
|
||||
Pos=0,24
|
||||
Size=1124,1608
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Approve Tool Execution]
|
||||
Pos=3,524
|
||||
@@ -135,13 +134,13 @@ Collapsed=0
|
||||
Pos=3360,26
|
||||
Size=480,2134
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Log Management]
|
||||
Pos=3360,26
|
||||
Size=480,2134
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Track Proposal]
|
||||
Pos=709,326
|
||||
@@ -400,6 +399,18 @@ Pos=1518,488
|
||||
Size=900,700
|
||||
Collapsed=0
|
||||
|
||||
[Window][Session Hub]
|
||||
Pos=1163,24
|
||||
Size=1234,1542
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][Project Settings]
|
||||
Pos=0,24
|
||||
Size=1124,1608
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
[Table][0xFB6E3870,4]
|
||||
RefScale=13
|
||||
Column 0 Width=80
|
||||
@@ -431,11 +442,11 @@ Column 3 Width=20
|
||||
Column 4 Weight=1.0000
|
||||
|
||||
[Table][0x2A6000B6,4]
|
||||
RefScale=18
|
||||
Column 0 Width=54
|
||||
Column 1 Width=76
|
||||
RefScale=16
|
||||
Column 0 Width=48
|
||||
Column 1 Width=67
|
||||
Column 2 Weight=1.0000
|
||||
Column 3 Width=274
|
||||
Column 3 Width=243
|
||||
|
||||
[Table][0x8BCC69C7,6]
|
||||
RefScale=13
|
||||
@@ -454,11 +465,11 @@ Column 2 Weight=1.0000
|
||||
Column 3 Width=135
|
||||
|
||||
[Table][0x2C515046,4]
|
||||
RefScale=18
|
||||
Column 0 Width=54
|
||||
RefScale=16
|
||||
Column 0 Width=48
|
||||
Column 1 Weight=1.0000
|
||||
Column 2 Width=132
|
||||
Column 3 Width=54
|
||||
Column 2 Width=166
|
||||
Column 3 Width=48
|
||||
|
||||
[Table][0xD99F45C5,4]
|
||||
Column 0 Sort=0v
|
||||
@@ -479,9 +490,9 @@ Column 1 Width=100
|
||||
Column 2 Weight=1.0000
|
||||
|
||||
[Table][0xA02D8C87,3]
|
||||
RefScale=18
|
||||
Column 0 Width=202
|
||||
Column 1 Width=135
|
||||
RefScale=16
|
||||
Column 0 Width=179
|
||||
Column 1 Width=120
|
||||
Column 2 Weight=1.0000
|
||||
|
||||
[Table][0xD0277E63,2]
|
||||
@@ -513,23 +524,17 @@ Column 1 Weight=1.0000
|
||||
DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y
|
||||
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A
|
||||
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,26 Size=1680,1174 Split=X
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,24 Size=2764,1608 Split=X
|
||||
DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2175,1183 Split=X
|
||||
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2
|
||||
DockNode ID=0x00000007 Parent=0x0000000B SizeRef=1071,858 Split=Y Selected=0x8CA2375C
|
||||
DockNode ID=0x00000001 Parent=0x00000007 SizeRef=824,1037 CentralNode=1 Selected=0x7BD57D6A
|
||||
DockNode ID=0x00000002 Parent=0x00000007 SizeRef=824,951 Selected=0x1DCB2623
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=2767,858 Split=X Selected=0x418C7449
|
||||
DockNode ID=0x00000012 Parent=0x0000000E SizeRef=1297,402 Split=Y Selected=0x418C7449
|
||||
DockNode ID=0x00000005 Parent=0x00000012 SizeRef=876,1749 Selected=0x418C7449
|
||||
DockNode ID=0x00000006 Parent=0x00000012 SizeRef=876,362 Selected=0x1D56B311
|
||||
DockNode ID=0x00000013 Parent=0x0000000E SizeRef=1468,402 Selected=0x6F2B5B04
|
||||
DockNode ID=0x00000007 Parent=0x0000000B SizeRef=1512,858 Split=X Selected=0x8CA2375C
|
||||
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=1226,1681 CentralNode=1 Selected=0x7BD57D6A
|
||||
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=1638,1681 Selected=0x6F2B5B04
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=1777,858 Selected=0x418C7449
|
||||
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
|
||||
DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=1162,1183 Split=Y Selected=0x3AEC3498
|
||||
DockNode ID=0x00000010 Parent=0x00000004 SizeRef=1199,1689 Selected=0xB4CBF21A
|
||||
DockNode ID=0x00000011 Parent=0x00000004 SizeRef=1199,420 Split=X Selected=0xDEB547B6
|
||||
DockNode ID=0x0000000C Parent=0x00000011 SizeRef=916,380 Selected=0x655BC6E9
|
||||
DockNode ID=0x0000000F Parent=0x00000011 SizeRef=281,380 Selected=0xDEB547B6
|
||||
DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=1162,1183 Split=X Selected=0x3AEC3498
|
||||
DockNode ID=0x0000000C Parent=0x00000004 SizeRef=916,380 Selected=0x655BC6E9
|
||||
DockNode ID=0x0000000F Parent=0x00000004 SizeRef=281,380 Selected=0xDEB547B6
|
||||
|
||||
;;;<<<Layout_655921752_Default>>>;;;
|
||||
;;;<<<HelloImGui_Misc>>>;;;
|
||||
|
||||
@@ -71,5 +71,6 @@
|
||||
"logs/**",
|
||||
"*.log"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ active = "main"
|
||||
|
||||
[discussions.main]
|
||||
git_commit = ""
|
||||
last_updated = "2026-03-21T15:21:34"
|
||||
last_updated = "2026-03-22T12:59:02"
|
||||
history = []
|
||||
|
||||
@@ -230,7 +230,6 @@ class AppController:
|
||||
self.ui_project_system_prompt: str = ""
|
||||
self.ui_gemini_cli_path: str = "gemini"
|
||||
self.ui_word_wrap: bool = True
|
||||
self.ui_summary_only: bool = False
|
||||
self.ui_auto_add_history: bool = False
|
||||
self.ui_active_tool_preset: str | None = None
|
||||
self.ui_global_system_prompt: str = ""
|
||||
@@ -912,7 +911,6 @@ class AppController:
|
||||
self.ui_gemini_cli_path = self.project.get("gemini_cli", {}).get("binary_path", "gemini")
|
||||
self._update_gcli_adapter(self.ui_gemini_cli_path)
|
||||
self.ui_word_wrap = proj_meta.get("word_wrap", True)
|
||||
self.ui_summary_only = proj_meta.get("summary_only", False)
|
||||
self.ui_auto_add_history = disc_sec.get("auto_add", False)
|
||||
self.ui_global_system_prompt = self.config.get("ai", {}).get("system_prompt", "")
|
||||
|
||||
@@ -952,7 +950,7 @@ class AppController:
|
||||
bg_shader.get_bg().enabled = gui_cfg.get("bg_shader_enabled", False)
|
||||
|
||||
_default_windows = {
|
||||
"Context Hub": True,
|
||||
"Project Settings": True,
|
||||
"Files & Media": True,
|
||||
"AI Settings": True,
|
||||
"MMA Dashboard": True,
|
||||
@@ -2006,7 +2004,6 @@ class AppController:
|
||||
self.ui_auto_scroll_comms = proj.get("project", {}).get("auto_scroll_comms", True)
|
||||
self.ui_auto_scroll_tool_calls = proj.get("project", {}).get("auto_scroll_tool_calls", True)
|
||||
self.ui_word_wrap = proj.get("project", {}).get("word_wrap", True)
|
||||
self.ui_summary_only = proj.get("project", {}).get("summary_only", False)
|
||||
agent_tools_cfg = proj.get("agent", {}).get("tools", {})
|
||||
self.ui_agent_tools = {t: agent_tools_cfg.get(t, True) for t in models.AGENT_TOOL_NAMES}
|
||||
# MMA Tracks
|
||||
@@ -2458,7 +2455,6 @@ class AppController:
|
||||
proj["project"]["main_context"] = self.ui_project_main_context
|
||||
proj["project"]["active_preset"] = self.ui_project_preset_name
|
||||
proj["project"]["word_wrap"] = self.ui_word_wrap
|
||||
proj["project"]["summary_only"] = self.ui_summary_only
|
||||
proj["project"]["auto_scroll_comms"] = self.ui_auto_scroll_comms
|
||||
proj["project"]["auto_scroll_tool_calls"] = self.ui_auto_scroll_tool_calls
|
||||
proj.setdefault("gemini_cli", {})["binary_path"] = self.ui_gemini_cli_path
|
||||
|
||||
234
src/gui_2.py
234
src/gui_2.py
@@ -215,7 +215,6 @@ class App:
|
||||
self.show_windows.setdefault("Tier 4: QA", False)
|
||||
self.show_windows.setdefault('External Tools', False)
|
||||
self.show_windows.setdefault('Shader Editor', False)
|
||||
self.show_windows.setdefault('Session Hub', False)
|
||||
self.ui_multi_viewport = gui_cfg.get("multi_viewport", False)
|
||||
self.layout_presets = self.config.get("layout_presets", {})
|
||||
self._new_preset_name = ""
|
||||
@@ -639,9 +638,9 @@ class App:
|
||||
self._tool_log_cache = log_raw
|
||||
self._tool_log_dirty = False
|
||||
|
||||
if self.show_windows.get("Context Hub", False):
|
||||
exp, opened = imgui.begin("Context Hub", self.show_windows["Context Hub"])
|
||||
self.show_windows["Context Hub"] = bool(opened)
|
||||
if self.show_windows.get("Project Settings", False):
|
||||
exp, opened = imgui.begin("Project Settings", self.show_windows["Project Settings"])
|
||||
self.show_windows["Project Settings"] = bool(opened)
|
||||
if exp:
|
||||
if imgui.begin_tab_bar('context_hub_tabs'):
|
||||
if imgui.begin_tab_item('Projects')[0]:
|
||||
@@ -650,9 +649,6 @@ class App:
|
||||
if imgui.begin_tab_item('Paths')[0]:
|
||||
self._render_paths_panel()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item('Context Presets')[0]:
|
||||
self._render_context_presets_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
imgui.end()
|
||||
if self.show_windows.get("Files & Media", False):
|
||||
@@ -727,50 +723,20 @@ class App:
|
||||
exp, opened = imgui.begin("Discussion Hub", self.show_windows["Discussion Hub"])
|
||||
self.show_windows["Discussion Hub"] = bool(opened)
|
||||
if exp:
|
||||
# Top part for the history
|
||||
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_discussion_panel")
|
||||
self._render_discussion_panel()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_discussion_panel")
|
||||
imgui.end_child()
|
||||
# Splitter
|
||||
imgui.button("###discussion_splitter", imgui.ImVec2(-1, 4))
|
||||
if imgui.is_item_active():
|
||||
self.ui_discussion_split_h = max(150.0, min(imgui.get_window_height() - 150.0, self.ui_discussion_split_h - imgui.get_io().mouse_delta.y))
|
||||
# Bottom part with tabs for message and response
|
||||
# Detach controls
|
||||
imgui.push_style_var(imgui.StyleVar_.item_spacing, imgui.ImVec2(10, 4))
|
||||
ch1, self.ui_separate_message_panel = imgui.checkbox("Pop Out Message", self.ui_separate_message_panel)
|
||||
imgui.same_line()
|
||||
ch2, self.ui_separate_response_panel = imgui.checkbox("Pop Out Response", self.ui_separate_response_panel)
|
||||
if ch1: self.show_windows["Message"] = self.ui_separate_message_panel
|
||||
if ch2: self.show_windows["Response"] = self.ui_separate_response_panel
|
||||
imgui.pop_style_var()
|
||||
|
||||
show_message_tab = not self.ui_separate_message_panel
|
||||
show_response_tab = not self.ui_separate_response_panel
|
||||
|
||||
if show_message_tab or show_response_tab:
|
||||
if imgui.begin_tab_bar("discussion_tabs"):
|
||||
# Task: Auto-focus Response tab when response received
|
||||
tab_flags = imgui.TabItemFlags_.none
|
||||
if self._autofocus_response_tab:
|
||||
tab_flags = imgui.TabItemFlags_.set_selected
|
||||
self._autofocus_response_tab = False
|
||||
self.controller._autofocus_response_tab = False
|
||||
|
||||
if show_message_tab:
|
||||
if imgui.begin_tab_item("Message", None)[0]:
|
||||
self._render_message_panel()
|
||||
if imgui.begin_tab_bar("discussion_hub_tabs"):
|
||||
if imgui.begin_tab_item("Discussion")[0]:
|
||||
self._render_discussion_tab()
|
||||
imgui.end_tab_item()
|
||||
if show_response_tab:
|
||||
if imgui.begin_tab_item("Response", None, tab_flags)[0]:
|
||||
self._render_response_panel()
|
||||
if imgui.begin_tab_item("Context Composition")[0]:
|
||||
self._render_context_composition_panel()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("Snapshot")[0]:
|
||||
self._render_snapshot_tab()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("Takes")[0]:
|
||||
self._render_takes_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
else:
|
||||
imgui.text_disabled("Message & Response panels are detached.")
|
||||
|
||||
imgui.end()
|
||||
if self.show_windows.get("Operations Hub", False):
|
||||
exp, opened = imgui.begin("Operations Hub", self.show_windows["Operations Hub"])
|
||||
@@ -845,8 +811,6 @@ class App:
|
||||
if self.show_windows.get("Diagnostics", False):
|
||||
self._render_diagnostics_panel()
|
||||
|
||||
self._render_session_hub()
|
||||
|
||||
self.perf_monitor.end_frame()
|
||||
# ---- Modals / Popups
|
||||
with self._pending_dialog_lock:
|
||||
@@ -1702,7 +1666,6 @@ class App:
|
||||
models.save_config(self.config)
|
||||
self.ai_status = "config saved"
|
||||
ch, self.ui_word_wrap = imgui.checkbox("Word-Wrap (Read-only panels)", self.ui_word_wrap)
|
||||
ch, self.ui_summary_only = imgui.checkbox("Summary Only (send file structure, not full content)", self.ui_summary_only)
|
||||
ch, self.ui_auto_scroll_comms = imgui.checkbox("Auto-scroll Comms History", self.ui_auto_scroll_comms)
|
||||
ch, self.ui_auto_scroll_tool_calls = imgui.checkbox("Auto-scroll Tool History", self.ui_auto_scroll_tool_calls)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_projects_panel")
|
||||
@@ -2085,13 +2048,98 @@ class App:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel")
|
||||
imgui.end()
|
||||
|
||||
def _render_session_hub(self) -> None:
|
||||
if self.show_windows.get('Session Hub', False):
|
||||
exp, opened = imgui.begin('Session Hub', self.show_windows['Session Hub'])
|
||||
self.show_windows['Session Hub'] = bool(opened)
|
||||
if exp:
|
||||
if imgui.begin_tab_bar('session_hub_tabs'):
|
||||
if imgui.begin_tab_item('Aggregate MD')[0]:
|
||||
def _render_discussion_tab(self) -> None:
|
||||
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_discussion_panel")
|
||||
self._render_discussion_panel()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_discussion_panel")
|
||||
imgui.end_child()
|
||||
imgui.button("###discussion_splitter", imgui.ImVec2(-1, 4))
|
||||
if imgui.is_item_active():
|
||||
self.ui_discussion_split_h = max(150.0, min(imgui.get_window_height() - 150.0, self.ui_discussion_split_h - imgui.get_io().mouse_delta.y))
|
||||
imgui.push_style_var(imgui.StyleVar_.item_spacing, imgui.ImVec2(10, 4))
|
||||
ch1, self.ui_separate_message_panel = imgui.checkbox("Pop Out Message", self.ui_separate_message_panel)
|
||||
imgui.same_line()
|
||||
ch2, self.ui_separate_response_panel = imgui.checkbox("Pop Out Response", self.ui_separate_response_panel)
|
||||
if ch1: self.show_windows["Message"] = self.ui_separate_message_panel
|
||||
if ch2: self.show_windows["Response"] = self.ui_separate_response_panel
|
||||
imgui.pop_style_var()
|
||||
show_message_tab = not self.ui_separate_message_panel
|
||||
show_response_tab = not self.ui_separate_response_panel
|
||||
if show_message_tab or show_response_tab:
|
||||
if imgui.begin_tab_bar("discussion_tabs"):
|
||||
tab_flags = imgui.TabItemFlags_.none
|
||||
if self._autofocus_response_tab:
|
||||
tab_flags = imgui.TabItemFlags_.set_selected
|
||||
self._autofocus_response_tab = False
|
||||
self.controller._autofocus_response_tab = False
|
||||
if show_message_tab:
|
||||
if imgui.begin_tab_item("Message", None)[0]:
|
||||
self._render_message_panel()
|
||||
imgui.end_tab_item()
|
||||
if show_response_tab:
|
||||
if imgui.begin_tab_item("Response", None, tab_flags)[0]:
|
||||
self._render_response_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
else:
|
||||
imgui.text_disabled("Message & Response panels are detached.")
|
||||
|
||||
def _render_context_composition_panel(self) -> None:
|
||||
imgui.text("Context Composition")
|
||||
imgui.separator()
|
||||
if imgui.begin_table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 120)
|
||||
imgui.table_headers_row()
|
||||
for i, f_item in enumerate(self.files):
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
imgui.text(f_item.path if hasattr(f_item, "path") else str(f_item))
|
||||
imgui.table_set_column_index(1)
|
||||
if hasattr(f_item, "auto_aggregate"):
|
||||
changed_agg, f_item.auto_aggregate = imgui.checkbox(f"Agg##cc{i}", f_item.auto_aggregate)
|
||||
imgui.same_line()
|
||||
changed_full, f_item.force_full = imgui.checkbox(f"Full##cc{i}", f_item.force_full)
|
||||
imgui.end_table()
|
||||
imgui.separator()
|
||||
imgui.text("Screenshots")
|
||||
for i, s in enumerate(self.screenshots):
|
||||
imgui.text(s)
|
||||
imgui.separator()
|
||||
imgui.text("Presets")
|
||||
presets = self.controller.project.get('context_presets', {})
|
||||
preset_names = [""] + sorted(presets.keys())
|
||||
active = getattr(self, "ui_active_context_preset", "")
|
||||
if active not in preset_names:
|
||||
active = ""
|
||||
try:
|
||||
idx = preset_names.index(active)
|
||||
except ValueError:
|
||||
idx = 0
|
||||
ch, new_idx = imgui.combo("##ctx_preset", idx, preset_names)
|
||||
if ch:
|
||||
self.ui_active_context_preset = preset_names[new_idx]
|
||||
if preset_names[new_idx]:
|
||||
self.load_context_preset(preset_names[new_idx])
|
||||
imgui.same_line()
|
||||
changed, new_name = imgui.input_text("##new_preset", getattr(self, "ui_new_context_preset_name", ""))
|
||||
if changed:
|
||||
self.ui_new_context_preset_name = new_name
|
||||
imgui.same_line()
|
||||
if imgui.button("Save##ctx"):
|
||||
if getattr(self, "ui_new_context_preset_name", "").strip():
|
||||
self.save_context_preset(self.ui_new_context_preset_name.strip())
|
||||
self.ui_new_context_preset_name = ""
|
||||
imgui.same_line()
|
||||
if imgui.button("Delete##ctx"):
|
||||
if getattr(self, "ui_active_context_preset", ""):
|
||||
self.delete_context_preset(self.ui_active_context_preset)
|
||||
self.ui_active_context_preset = ""
|
||||
|
||||
def _render_snapshot_tab(self) -> None:
|
||||
if imgui.begin_tab_bar("snapshot_tabs"):
|
||||
if imgui.begin_tab_item("Aggregate MD")[0]:
|
||||
display_md = self.last_aggregate_markdown
|
||||
if self.ui_focus_agent:
|
||||
tier_usage = self.mma_tier_usage.get(self.ui_focus_agent)
|
||||
@@ -2104,7 +2152,6 @@ class App:
|
||||
if cp_name in self._focus_md_cache:
|
||||
display_md = self._focus_md_cache[cp_name]
|
||||
else:
|
||||
# Generate focused aggregate
|
||||
flat = src.project_manager.flat_config(self.controller.project, self.active_discussion)
|
||||
cp = self.controller.project.get('context_presets', {}).get(cp_name)
|
||||
if cp:
|
||||
@@ -2116,19 +2163,73 @@ class App:
|
||||
if imgui.button("Copy"):
|
||||
imgui.set_clipboard_text(display_md)
|
||||
imgui.begin_child("last_agg_md", imgui.ImVec2(0, 0), True)
|
||||
markdown_helper.render(display_md, context_id="session_hub_agg")
|
||||
markdown_helper.render(display_md, context_id="snapshot_agg")
|
||||
imgui.end_child()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item('System Prompt')[0]:
|
||||
if imgui.begin_tab_item("System Prompt")[0]:
|
||||
if imgui.button("Copy"):
|
||||
imgui.set_clipboard_text(self.last_resolved_system_prompt)
|
||||
imgui.begin_child("last_sys_prompt", imgui.ImVec2(0, 0), True)
|
||||
markdown_helper.render(self.last_resolved_system_prompt, context_id="session_hub_sys")
|
||||
markdown_helper.render(self.last_resolved_system_prompt, context_id="snapshot_sys")
|
||||
imgui.end_child()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
imgui.end()
|
||||
|
||||
def _render_takes_panel(self) -> None:
|
||||
imgui.text("Takes & Synthesis")
|
||||
imgui.separator()
|
||||
discussions = self.project.get('discussion', {}).get('discussions', {})
|
||||
if not hasattr(self, 'ui_synthesis_selected_takes'):
|
||||
self.ui_synthesis_selected_takes = {name: False for name in discussions}
|
||||
if not hasattr(self, 'ui_synthesis_prompt'):
|
||||
self.ui_synthesis_prompt = ""
|
||||
if imgui.begin_table("takes_table", 3, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Name", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Entries", imgui.TableColumnFlags_.width_fixed, 80)
|
||||
imgui.table_setup_column("Actions", imgui.TableColumnFlags_.width_fixed, 150)
|
||||
imgui.table_headers_row()
|
||||
for name, disc in discussions.items():
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
is_active = name == self.active_discussion
|
||||
if is_active:
|
||||
imgui.text_colored(C_IN, name)
|
||||
else:
|
||||
imgui.text(name)
|
||||
imgui.table_set_column_index(1)
|
||||
history = disc.get('history', [])
|
||||
imgui.text(f"{len(history)}")
|
||||
imgui.table_set_column_index(2)
|
||||
if imgui.button(f"Switch##{name}"):
|
||||
self._switch_discussion(name)
|
||||
imgui.same_line()
|
||||
if name != "main" and imgui.button(f"Delete##{name}"):
|
||||
del discussions[name]
|
||||
imgui.end_table()
|
||||
imgui.separator()
|
||||
imgui.text("Synthesis")
|
||||
imgui.text("Select takes to synthesize:")
|
||||
for name in discussions:
|
||||
_, self.ui_synthesis_selected_takes[name] = imgui.checkbox(name, self.ui_synthesis_selected_takes.get(name, False))
|
||||
imgui.spacing()
|
||||
imgui.text("Synthesis Prompt:")
|
||||
_, self.ui_synthesis_prompt = imgui.input_text_multiline("##synthesis_prompt", self.ui_synthesis_prompt, imgui.ImVec2(-1, 100))
|
||||
if imgui.button("Generate Synthesis"):
|
||||
selected = [name for name, sel in self.ui_synthesis_selected_takes.items() if sel]
|
||||
if len(selected) > 1:
|
||||
from src import synthesis_formatter
|
||||
takes_dict = {name: discussions.get(name, {}).get('history', []) for name in selected}
|
||||
diff_text = synthesis_formatter.format_takes_diff(takes_dict)
|
||||
prompt = f"{self.ui_synthesis_prompt}\n\nHere are the variations:\n{diff_text}"
|
||||
new_name = "synthesis_take"
|
||||
counter = 1
|
||||
while new_name in discussions:
|
||||
new_name = f"synthesis_take_{counter}"
|
||||
counter += 1
|
||||
self._create_discussion(new_name)
|
||||
with self._disc_entries_lock:
|
||||
self.disc_entries.append({"role": "user", "content": prompt, "collapsed": False, "ts": project_manager.now_ts()})
|
||||
self._handle_generate_send()
|
||||
def _render_markdown_test(self) -> None:
|
||||
imgui.text("Markdown Test Panel")
|
||||
imgui.separator()
|
||||
@@ -2330,7 +2431,10 @@ def hello():
|
||||
imgui.set_item_default_focus()
|
||||
imgui.end_combo()
|
||||
|
||||
# Sync variables in case combo selection changed self.active_discussion
|
||||
active_base = self.active_discussion.split("_take_")[0]
|
||||
current_takes = grouped_discussions.get(active_base, [])
|
||||
|
||||
if imgui.begin_tab_bar("discussion_takes_tabs"):
|
||||
for take_name in current_takes:
|
||||
label = "Original" if take_name == active_base else take_name.replace(f"{active_base}_", "").replace("_", " ").title()
|
||||
@@ -2649,6 +2753,8 @@ def hello():
|
||||
if imgui.selectable("None", not self.ui_active_persona)[0]:
|
||||
self.ui_active_persona = ""
|
||||
for pname in sorted(personas.keys()):
|
||||
if not pname:
|
||||
continue
|
||||
if imgui.selectable(pname, pname == self.ui_active_persona)[0]:
|
||||
self.ui_active_persona = pname
|
||||
if pname in personas:
|
||||
@@ -4216,6 +4322,8 @@ def hello():
|
||||
from src import ai_client
|
||||
ai_client.set_bias_profile(None)
|
||||
for bname in sorted(self.controller.bias_profiles.keys()):
|
||||
if not bname:
|
||||
continue
|
||||
if imgui.selectable(bname, bname == getattr(self, 'ui_active_bias_profile', ""))[0]:
|
||||
self.ui_active_bias_profile = bname
|
||||
from src import ai_client
|
||||
|
||||
42
tests/test_context_composition_panel.py
Normal file
42
tests/test_context_composition_panel.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
def test_context_composition_panel_replaces_placeholder():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "_render_context_composition_placeholder" not in source, (
|
||||
"Placeholder should be replaced"
|
||||
)
|
||||
assert "_render_context_composition_panel" in source, (
|
||||
"Should have _render_context_composition_panel"
|
||||
)
|
||||
|
||||
|
||||
def test_context_composition_has_save_load_buttons():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._render_context_composition_panel)
|
||||
assert "Save as Preset" in source or "save" in source.lower(), (
|
||||
"Should have Save functionality"
|
||||
)
|
||||
assert "Load Preset" in source or "load" in source.lower(), (
|
||||
"Should have Load functionality"
|
||||
)
|
||||
|
||||
|
||||
def test_context_composition_shows_files():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._render_context_composition_panel)
|
||||
assert "files" in source.lower() or "Files" in source, "Should show files"
|
||||
|
||||
|
||||
def test_context_composition_has_preset_list():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._render_context_composition_panel)
|
||||
assert "context_presets" in source or "preset" in source.lower(), (
|
||||
"Should reference presets"
|
||||
)
|
||||
14
tests/test_context_presets_removal.py
Normal file
14
tests/test_context_presets_removal.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
def test_context_presets_tab_removed_from_project_settings():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Context Presets" not in source, (
|
||||
"Context Presets tab should be removed from Project Settings"
|
||||
)
|
||||
assert "_render_context_presets_panel" not in source, (
|
||||
"Context presets panel call should be removed"
|
||||
)
|
||||
@@ -6,7 +6,7 @@ def test_gui2_hubs_exist_in_show_windows(app_instance: App) -> None:
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
"""
|
||||
expected_hubs = [
|
||||
"Context Hub",
|
||||
"Project Settings",
|
||||
"AI Settings",
|
||||
"Discussion Hub",
|
||||
"Operations Hub",
|
||||
|
||||
@@ -15,7 +15,7 @@ def test_new_hubs_defined_in_show_windows(mock_app: App) -> None:
|
||||
This ensures they will be available in the 'Windows' menu.
|
||||
"""
|
||||
expected_hubs = [
|
||||
"Context Hub",
|
||||
"Project Settings",
|
||||
"AI Settings",
|
||||
"Discussion Hub",
|
||||
"Operations Hub",
|
||||
@@ -53,7 +53,7 @@ def test_hub_windows_exist_in_gui2(app_instance_simple: Any) -> None:
|
||||
"""
|
||||
Verifies that the new Hub windows are present in the show_windows dictionary.
|
||||
"""
|
||||
hubs = ["Context Hub", "AI Settings", "Discussion Hub", "Operations Hub"]
|
||||
hubs = ["Project Settings", "AI Settings", "Discussion Hub", "Operations Hub"]
|
||||
for hub in hubs:
|
||||
assert hub in app_instance_simple.show_windows
|
||||
|
||||
|
||||
22
tests/test_project_settings_rename.py
Normal file
22
tests/test_project_settings_rename.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
def test_context_hub_renamed_to_project_settings():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Project Settings" in source, (
|
||||
"Context Hub should be renamed to Project Settings"
|
||||
)
|
||||
assert '"Context Hub"' not in source, '"Context Hub" string should be removed'
|
||||
|
||||
|
||||
def test_show_windows_key_updated():
|
||||
import src.app_controller as app_controller
|
||||
|
||||
source = inspect.getsource(app_controller.AppController)
|
||||
assert '"Project Settings"' in source or "'Project Settings'" in source, (
|
||||
"show_windows key should be Project Settings"
|
||||
)
|
||||
assert '"Context Hub"' not in source, '"Context Hub" key should be removed'
|
||||
42
tests/test_session_hub_merge.py
Normal file
42
tests/test_session_hub_merge.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
def test_session_hub_window_removed():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Session Hub" not in source, "Session Hub window should be removed"
|
||||
|
||||
|
||||
def test_discussion_hub_has_snapshot_tab():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Snapshot" in source, "Discussion Hub should have Snapshot tab"
|
||||
assert "_render_snapshot_tab" in source, "Discussion Hub should call _render_snapshot_tab"
|
||||
|
||||
|
||||
def test_discussion_hub_has_context_composition_placeholder():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Context Composition" in source, (
|
||||
"Discussion Hub should have Context Composition tab placeholder"
|
||||
)
|
||||
|
||||
|
||||
def test_discussion_hub_has_takes_tab():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "Takes" in source, "Discussion Hub should have Takes tab"
|
||||
|
||||
|
||||
def test_show_windows_no_session_hub():
|
||||
import src.app_controller as app_controller
|
||||
|
||||
source = inspect.getsource(app_controller.AppController)
|
||||
assert "Session Hub" not in source, (
|
||||
"Session Hub should be removed from show_windows"
|
||||
)
|
||||
16
tests/test_takes_panel.py
Normal file
16
tests/test_takes_panel.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import pytest
|
||||
import inspect
|
||||
|
||||
|
||||
def test_takes_tab_replaces_placeholder():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._gui_func)
|
||||
assert "_render_takes_placeholder" not in source, "Placeholder should be replaced"
|
||||
|
||||
|
||||
def test_takes_panel_has_synthesis():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._render_takes_panel)
|
||||
assert "synthesis" in source.lower(), "Should have synthesis functionality"
|
||||
75
tests/test_ui_summary_only_removal.py
Normal file
75
tests/test_ui_summary_only_removal.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import pytest
|
||||
import inspect
|
||||
from src import models
|
||||
|
||||
|
||||
def test_ui_summary_only_not_in_projects_panel():
|
||||
import src.gui_2 as gui_2
|
||||
|
||||
source = inspect.getsource(gui_2.App._render_projects_panel)
|
||||
assert "ui_summary_only" not in source, (
|
||||
"ui_summary_only checkbox should be removed from Projects panel"
|
||||
)
|
||||
assert "Summary Only" not in source, (
|
||||
"Summary Only label should be removed from Projects panel"
|
||||
)
|
||||
|
||||
|
||||
def test_ui_summary_only_not_in_app_controller_projects():
|
||||
import src.app_controller as app_controller
|
||||
|
||||
source = inspect.getsource(app_controller.AppController)
|
||||
assert "ui_summary_only" not in source, (
|
||||
"ui_summary_only should be removed from AppController"
|
||||
)
|
||||
|
||||
|
||||
def test_file_item_has_per_file_flags():
|
||||
item = models.FileItem(path="test.py")
|
||||
assert hasattr(item, "auto_aggregate")
|
||||
assert hasattr(item, "force_full")
|
||||
assert item.auto_aggregate is True
|
||||
assert item.force_full is False
|
||||
|
||||
|
||||
def test_file_item_serialization_with_flags():
|
||||
item = models.FileItem(path="test.py", auto_aggregate=False, force_full=True)
|
||||
data = item.to_dict()
|
||||
|
||||
assert data["auto_aggregate"] is False
|
||||
assert data["force_full"] is True
|
||||
|
||||
restored = models.FileItem.from_dict(data)
|
||||
assert restored.auto_aggregate is False
|
||||
assert restored.force_full is True
|
||||
|
||||
|
||||
def test_project_without_summary_only_loads():
|
||||
proj = {"project": {"name": "test", "paths": []}}
|
||||
assert proj.get("project", {}).get("summary_only") is None
|
||||
|
||||
|
||||
def test_aggregate_from_items_respects_auto_aggregate():
|
||||
from pathlib import Path
|
||||
from src import aggregate
|
||||
|
||||
items = [
|
||||
{
|
||||
"path": Path("file1.py"),
|
||||
"entry": "file1.py",
|
||||
"content": "print('hello')",
|
||||
"auto_aggregate": True,
|
||||
"force_full": False,
|
||||
},
|
||||
{
|
||||
"path": Path("file2.py"),
|
||||
"entry": "file2.py",
|
||||
"content": "print('world')",
|
||||
"auto_aggregate": False,
|
||||
"force_full": False,
|
||||
},
|
||||
]
|
||||
|
||||
result = aggregate._build_files_section_from_items(items)
|
||||
assert "file1.py" in result
|
||||
assert "file2.py" not in result
|
||||
Reference in New Issue
Block a user