10 KiB
10 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-integration-layer | 02 | execute | 1 |
|
true |
|
|
Purpose: Provide channel-adaptive response formatting for Feishu. The formatter converts GSD output into structured Feishu Card messages with proper theming, pagination, and interactive elements.
Output:
- src/gsd_openclaw/response_formatter.py - Response formatter implementation
- tests/test_response_formatter.py - Formatter tests
<execution_context> @/home/starmen1265/.claude/get-shit-done/workflows/execute-plan.md @/home/starmen1265/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-integration-layer/02-CONTEXT.md @.planning/phases/02-integration-layer/02-RESEARCH.mdThree-zone layout:
- header: Title + status color (blue=info, green=success, red=error)
- elements: Main content area (div, markdown, note components)
- actions: Interactive buttons (at card bottom)
Card JSON structure:
{
"schema": "2.0",
"config": {"wide_screen_mode": true},
"header": {
"title": {"tag": "plain_text", "content": "..."},
"template": "green"
},
"elements": [
{"tag": "div", "text": {"tag": "lark_md", "content": "..."}}
]
}
Button structure:
{
"tag": "action",
"actions": [
{
"tag": "button",
"text": {"tag": "plain_text", "content": "Confirm"},
"type": "primary",
"value": {"action": "approve", "project": "my-auth"}
}
]
}
Use lark_md tag for markdown content (Feishu's built-in markdown support).
1. test_format_success_returns_valid_card():
- Create FeishuResponseFormatter()
- Call format_success("Test Title", "Test content")
- Assert card["schema"] == "2.0"
- Assert card["header"]["template"] == "green"
- Assert card["header"]["title"]["content"] == "Test Title"
2. test_format_error_returns_red_theme():
- Call format_error("Error", "Something went wrong")
- Assert card["header"]["template"] == "red"
3. test_format_info_returns_blue_theme():
- Call format_info("Info", "Status update")
- Assert card["header"]["template"] == "blue"
4. test_format_with_buttons_includes_actions():
- Create CardButton("OK", {"action": "ok"})
- Call format_success("Test", "Content", buttons=[button])
- Assert elements contains action with tag="action"
- Assert button text is "OK"
5. test_format_paginated_adds_marker():
- Call format_paginated("Title", "Content", page=1, total_pages=3)
- Assert "[1/3]" appears in content
6. test_card_has_required_structure():
- Call format_success("Test", "Content")
- Assert "config" key exists
- Assert config["wide_screen_mode"] == True
- Assert elements[0]["tag"] == "div"
Import from gsd_openclaw.response_formatter: FeishuResponseFormatter, CardTheme, CardButton
Follow test pattern from tests/test_state_manager.py.
pytest tests/test_response_formatter.py -v
- tests/test_response_formatter.py exists with 6 tests
- All tests fail initially (no implementation yet)
Task 2: Implement CardTheme enum and CardButton dataclass
src/gsd_openclaw/response_formatter.py
- Test: CardButton can be created with text, value, button_type
- Test: CardTheme enum has SUCCESS, ERROR, INFO, WARNING values
Create src/gsd_openclaw/response_formatter.py with:
1. Imports:
- from dataclasses import dataclass
- from typing import Dict, Any, List, Optional
- from enum import Enum
2. CardTheme(Enum):
- SUCCESS = "green"
- ERROR = "red"
- INFO = "blue"
- WARNING = "orange"
3. @dataclass CardButton:
- text: str
- value: Dict[str, Any]
- button_type: str = "primary" # primary, default, danger
Keep implementation minimal - just these data structures.
Tests should now pass for CardTheme and CardButton.
pytest tests/test_response_formatter.py::TestFeishuResponseFormatter::test_format_success_returns_valid_card -v 2>&1 | head -20 || echo "Expected: tests still fail (formatter not implemented)"
- CardTheme enum exists with SUCCESS, ERROR, INFO, WARNING
- CardButton dataclass exists with text, value, button_type
Task 3: Implement FeishuResponseFormatter class
src/gsd_openclaw/response_formatter.py
- Test: All 6 tests in test_response_formatter.py pass
Add FeishuResponseFormatter class to response_formatter.py:
class FeishuResponseFormatter:
"""Format responses as Feishu Card messages."""
def format_success(self, title: str, content: str,
buttons: Optional[List[CardButton]] = None) -> dict:
"""Format a success response card with green theme."""
return self._build_card(title, content, CardTheme.SUCCESS, buttons)
def format_error(self, title: str, content: str,
buttons: Optional[List[CardButton]] = None) -> dict:
"""Format an error response card with red theme."""
return self._build_card(title, content, CardTheme.ERROR, buttons)
def format_info(self, title: str, content: str,
buttons: Optional[List[CardButton]] = None) -> dict:
"""Format an info response card with blue theme."""
return self._build_card(title, content, CardTheme.INFO, buttons)
def format_paginated(self, title: str, content: str,
page: int, total_pages: int) -> dict:
"""Format a paginated response with [page/total] marker."""
footer = f"\n\n---\n[{page}/{total_pages}]"
return self._build_card(title, content + footer, CardTheme.INFO)
def _build_card(self, title: str, content: str, theme: CardTheme,
buttons: Optional[List[CardButton]] = None) -> dict:
"""Build complete card JSON structure."""
card = {
"schema": "2.0",
"config": {"wide_screen_mode": True},
"header": {
"title": {"tag": "plain_text", "content": title},
"template": theme.value
},
"elements": [
{"tag": "div", "text": {"tag": "lark_md", "content": content}}
]
}
if buttons:
card["elements"].append(self._build_actions(buttons))
return card
def _build_actions(self, buttons: List[CardButton]) -> dict:
"""Build actions element from button list."""
return {
"tag": "action",
"actions": [
{
"tag": "button",
"text": {"tag": "plain_text", "content": btn.text},
"type": btn.button_type,
"value": btn.value
}
for btn in buttons
]
}
User decision (LOCKED):
- Three-zone structure: header + elements + actions
- Error cards use red theme
- Success cards use green theme
- Pagination uses [N/M] format
- Interactive buttons support callback values
All 6 tests should now pass.
pytest tests/test_response_formatter.py -v
- FeishuResponseFormatter class implements all format methods
- All 6 tests pass
- Card JSON uses schema 2.0 with three-zone structure
- Run pytest tests/test_response_formatter.py -v (all tests pass)
- Verify card structure matches Feishu Card JSON 2.0 specification
- Verify theme colors are correct (green=success, red=error, blue=info)
<success_criteria>
- FeishuResponseFormatter class exists in src/gsd_openclaw/response_formatter.py
- format_success, format_error, format_info, format_paginated methods work
- Card JSON has schema "2.0" with proper header/elements structure
- Buttons are rendered as action elements with callback values
- All 6 tests in tests/test_response_formatter.py pass </success_criteria>