-- allium: 1
-- bDS Chat Panel
-- Scope: UI content area — AI chat surface
-- Distilled from: ChatPanel.tsx

-- Describes the layout and behaviour of the chat panel.

use "./i18n.allium" as i18n

-- ─── Chat panel ───────────────────────────────────────────────

value ChatPanelView {
    conversation_id: String?
    needs_api_key: Boolean
    title: String                       -- conversation title or "New Chat"
    selected_model_id: String?
    messages: List<ChatMessage>
    is_streaming: Boolean
    input_text: String
}

value ChatMessage {
    role: String                        -- user | assistant | system
    content: String                     -- user: plain text; assistant: GFM markdown
    tool_markers: List<ToolMarker>
    inline_surfaces: List<InlineSurface>
    is_streaming: Boolean               -- true while accumulating
}

value InlineSurface {
    id: String
    type: "card" | "chart" | "form" | "list" | "metric" | "mindmap" | "table" | "tabs" | "text" | "json"
    title: String?
    subtitle: String?                    -- card only
    body: String?                        -- card, text
    actions: List<SurfaceAction>         -- card only
    columns: List<String>                -- table
    rows: List<List<String>>             -- table
    chart_type: String?                  -- chart: bar/pie/line
    series: List<ChartSeries>            -- chart
    max_value: Integer?                  -- chart
    label: String?                       -- metric
    value: String?                       -- metric
    items: List<String>                  -- list
    nodes: List<MindmapNode>             -- mindmap
    fields: List<FormField>              -- form
    submit_label: String?                -- form
    submit_action: String?               -- form
    tabs: List<TabPanel>                 -- tabs
    selected_index: Integer?             -- tabs
    raw: Map?                            -- json catch-all
}

value SurfaceAction {
    label: String
    action: String
    payload: Map
}

value ChartSeries {
    label: String
    value: Integer
    segments: List
}

value MindmapNode {
    id: String?
    label: String
    children: List<String>
}

value FormField {
    key: String
    label: String
    input_type: String
    placeholder: String?
    value: String?
    options: List<FieldOption>
    required: Boolean
}

value FieldOption {
    label: String
    value: String
}

value TabPanel {
    label: String
    content: List<InlineSurface>        -- nested surfaces or text
}

value ToolMarker {
    tool_name: String
    args_preview: String                -- string args truncated to config.chat_tool_args_max_length
    is_complete: Boolean                -- checkmark when done, dot when in-progress
}

value ModelSelectorDropdown {
    groups: List<ModelProviderGroup>
    selected_model_id: String?
}

surface ModelSelectorDropdownSurface {
    context dropdown: ModelSelectorDropdown

    exposes:
        dropdown.selected_model_id when dropdown.selected_model_id != null
        for group in dropdown.groups:
            group.provider_name
            for model in group.models:
                model.model_id
                model.display_name
                model.context_window
                model.max_output_tokens
}

value ModelProviderGroup {
    provider_name: String               -- e.g. "OpenAI", "Ollama", "LM Studio"
    models: List<ModelEntry>
}

value ModelEntry {
    model_id: String
    display_name: String
    context_window: Integer
    max_output_tokens: Integer
}

config {
    chat_tool_args_max_length: Integer = 30
    chat_input_max_height: Integer = 200
    surface_form_debounce_ms: Integer = 500
}

surface ChatPanelSurface {
    context panel: ChatPanelView

    exposes:
        panel.needs_api_key
        panel.title
        panel.selected_model_id
        panel.is_streaming
        panel.input_text
        for msg in panel.messages:
            msg.role
            msg.content
            msg.is_streaming
            for tm in msg.tool_markers:
                tm.tool_name
                tm.args_preview
                tm.is_complete
            for sfc in msg.inline_surfaces:
                sfc.type
                sfc.id

    provides:
        ChatSendMessage(panel.conversation_id, panel.input_text)
            when panel.input_text != "" and not panel.is_streaming
        ChatAbortStreaming(panel.conversation_id)
            when panel.is_streaming
        ChatSelectModel(panel.conversation_id, model_id)
        ChatOpenSettings()
            when panel.needs_api_key

    @guarantee ApiKeyRequiredScreen
        -- Shown when needs_api_key is true.
        -- Key icon, title, description text, "Open Settings" button.
        -- No chat functionality available until API key is set.

    @guarantee HeaderLayout
        -- Left: conversation title (or "New Chat"), CSS ellipsis on overflow.
        -- Right: model selector button opening dropdown.

    @guarantee ModelSelectorDropdown
        -- Dropdown groups models by provider (section headers).
        -- Each entry: model display name.
        -- Expandable details: context window, max output tokens.
        -- Selection is per-conversation override, persisted with conversation.
        -- Changing model mid-conversation applies to subsequent messages only.

    @guarantee WelcomeScreen
        -- Shown when no messages and not streaming.
        -- Robot icon, title, description, 5 tip bullet points.

    @guarantee MessageRendering
        -- User messages: plain text.
        -- Assistant messages: rendered as GFM Markdown.
        --   External images blocked (CSP), shown as links.
        -- Tool markers: checkmark (done) or dot (in-progress) icon,
        --   tool name, args truncated to config.chat_tool_args_max_length for strings.
        -- Streaming: accumulating markdown + tool markers, thinking dots animation.

    @guarantee AutoScroll
        -- Message area auto-scrolls to bottom on new messages.

    @guarantee InputArea
        -- Abort/Stop button: square stop icon, visible only during streaming.
        -- Auto-growing textarea: max config.chat_input_max_height px.
        --   Enter sends message. Shift+Enter inserts newline.
        -- Send button: up-arrow icon, disabled when input is empty or streaming.

    @guarantee AssistantActionDispatch
        -- Assistant tool calls can trigger navigation actions:
        --   open_post(id), open_media(id), open_settings(), etc.
        -- Actions dispatched through store, same as user clicks.
        -- Navigation actions open tabs with pin intent.

    @guarantee InlineSurfaceRendering
        -- Assistant render-tool calls produce structured inline surfaces
        -- rendered between message content and tool markers.
        -- 9 surface types: card, chart, form, list, metric, mindmap, table, tabs, text, json.
        -- Render tool names: render_card, render_chart, render_form, render_list,
        --   render_metric, render_mindmap, render_table, render_tabs.
        -- Unrecognized render names render as json (raw dump).
        -- Tab content nests any surface type including plain text.
        -- Form surfaces persist field values in conversation surface_state.
        -- Tab surfaces track selected_index in conversation surface_state.
        -- Surfaces can be dismissed, persisted in conversation surface_state.
        -- Form debounce: config.surface_form_debounce_ms.

    @guarantee TokenTracking
        -- Token usage tracked per conversation.
        -- Displayed in status bar, not in the chat panel itself.
}
