File size: 5,371 Bytes
aceb1b2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Live Coding Agent Display

Dual-mode display for live coding agent sessions:
- Live mode (no data): Shows start form + streaming viewer with controls
- Review mode (data present): Delegates to CodingTraceDisplay

Usage:
    fields:
      - key: structured_turns
        type: live_coding_agent
        display_options:
          show_file_tree: true
          show_reasoning: true
          collapse_long_outputs: true
"""

import html
from typing import Dict, Any, List, Optional

from .base import BaseDisplay
from .coding_trace_display import CodingTraceDisplay


class LiveCodingAgentDisplay(BaseDisplay):
    """Display type for live coding agent sessions."""

    name = "live_coding_agent"
    required_fields = ["key"]
    optional_fields = {
        "show_file_tree": True,
        "show_reasoning": True,
        "collapse_long_outputs": True,
        "max_output_lines": 50,
        "show_controls": True,
        "allow_instructions": True,
    }
    description = "Live coding agent viewer with real-time streaming and intervention controls"
    supports_span_target = False

    def __init__(self):
        self._coding_trace_display = CodingTraceDisplay()

    def render(self, field_config: Dict[str, Any], data: Any) -> str:
        # If data has structured turns, delegate to CodingTraceDisplay (review mode)
        if data and isinstance(data, (list, dict)):
            if isinstance(data, list) and len(data) > 0:
                return self._coding_trace_display.render(field_config, data)
            if isinstance(data, dict) and data.get("structured_turns"):
                return self._coding_trace_display.render(
                    field_config, data["structured_turns"]
                )

        # Live mode: render the viewer UI
        field_key = html.escape(field_config.get("key", ""), quote=True)
        options = self.get_display_options(field_config)

        show_controls = options.get("show_controls", True)
        allow_instructions = options.get("allow_instructions", True)

        controls_html = ""
        if show_controls:
            controls_html = f'''
            <div class="lca-controls" id="lca-controls-{field_key}">
                <button type="button" class="lca-btn lca-btn-pause" data-action="pause" title="Pause agent">
                    Pause
                </button>
                <button type="button" class="lca-btn lca-btn-resume" data-action="resume" title="Resume agent" style="display:none">
                    Resume
                </button>
                <button type="button" class="lca-btn lca-btn-stop" data-action="stop" title="Stop agent">
                    Stop
                </button>
            </div>
            '''

        instruction_html = ""
        if allow_instructions:
            instruction_html = f'''
            <div class="lca-instruction" id="lca-instruction-{field_key}">
                <input type="text" class="lca-instruction-input"
                       placeholder="Send instruction to agent..."
                       id="lca-instruction-input-{field_key}">
                <button type="button" class="lca-btn lca-btn-send" data-action="instruct">
                    Send
                </button>
            </div>
            '''

        return f'''
        <div class="live-coding-agent-viewer" id="lca-viewer-{field_key}"
             data-field-key="{field_key}">

            <!-- Start form (shown when no session active) -->
            <div class="lca-start-form" id="lca-start-{field_key}">
                <div class="lca-start-header">Start Coding Agent</div>
                <textarea class="lca-task-input" id="lca-task-{field_key}"
                          rows="3" placeholder="Describe the coding task..."></textarea>
                <button type="button" class="lca-btn lca-btn-start" data-action="start">
                    Start Agent
                </button>
            </div>

            <!-- Live session view (hidden until session starts) -->
            <div class="lca-session" id="lca-session-{field_key}" style="display:none">
                <!-- Status bar -->
                <div class="lca-status-bar">
                    <span class="lca-status-indicator" id="lca-status-{field_key}"></span>
                    <span class="lca-status-text" id="lca-status-text-{field_key}">Connecting...</span>
                    <span class="lca-turn-counter" id="lca-counter-{field_key}">0 turns</span>
                    {controls_html}
                </div>

                {instruction_html}

                <!-- Thinking indicator -->
                <div class="lca-thinking" id="lca-thinking-{field_key}" style="display:none">
                    <span class="lca-thinking-dot"></span>
                    <span class="lca-thinking-text" id="lca-thinking-text-{field_key}">Thinking...</span>
                </div>

                <!-- Streaming turns (same structure as CodingTraceDisplay) -->
                <div class="lca-turns coding-trace-display" id="lca-turns-{field_key}">
                </div>
            </div>
        </div>
        '''

    def has_inline_label(self, field_config: Dict[str, Any]) -> bool:
        return False

    def get_css_classes(self, field_config: Dict[str, Any]) -> List[str]:
        classes = super().get_css_classes(field_config)
        return classes