Chat Component - Reference Guide

SkillMedia

PyWry is a cross-platform app factory, rendering engine and UI toolkit for Python that produces native desktop, web, and notebook experiences from a single API.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Chat Component - Reference Guide skill

What this skill tells your AI

The instructions your AI receives, as published by deeleeramone/pywry in pywry/pywry/mcp/skills/chat/SKILL.md and read by ahel’s review.

Read this before creating chat widgets.

Overview

The chat component provides a full-featured conversational UI with:

  • Message rendering with inline markdown
  • Streaming responses with token-by-token display
  • Stop-generation (cancel in-flight LLM responses)
  • Thread management (create, switch, delete)
  • Slash command palette (type / to see commands)
  • Settings panel (model, temperature, system prompt)
  • LLM provider adapters (OpenAI, Anthropic, custom callback)

Quick Start

Via MCP Tool

{
  "name": "create_chat_widget",
  "arguments": {
    "title": "AI Assistant",
    "model": "gpt-4",
    "system_prompt": "You are a helpful assistant.",
    "streaming": true,
    "provider": "openai"
  }
}

Via Python

from pywry import App
from pywry.chat import ChatConfig, ChatWidgetConfig

app = App()
config = ChatWidgetConfig(
    title="AI Chat",
    height=600,
    chat=ChatConfig(
        system_prompt="You are helpful.",
        model="gpt-4",
        streaming=True,
        provider="openai",
    ),
)
# Widget creation handled by MCP or directly via app.show()

MCP Tools

create_chat_widget

Creates a chat widget. Returns {widget_id, thread_id}.

ParameterTypeDefaultDescription
titlestring"Chat"Window title
heightinteger600Window height
system_promptstring""System prompt for LLM
modelstring"gpt-4"Model name
temperaturenumber0.7Sampling temperature (0-2)
max_tokensinteger4096Max tokens per response
streamingbooleantrueEnable streaming
persistbooleanfalsePersist threads in ChatStore
providerstring"openai", "anthropic", "callback"
show_sidebarbooleantrueShow thread sidebar
slash_commandsarrayCustom slash commands

chat_send_message

Send a user message. Returns {message_id, thread_id, sent}.

chat_stop_generation

Stop an in-flight generation. Idempotent. Returns partial content.

chat_manage_thread

Thread CRUD: create, switch, delete, rename, list.

chat_register_command

Register a slash command at runtime.

chat_get_history

Paginated conversation history with cursor (before_id).

chat_update_settings

Update model, temperature, system prompt, etc.

chat_set_typing

Show/hide the typing indicator.


Event Contract

Incoming Events (Python → Frontend)

EventPayload
chat:assistant-message{messageId, text, threadId}
chat:stream-chunk{chunk, messageId, threadId, done}
chat:typing-indicator{typing, threadId}
chat:switch-thread{threadId}
chat:update-thread-list{threads: [{thread_id, title}]}
chat:clear{}
chat:register-command{name, description}
chat:update-settings{model, temperature, system_prompt}
chat:state-response{messages, threads, settings, activeThreadId}
chat:generation-stopped{messageId, threadId, partialContent}

Outgoing Events (Frontend → Python)

EventPayload
chat:user-message{text, threadId, timestamp}
chat:slash-command{command, args, threadId}
chat:thread-create{title}
chat:thread-switch{threadId}
chat:thread-delete{threadId}
chat:settings-change{key, value}
chat:request-history{threadId, limit}
chat:stop-generation{threadId, messageId}
chat:request-state{}

Stop-Generation Mechanics

  1. User clicks Stop button → frontend immediately re-enables UI
  2. chat:stop-generation sent to backend
  3. Backend sets cancel_event on GenerationHandle
  4. LLM provider checks cancel_event.is_set() between chunks
  5. Provider raises GenerationCancelledError → partial content saved
  6. Backend emits chat:generation-stopped with partial content
  7. Frontend marks message as "(stopped)"

The UI never waits for backend confirmation — recovery is instant.


Default Slash Commands

CommandDescription
/clearClear conversation
/exportExport chat history
/modelSwitch model
/systemChange system prompt

Register custom commands via chat_register_command tool or ChatConfig.slash_commands list.


LLM Providers

OpenAI

{"provider": "openai"}

Requires openai package and OPENAI_API_KEY environment variable.

Anthropic

{"provider": "anthropic"}

Requires anthropic package and ANTHROPIC_API_KEY environment variable.

Custom Callback

from pywry.chat.providers.callback import CallbackProvider

provider = CallbackProvider(
    prompt_fn=my_prompt,   # (session_id, content_blocks, cancel_event) → AsyncIterator[SessionUpdate]
)

Safety Constants

ConstantValuePurpose
MAX_RENDERED_MESSAGES200DOM cap for performance
MAX_CONTENT_LENGTH100,000Per-message content limit
MAX_MESSAGES_PER_THREAD1,000Eviction threshold
STREAM_TIMEOUT_SECONDS30Max silence before timeout
SEND_COOLDOWN_MS1,000Input rate limit
GENERATION_HANDLE_TTL300Auto-expire stale handles

Signals

GitHub stars
93
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
chat
Source
github.com/deeleeramone/pywry