Ver Fonte

feat: refine prompt list message types

zhenyu.hu há 3 semanas atrás
pai
commit
b467a1af89

+ 23 - 0
docs/plans/todo-25-prompt-list-message-types.md

@@ -0,0 +1,23 @@
+# Todo 25: Prompt List Message Types
+
+## Status
+
+done
+
+## Goal
+
+The ChatAgent prompt list should be easier to scan and each item should clearly show its message type. For this iteration, prompt list items remain ChatAgent `system` messages; the UI must make that explicit instead of only showing "Custom Prompt".
+
+## Scope
+
+- Add a visible `type: system` marker to each ChatAgent prompt item.
+- Keep the generated EventAgent event-rules prompt in the same ordered list.
+- Make the item header, action buttons, and text area more compact inside the modal.
+- Preserve existing prompt save/load, add/delete, and drag ordering behavior.
+
+## Verification
+
+- Static tests assert that prompt items expose message type markup and compact styling hooks.
+- `uv run pytest` passes: 51 tests.
+- Local HTTP check returned `/health` and `/static/app.js?v=20260706-prompt-types`.
+- Browser automation was attempted but the in-app browser connection timed out, and direct Playwright did not have a browser binary installed in this environment.

+ 1 - 0
docs/plans/todos.md

@@ -51,3 +51,4 @@
 | 22 | done | `docs/plans/todo-22-text-event-protocol.md` | Replace ChatAgent tool calls with streamed text event parsing, inject generated event descriptions as a system message, and harden Agent config buttons. | `uv run pytest` passes (`50 passed`, one existing Starlette deprecation warning), plus local browser click check. |
 | 23 | done | `docs/plans/todo-23-agent-prompt-and-event-llm.md` | Move Prompt Config into ChatAgent config, show available-event prompt by default, and make EventAgent use LLM tool calls to generate tool arguments. | `uv run pytest` passes (`51 passed`, one existing Starlette deprecation warning); changed Python modules compile; local server returned page/static assets/tools API. |
 | 24 | done | `docs/plans/todo-24-chat-agent-prompt-list.md` | Put all ChatAgent prompts, including generated EventAgent event rules, into one ordered prompt list with add/delete/drag controls. | `uv run pytest` passes (`51 passed`, one existing Starlette deprecation warning), plus local browser prompt-list check. |
+| 25 | done | `docs/plans/todo-25-prompt-list-message-types.md` | Make the ChatAgent prompt list visually compact and show the message type for each prompt item. | `uv run pytest` passes (`51 passed`, one existing Starlette deprecation warning); local service returned `/health` and versioned JS asset. |

+ 18 - 5
src/agent_lab/presentation/static/app.js

@@ -307,15 +307,25 @@ function createSystemPrompt(prompt) {
     ? "prompt-item event-prompt"
     : "prompt-item";
   item.dataset.promptKind = promptItem.prompt_kind;
+  item.dataset.promptRole = promptItem.role;
   item.draggable = true;
 
   const head = document.createElement("div");
   head.className = "prompt-item-head";
 
+  const meta = document.createElement("div");
+  meta.className = "prompt-meta";
+
+  const type = document.createElement("span");
+  type.className = "prompt-type";
+  type.textContent = `type: ${promptItem.role}`;
+
   const title = document.createElement("span");
+  title.className = "prompt-title";
   title.textContent = promptItem.prompt_kind === "event_agent_system"
-    ? "EventAgent System Prompt"
-    : "Custom Prompt";
+    ? "EventAgent Rules"
+    : "Custom";
+  meta.append(type, title);
 
   const actions = document.createElement("div");
   actions.className = "prompt-actions";
@@ -342,11 +352,11 @@ function createSystemPrompt(prompt) {
     actions.append(deleteButton);
   }
 
-  head.append(title, actions);
+  head.append(meta, actions);
 
   const textarea = document.createElement("textarea");
   textarea.className = "system-prompt";
-  textarea.rows = promptItem.prompt_kind === "event_agent_system" ? 7 : 4;
+  textarea.rows = promptItem.prompt_kind === "event_agent_system" ? 7 : 3;
   textarea.value = promptItem.content;
   textarea.readOnly = promptItem.prompt_kind === "event_agent_system";
 
@@ -389,6 +399,7 @@ function buildPromptItems() {
   return [...systemPrompts.querySelectorAll(".prompt-item")]
     .map((item) => ({
       prompt_kind: item.dataset.promptKind || "custom",
+      role: item.dataset.promptRole || "system",
       content: item.querySelector(".system-prompt").value.trim(),
     }))
     .filter((item) => item.prompt_kind === "event_agent_system" || item.content);
@@ -413,7 +424,7 @@ function normalizePromptItems(prompts) {
     normalized.push({ prompt_kind: "event_agent_system", content: "" });
   }
   if (!normalized.some((prompt) => prompt.prompt_kind === "custom")) {
-    normalized.unshift({ prompt_kind: "custom", content: "" });
+    normalized.unshift({ prompt_kind: "custom", role: "system", content: "" });
   }
   return normalized;
 }
@@ -424,11 +435,13 @@ function normalizePromptItem(prompt) {
       prompt_kind: prompt.prompt_kind === "event_agent_system"
         ? "event_agent_system"
         : "custom",
+      role: "system",
       content: prompt.content || "",
     };
   }
   return {
     prompt_kind: "custom",
+    role: "system",
     content: prompt || "",
   };
 }

+ 12 - 6
src/agent_lab/presentation/static/index.html

@@ -90,20 +90,26 @@
             <button id="add-system-prompt" type="button">Add</button>
           </div>
           <div id="system-prompts" class="prompt-list stack">
-            <div class="prompt-item" draggable="true" data-prompt-kind="custom">
+            <div class="prompt-item" draggable="true" data-prompt-kind="custom" data-prompt-role="system">
               <div class="prompt-item-head">
-                <span>Custom Prompt</span>
+                <div class="prompt-meta">
+                  <span class="prompt-type">type: system</span>
+                  <span class="prompt-title">Custom</span>
+                </div>
                 <div class="prompt-actions">
                   <button class="move-prompt-up" type="button">Up</button>
                   <button class="move-prompt-down" type="button">Down</button>
                   <button class="delete-system-prompt" type="button">Delete</button>
                 </div>
               </div>
-              <textarea class="system-prompt" rows="4">You are a debugging assistant.</textarea>
+              <textarea class="system-prompt" rows="3">You are a debugging assistant.</textarea>
             </div>
-            <div class="prompt-item event-prompt" draggable="true" data-prompt-kind="event_agent_system">
+            <div class="prompt-item event-prompt" draggable="true" data-prompt-kind="event_agent_system" data-prompt-role="system">
               <div class="prompt-item-head">
-                <span>EventAgent System Prompt</span>
+                <div class="prompt-meta">
+                  <span class="prompt-type">type: system</span>
+                  <span class="prompt-title">EventAgent Rules</span>
+                </div>
                 <div class="prompt-actions">
                   <button class="move-prompt-up" type="button">Up</button>
                   <button class="move-prompt-down" type="button">Down</button>
@@ -157,6 +163,6 @@
       </div>
     </template>
 
-    <script src="/static/app.js?v=20260706-prompt-list"></script>
+    <script src="/static/app.js?v=20260706-prompt-types"></script>
   </body>
 </html>

+ 43 - 6
src/agent_lab/presentation/static/styles.css

@@ -178,10 +178,11 @@ textarea {
 }
 
 .prompt-item {
+  background: #fbfcfd;
   border: 1px solid #d7dee5;
   border-radius: 6px;
   cursor: grab;
-  padding: 10px;
+  padding: 8px;
 }
 
 .prompt-item.dragging {
@@ -191,25 +192,61 @@ textarea {
 .prompt-item-head {
   align-items: center;
   display: flex;
-  gap: 10px;
+  gap: 8px;
   justify-content: space-between;
-  margin-bottom: 8px;
+  margin-bottom: 6px;
 }
 
-.prompt-item-head span {
+.prompt-meta {
+  align-items: center;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+  min-width: 0;
+}
+
+.prompt-title {
   color: #52616f;
   font-size: 12px;
   font-weight: 600;
 }
 
+.prompt-type {
+  background: #e0f2f1;
+  border: 1px solid #b2dfdb;
+  border-radius: 999px;
+  color: #0f766e;
+  font-size: 11px;
+  font-weight: 700;
+  line-height: 1;
+  padding: 3px 7px;
+  text-transform: lowercase;
+}
+
 .prompt-actions {
   display: flex;
   flex-wrap: wrap;
-  gap: 6px;
+  gap: 4px;
+  justify-content: flex-end;
 }
 
 .prompt-actions button {
-  padding: 5px 8px;
+  background: #eef2f5;
+  border: 1px solid #cbd5df;
+  color: #1f2933;
+  font-size: 12px;
+  line-height: 1.1;
+  padding: 4px 7px;
+}
+
+.prompt-actions button:hover {
+  background: #e4e9ee;
+}
+
+.prompt-item textarea {
+  font-size: 13px;
+  line-height: 1.45;
+  padding: 7px;
 }
 
 .event-prompt textarea {

+ 7 - 0
tests/test_websocket_api.py

@@ -484,18 +484,25 @@ def test_static_chat_agent_prompt_is_a_single_sortable_list_with_event_instructi
     assert 'id="chat-event-prompt-preview"' not in html
     assert 'class="prompt-list stack"' in html
     assert 'class="prompt-item"' in html
+    assert 'data-prompt-role="system"' in html
+    assert "prompt-type" in html
     assert "function buildAvailableEventsPrompt(" in js
     assert "Available events:" in js
     assert "function updateEventPromptItem(" in js
     assert "function createSystemPrompt(" in js
     assert "function movePromptItem(" in js
     assert 'draggable = true' in js
+    assert "dataset.promptRole" in js
+    assert "prompt-title" in js
     assert "delete-system-prompt" in js
     assert 'prompt_kind: "event_agent_system"' in js
     assert "system_prompts: collectSystemPrompts()" in js
     assert 'system_prompt: ""' in js
     assert ".prompt-item" in css
     assert ".prompt-item.dragging" in css
+    assert ".prompt-meta" in css
+    assert ".prompt-type" in css
+    assert ".prompt-actions button" in css
     assert "#open-prompt-config" not in js
     assert "promptDialog" not in js