This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
openclaw/skills/gsd-openclaw/.planning/phases/02-integration-layer/02-02-PLAN.md
T

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
src/gsd_openclaw/response_formatter.py
tests/test_response_formatter.py
true
OCLW-04
truths artifacts key_links
Response formatter creates valid Feishu Card JSON 2.0 structure
Success cards have green theme
Error cards have red theme with guidance buttons
Long messages are paginated with [N/M] markers
Cards support interactive buttons with callback values
path provides exports
src/gsd_openclaw/response_formatter.py Feishu Card message formatting
FeishuResponseFormatter
CardTheme
CardButton
path provides exports
tests/test_response_formatter.py Tests for response formatting
TestFeishuResponseFormatter
from to via pattern
FeishuResponseFormatter Feishu API card JSON structure "schema": "2.0"
Create FeishuResponseFormatter class that formats responses as Feishu Card JSON 2.0 messages with three-zone structure (header/content/actions).

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.md

Three-zone layout:

  1. header: Title + status color (blue=info, green=success, red=error)
  2. elements: Main content area (div, markdown, note components)
  3. 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).

Task 1: Create test scaffold for FeishuResponseFormatter tests/test_response_formatter.py - Test 1: format_success returns valid card with green theme - Test 2: format_error returns valid card with red theme - Test 3: format_info returns valid card with blue theme - Test 4: Card with buttons includes action element - Test 5: format_paginated adds [N/M] marker - Test 6: Card has schema 2.0 and wide_screen_mode config Create tests/test_response_formatter.py with test class TestFeishuResponseFormatter:
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>

  1. FeishuResponseFormatter class exists in src/gsd_openclaw/response_formatter.py
  2. format_success, format_error, format_info, format_paginated methods work
  3. Card JSON has schema "2.0" with proper header/elements structure
  4. Buttons are rendered as action elements with callback values
  5. All 6 tests in tests/test_response_formatter.py pass </success_criteria>
After completion, create `.planning/phases/02-integration-layer/02-02-SUMMARY.md`