Skip to content

pywry.chat_manager

High-level orchestration layer for the PyWry chat component.


Manager

pywry.chat_manager.ChatManager

ChatManager(handler: HandlerFunc, *, system_prompt: str = '', model: str = '', temperature: float = 0.7, welcome_message: str = '', settings: Sequence[SettingsItem] | None = None, slash_commands: Sequence[SlashCommandDef] | None = None, on_slash_command: Callable[..., Any] | None = None, on_settings_change: Callable[..., Any] | None = None, show_sidebar: bool = True, show_settings: bool = True, toolbar_width: str = '380px', toolbar_min_width: str = '280px', collapsible: bool = True, resizable: bool = True, include_plotly: bool = False, include_aggrid: bool = False, aggrid_theme: str = 'alpine', enable_context: bool = False, enable_file_attach: bool = False, file_accept_types: list[str] | None = None, context_allowed_roots: list[str] | None = None)

Zero-boilerplate orchestrator for the PyWry chat component.

Handles all event wiring, thread management, streaming, cancellation, and state synchronization. The developer provides a handler function and optional configuration.

Parameters:

Name Type Description Default
handler callable

Function that receives (messages, ctx) where messages is a list[dict] of conversation history and ctx is a ChatContext. Can return str, yield str chunks, or yield ChatResponse objects for rich content.

required
system_prompt str

System prompt prepended to every request.

''
model str

Model identifier (passed to handler via context).

''
temperature float

Temperature (passed to handler via context).

0.7
welcome_message str

Markdown message sent when the chat initializes.

''
settings list[SettingsItem]

Settings items rendered in the gear dropdown.

None
slash_commands list[SlashCommandDef]

Slash commands registered in the chat input.

None
on_slash_command callable

Callback (command, args, thread_id) for slash commands not handled by built-in behavior.

None
on_settings_change callable

Callback (key, value) when a setting changes.

None
show_sidebar bool

Show the conversation picker in the header.

True
show_settings bool

Show the gear icon in the header.

True
toolbar_width str

CSS width for the chat toolbar.

'380px'
toolbar_min_width str

CSS min-width for the chat toolbar.

'280px'
collapsible bool

Whether the chat toolbar is collapsible.

True
resizable bool

Whether the chat toolbar is resizable.

True
include_plotly bool

Include Plotly.js library eagerly on initialization.

False
include_aggrid bool

Include AG Grid library eagerly on initialization.

False
aggrid_theme str

AG Grid theme name (e.g. "alpine", "quartz", "balham").

'alpine'
enable_context bool

Enable the context attachment system (@ mentions for live widgets).

False
enable_file_attach bool

Enable the file attachment button (📎), drag-and-drop, and the hidden file input. Independent of enable_context. Both can be enabled simultaneously.

False
file_accept_types list[str] | None

Required when enable_file_attach=True. Specifies which file extensions are allowed, e.g. [".csv", ".json", ".xlsx"]. Each entry must be a dot-prefixed extension. Files that don't match are rejected on both the frontend and backend.

None
context_allowed_roots list[str] | None

Restrict file attachments to these directories. None means allow any readable path.

None

Examples:

Simplest usage — echo bot::

def echo(messages, ctx):
    return f"You said: {messages[-1]['text']}"


chat = ChatManager(handler=echo)

Streaming generator::

def stream_handler(messages, ctx):
    for word in call_my_api(messages):
        if ctx.cancel_event.is_set():
            return
        yield word


chat = ChatManager(handler=stream_handler)

Rich responses with tool calls::

def agent_handler(messages, ctx):
    yield StatusResponse(text="Searching...")
    results = search(messages[-1]["text"])
    yield ToolCallResponse(name="search", arguments={"q": messages[-1]["text"]})
    yield ToolResultResponse(tool_id="...", result=str(results))
    for chunk in summarize(results):
        yield chunk


chat = ChatManager(handler=agent_handler)

Attributes

CONTEXT_TOOL class-attribute

CONTEXT_TOOL: dict[str, Any] = {'type': 'function', 'function': {'name': 'get_context', 'description': 'Retrieve the full content of an attached file or widget. Call this when you need to read, analyze, or reference an attachment the user has provided.', 'parameters': {'type': 'object', 'properties': {'name': {'type': 'string', 'description': 'The attachment name (from the list of attached items).'}}, 'required': ['name']}}}

_handler instance-attribute

_handler = handler

_system_prompt instance-attribute

_system_prompt = system_prompt

_model instance-attribute

_model = model

_temperature instance-attribute

_temperature = temperature

_welcome_message instance-attribute

_welcome_message = welcome_message

_settings_items instance-attribute

_settings_items = list(settings) if settings else []

_slash_commands instance-attribute

_slash_commands = list(slash_commands) if slash_commands else []

_on_slash_command instance-attribute

_on_slash_command = on_slash_command

_on_settings_change instance-attribute

_on_settings_change = on_settings_change

_show_sidebar instance-attribute

_show_sidebar = show_sidebar

_show_settings instance-attribute

_show_settings = show_settings

_toolbar_width instance-attribute

_toolbar_width = toolbar_width

_toolbar_min_width instance-attribute

_toolbar_min_width = toolbar_min_width

_collapsible instance-attribute

_collapsible = collapsible

_resizable instance-attribute

_resizable = resizable

_include_plotly instance-attribute

_include_plotly = include_plotly

_include_aggrid instance-attribute

_include_aggrid = include_aggrid

_aggrid_theme instance-attribute

_aggrid_theme = aggrid_theme

_enable_context instance-attribute

_enable_context = enable_context

_enable_file_attach instance-attribute

_enable_file_attach = enable_file_attach

_file_accept_types instance-attribute

_file_accept_types = file_accept_types

_context_allowed_roots instance-attribute

_context_allowed_roots = [(str(resolve())) for r in context_allowed_roots] if context_allowed_roots else None

_widget instance-attribute

_widget: Any = None

_threads instance-attribute

_threads: dict[str, list[MessageDict]] = {}

_thread_titles instance-attribute

_thread_titles: dict[str, str] = {}

_cancel_events instance-attribute

_cancel_events: dict[str, Event] = {}

_settings_values instance-attribute

_settings_values: dict[str, Any] = {(id): (value) for s in (_settings_items) if type != 'separator'}

_todo_items instance-attribute

_todo_items: list[TodoItem] = []

_pending_inputs instance-attribute

_pending_inputs: dict[str, dict[str, Any]] = {}

_aggrid_assets_sent instance-attribute

_aggrid_assets_sent: bool = include_aggrid

_plotly_assets_sent instance-attribute

_plotly_assets_sent: bool = include_plotly

_context_sources instance-attribute

_context_sources: dict[str, dict[str, Any]] = {}

_active_thread instance-attribute

_active_thread: str = default_id

active_thread_id property

active_thread_id: str

The currently active thread ID.

settings property

settings: dict[str, Any]

Current settings values.

threads property

threads: dict[str, list[MessageDict]]

Thread history (read-only view).

_STREAM_FLUSH_INTERVAL class-attribute instance-attribute

_STREAM_FLUSH_INTERVAL: float = 0.03

_STREAM_MAX_BUFFER class-attribute instance-attribute

_STREAM_MAX_BUFFER: int = 300

Functions

register_context_source

register_context_source(component_id: str, name: str) -> None

Register a live dashboard component as an @-mentionable context source.

When the user types @ in the chat, registered sources appear in the autocomplete popup. When selected and sent, the frontend extracts live data from the component and includes it in the message.

Parameters:

Name Type Description Default
component_id str

The unique ID of the component (e.g. the grid_id passed to build_grid_config, the chart_id passed to build_plotly_init_script, a toolbar's component_id, etc.).

required
name str

Human-readable label shown in the popup (e.g. "Sales Data").

required

bind

bind(widget: Any) -> None

Bind to a widget after app.show().

toolbar

toolbar(*, position: Literal['header', 'footer', 'top', 'bottom', 'left', 'right', 'inside'] = 'right') -> Any

Build a Toolbar containing the chat panel.

Returns a Toolbar instance ready to pass to app.show(toolbars=...).

callbacks

callbacks() -> dict[str, Callable[..., Any]]

Return the callbacks dict to pass to app.show(callbacks=...).

This wires up ALL chat events automatically.

_emit

_emit(event: str, data: dict[str, Any]) -> None

Emit an event via the bound widget.

_emit_fire

_emit_fire(event: str, data: dict[str, Any]) -> None

Fire-and-forget emit — non-blocking, for high-frequency streaming.

_inject_aggrid_assets

_inject_aggrid_assets() -> None

Lazy-inject AG Grid JS/CSS on first table artifact.

_inject_plotly_assets

_inject_plotly_assets() -> None

Lazy-inject Plotly JS on first plotly artifact.

_is_accepted_file

_is_accepted_file(filename: str) -> bool

Check if the file extension is in the developer's allowed list.

_resolve_widget_attachment

_resolve_widget_attachment(widget_id: str, content: str | None = None, name: str | None = None) -> Attachment | None

Create an Attachment for a widget/component reference.

When content is provided (extracted by the frontend from the live component), it is used directly. Otherwise falls back to auto-discovered inline widgets.

_resolve_attachments

_resolve_attachments(raw_attachments: list[dict[str, Any]]) -> list[Attachment]

Resolve raw attachment dicts from the frontend into Attachments.

Desktop (Tauri): file attachments carry a path — a full filesystem path. The handler is responsible for reading file content.

Browser (inline / iframe): the File API cannot expose filesystem paths, so file attachments carry content instead (read by the frontend via FileReader).

Widget attachments always carry content extracted by the frontend from the live component.

_get_context_sources

_get_context_sources() -> list[dict[str, str]]

List available context sources for the @ mention popup.

_dispatch_artifact

_dispatch_artifact(item: _ArtifactBase, message_id: str, thread_id: str) -> None

Dispatch an artifact to the frontend with type-specific payloads.

For TableArtifact / PlotlyArtifact, assets are lazy-injected on first use and data is normalized before sending.

_on_user_message

_on_user_message(data: Any, _event_type: str, _label: str) -> None

Handle incoming user message — run handler in background thread.

_inject_context

_inject_context(messages: list[MessageDict], ctx: ChatContext, message_id: str, thread_id: str) -> list[MessageDict]

Inject attachment context into messages and emit tool-call events.

_dispatch_handler_result

_dispatch_handler_result(result: Any, message_id: str, thread_id: str, cancel: Event, ctx: ChatContext) -> None

Route handler return value to the appropriate processing path.

_run_handler

_run_handler(messages: list[MessageDict], ctx: ChatContext, message_id: str, thread_id: str, cancel: Event) -> None

Execute the handler in a background thread.

_handle_complete

_handle_complete(text: str, message_id: str, thread_id: str) -> None

Send a complete (non-streamed) assistant message.

_flush_buffer

_flush_buffer(state: _StreamState) -> None

Flush buffered text to the frontend.

_buffer_text

_buffer_text(state: _StreamState, text: str) -> None

Add text to the stream buffer and auto-flush if threshold reached.

_handle_input_required

_handle_input_required(item: InputRequiredResponse, state: _StreamState, thread_id: str, ctx: ChatContext | None) -> None

Handle an InputRequiredResponse during streaming.

_process_stream_item

_process_stream_item(item: Any, state: _StreamState, thread_id: str, ctx: ChatContext | None) -> None

Dispatch a single stream item to the appropriate handler.

_finalize_stream

_finalize_stream(state: _StreamState, thread_id: str) -> None

Flush remaining buffer and send stream-done events.

_handle_cancel

_handle_cancel(state: _StreamState, thread_id: str) -> None

Handle stream cancellation.

_handle_stream

_handle_stream(gen: Any, message_id: str, thread_id: str, cancel: Event, *, ctx: ChatContext | None = None) -> None

Stream chunks from a generator, handling rich response types.

_handle_async_stream async

_handle_async_stream(agen: Any, message_id: str, thread_id: str, cancel: Event, *, ctx: ChatContext | None = None) -> None

Stream chunks from an async generator, handling rich response types.

_on_stop_generation

_on_stop_generation(data: Any, _event_type: str, _label: str) -> None

Cancel active generation.

_on_todo_clear

_on_todo_clear(_data: Any, _event_type: str, _label: str) -> None

Handle user clearing the todo list.

_on_input_response

_on_input_response(data: Any, _event_type: str, _label: str) -> None

Handle user's response to an InputRequiredResponse.

_on_slash_command_event

_on_slash_command_event(data: Any, _event_type: str, _label: str) -> None

Handle slash command from frontend.

_on_thread_create

_on_thread_create(data: Any, _event_type: str, _label: str) -> None

Create a new thread.

_on_thread_switch

_on_thread_switch(data: Any, _event_type: str, _label: str) -> None

Switch to an existing thread.

_on_thread_delete

_on_thread_delete(data: Any, _event_type: str, _label: str) -> None

Delete a thread.

_on_thread_rename

_on_thread_rename(data: Any, _event_type: str, _label: str) -> None

Rename a thread.

_on_settings_change_event

_on_settings_change_event(data: Any, _event_type: str, _label: str) -> None

Handle settings change.

_on_request_state

_on_request_state(_data: Any, _event_type: str, _label: str) -> None

Respond to initialization request from frontend JS.

update_todos

update_todos(items: list[TodoItem]) -> None

Push a todo list update to the chat UI.

Call from handlers, slash commands, or any callback.

clear_todos

clear_todos() -> None

Clear the todo list.

send_message

send_message(text: str, thread_id: str | None = None) -> None

Send a programmatic assistant message to the chat.

Useful from slash-command handlers or other callbacks that want to inject a message directly (without going through the handler).

_build_thread_list

_build_thread_list() -> list[dict[str, str]]

Build thread list dicts for the frontend.

pywry.chat_manager.ChatContext dataclass

ChatContext(thread_id: str = '', message_id: str = '', settings: dict[str, Any] = dict(), cancel_event: Event = Event(), system_prompt: str = '', model: str = '', temperature: float = 0.7, attachments: list[Attachment] = list())

Context object passed to handler functions.

Attributes:

Name Type Description
thread_id str

Active thread ID.

message_id str

The assistant message ID being generated.

settings dict

Current settings values (from the settings dropdown).

cancel_event Event

Set when the user clicks Stop. Check this between chunks.

system_prompt str

System prompt configured for the chat.

model str

Model name configured for the chat.

temperature float

Temperature configured for the chat.

attachments list[Attachment]

Resolved context attachments for the current message.

Attributes

thread_id class-attribute instance-attribute

thread_id: str = ''

message_id class-attribute instance-attribute

message_id: str = ''

settings class-attribute instance-attribute

settings: dict[str, Any] = field(default_factory=dict)

cancel_event class-attribute instance-attribute

cancel_event: Event = field(default_factory=Event)

system_prompt class-attribute instance-attribute

system_prompt: str = ''

model class-attribute instance-attribute

model: str = ''

temperature class-attribute instance-attribute

temperature: float = 0.7

attachments class-attribute instance-attribute

attachments: list[Attachment] = field(default_factory=list)

attachment_summary property

attachment_summary: str

One-line summary of attached context for system/user prompts.

Returns an empty string when there are no attachments. Example output::

Attached context: report.csv (file: C:/data/report.csv), @Sales Data (widget)

Returns:

Type Description
str

Summary line suitable for prompt construction.

context_text property

context_text: str

Pre-formatted attachment content ready to inject into prompts.

For file attachments with a path (desktop/Tauri), includes only the path — the handler is responsible for reading file content. For file attachments with content (browser/inline), includes the content directly. For widget attachments, includes the extracted content.

Empty string when there are no attachments.

Returns:

Type Description
str

Multi-block attachment context ready to insert into prompts.

_input_event class-attribute instance-attribute

_input_event: Event = field(default_factory=Event, init=False, repr=False)

_input_response class-attribute instance-attribute

_input_response: str = field(default='', init=False, repr=False)

Functions

get_attachment

get_attachment(name: str) -> str

Retrieve attachment content or path by name.

For file attachments with a path (desktop/Tauri), returns the file path as a string — the handler should read the file itself. For file attachments with content (browser/inline), or widget attachments, returns the content directly.

Parameters:

Name Type Description Default
name str

Attachment name, with or without a leading @.

required

Returns:

Type Description
str

Attachment path or content, or a not-found message.

wait_for_input

wait_for_input(timeout: float | None = None) -> str

Block until the user provides input via InputRequiredResponse.

Call this after yielding InputRequiredResponse to pause the handler until the user responds. Returns the user's text. Returns empty string on cancellation or timeout.

Compatible with both the OpenAI API pattern (tool calls requiring user confirmation) and MCP A2A input_required task status.

Parameters:

Name Type Description Default
timeout float

Maximum seconds to wait. None means wait indefinitely (until user responds or generation is cancelled).

None

Returns:

Type Description
str

User-supplied input, or an empty string on cancellation or timeout.


Streaming Responses

pywry.chat_manager.TextChunkResponse

Bases: BaseModel

Explicit text chunk alternative to yielding bare strings.

Attributes:

Name Type Description
type Literal['text']

Response discriminator for text chunks.

text str

Incremental assistant text to append to the transcript.

Attributes

type class-attribute instance-attribute

type: Literal['text'] = 'text'

text class-attribute instance-attribute

text: str = ''

pywry.chat_manager.StatusResponse

Bases: BaseModel

Transient status message shown inline in the UI.

Attributes:

Name Type Description
type Literal['status']

Response discriminator for status updates.

text str

Human-readable status text.

Attributes

type class-attribute instance-attribute

type: Literal['status'] = 'status'

text class-attribute instance-attribute

text: str = ''

pywry.chat_manager.ThinkingResponse

Bases: BaseModel

Streaming thinking or reasoning chunk.

Rendered as a collapsible inline block in the UI. Thinking tokens are streamed in real-time and are NOT stored in conversation history. The block auto-collapses when the handler finishes.

Attributes:

Name Type Description
type Literal['thinking']

Response discriminator for thinking chunks.

text str

Incremental reasoning text to render.

Attributes

type class-attribute instance-attribute

type: Literal['thinking'] = 'thinking'

text class-attribute instance-attribute

text: str = ''

pywry.chat_manager.CitationResponse

Bases: BaseModel

Citation or source reference attached to a response.

Attributes:

Name Type Description
type Literal['citation']

Response discriminator for citation UI events.

url str

Citation URL shown to the user.

title str

Human-readable citation title.

snippet str

Supporting excerpt associated with the citation.

Attributes

type class-attribute instance-attribute

type: Literal['citation'] = 'citation'

url class-attribute instance-attribute

url: str = ''

title class-attribute instance-attribute

title: str = ''

snippet class-attribute instance-attribute

snippet: str = ''

Functions

_block_dangerous_schemes classmethod

_block_dangerous_schemes(v: str) -> str

Reject unsafe citation URL schemes.

Parameters:

Name Type Description Default
v str

Candidate citation URL.

required

Returns:

Type Description
str

The original URL when it is safe to render.

Raises:

Type Description
ValueError

Raised when the URL uses the javascript: scheme.

pywry.chat_manager.ToolCallResponse

Bases: BaseModel

Handler requests a tool invocation to be shown in the UI.

Attributes:

Name Type Description
type Literal['tool_call']

Response discriminator for tool-call UI events.

tool_id str

Stable identifier used to correlate a later tool result.

name str

Tool name displayed to the user and routed by the handler.

arguments dict[str, Any]

Structured tool arguments associated with the invocation.

Attributes

type class-attribute instance-attribute

type: Literal['tool_call'] = 'tool_call'

tool_id class-attribute instance-attribute

tool_id: str = Field(default_factory=lambda: f'call_{hex[:8]}')

name instance-attribute

name: str

arguments class-attribute instance-attribute

arguments: dict[str, Any] = Field(default_factory=dict)

pywry.chat_manager.ToolResultResponse

Bases: BaseModel

Result of a tool invocation shown in the UI.

Attributes:

Name Type Description
type Literal['tool_result']

Response discriminator for tool-result UI events.

tool_id str

Identifier of the tool call this result satisfies.

result str

Human-readable tool output rendered in the transcript.

is_error bool

Indicates the tool invocation failed.

Attributes

type class-attribute instance-attribute

type: Literal['tool_result'] = 'tool_result'

tool_id instance-attribute

tool_id: str

result class-attribute instance-attribute

result: str = ''

is_error class-attribute instance-attribute

is_error: bool = False

Artifacts

pywry.chat_manager.CodeArtifact

Bases: _ArtifactBase

Code snippet artifact rendered with syntax highlighting.

Attributes:

Name Type Description
artifact_type Literal['code']

Artifact subtype discriminator.

content str

Source code or text snippet to render.

language str

Optional language hint for syntax highlighting.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['code'] = 'code'

content class-attribute instance-attribute

content: str = ''

language class-attribute instance-attribute

language: str = ''

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

pywry.chat_manager.MarkdownArtifact

Bases: _ArtifactBase

Markdown artifact rendered as formatted HTML.

Attributes:

Name Type Description
artifact_type Literal['markdown']

Artifact subtype discriminator.

content str

Markdown source to render.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['markdown'] = 'markdown'

content class-attribute instance-attribute

content: str = ''

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

pywry.chat_manager.HtmlArtifact

Bases: _ArtifactBase

Raw HTML artifact rendered in a sandboxed container.

Attributes:

Name Type Description
artifact_type Literal['html']

Artifact subtype discriminator.

content str

Raw HTML content to render.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['html'] = 'html'

content class-attribute instance-attribute

content: str = ''

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

pywry.chat_manager.TableArtifact

Bases: _ArtifactBase

Tabular data rendered as an AG Grid widget.

Accepts the same data formats as normalize_data() in grid.py: pandas DataFrame, list of dicts, dict of lists, or single dict.

Attributes:

Name Type Description
artifact_type Literal['table']

Artifact subtype discriminator.

data list[dict[str, Any]] | dict[str, Any]

Table rows or source object to normalize into rows.

column_defs list[dict[str, Any]] | None

Optional AG Grid column definitions.

grid_options dict[str, Any] | None

Optional AG Grid configuration overrides.

height str

CSS height used by the table container.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['table'] = 'table'

data class-attribute instance-attribute

data: list[dict[str, Any]] | dict[str, Any] = Field(default_factory=list)

column_defs class-attribute instance-attribute

column_defs: list[dict[str, Any]] | None = None

grid_options class-attribute instance-attribute

grid_options: dict[str, Any] | None = None

height class-attribute instance-attribute

height: str = '400px'

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

pywry.chat_manager.PlotlyArtifact

Bases: _ArtifactBase

Plotly chart artifact rendered as an interactive widget.

figure accepts a standard Plotly figure dict: {"data": [...traces], "layout": {...}, "config": {...}}.

Attributes:

Name Type Description
artifact_type Literal['plotly']

Artifact subtype discriminator.

figure dict[str, Any]

Plotly figure payload passed to the frontend renderer.

height str

CSS height used by the chart container.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['plotly'] = 'plotly'

figure class-attribute instance-attribute

figure: dict[str, Any] = Field(default_factory=dict)

height class-attribute instance-attribute

height: str = '400px'

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

pywry.chat_manager.ImageArtifact

Bases: _ArtifactBase

Image artifact rendered as an <img> element.

url can be a data URI (data:image/png;base64,...) or an HTTP(S) URL.

Attributes:

Name Type Description
artifact_type Literal['image']

Artifact subtype discriminator.

url str

Image URL or data URI.

alt str

Alternate text for the rendered image.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['image'] = 'image'

url class-attribute instance-attribute

url: str = ''

alt class-attribute instance-attribute

alt: str = ''

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

Functions

_block_dangerous_schemes classmethod

_block_dangerous_schemes(v: str) -> str

Reject unsafe image URL schemes.

Parameters:

Name Type Description Default
v str

Candidate image URL.

required

Returns:

Type Description
str

The original URL when it is safe to render.

Raises:

Type Description
ValueError

Raised when the URL uses the javascript: scheme.

pywry.chat_manager.JsonArtifact

Bases: _ArtifactBase

Structured data rendered as a collapsible JSON tree.

Attributes:

Name Type Description
artifact_type Literal['json']

Artifact subtype discriminator.

data Any

Arbitrary JSON-serializable payload to display.

Attributes

artifact_type class-attribute instance-attribute

artifact_type: Literal['json'] = 'json'

data class-attribute instance-attribute

data: Any = None

type class-attribute instance-attribute

type: Literal['artifact'] = 'artifact'

title class-attribute instance-attribute

title: str = ''

UI State Models

pywry.chat_manager.SettingsItem

Bases: BaseModel

Settings menu item shown in the gear dropdown.

Attributes:

Name Type Description
id str

Stable identifier for the setting.

label str

User-visible label.

type Literal['action', 'toggle', 'select', 'range', 'separator']

Control type rendered in the settings menu.

value Any

Current value or payload associated with the setting.

options list[str] | None

Allowed values for select controls.

min float | None

Minimum value for range controls.

max float | None

Maximum value for range controls.

step float | None

Increment for range controls.

Attributes

id instance-attribute

id: str

label class-attribute instance-attribute

label: str = ''

type class-attribute instance-attribute

type: Literal['action', 'toggle', 'select', 'range', 'separator'] = 'action'

value class-attribute instance-attribute

value: Any = None

options class-attribute instance-attribute

options: list[str] | None = None

min class-attribute instance-attribute

min: float | None = None

max class-attribute instance-attribute

max: float | None = None

step class-attribute instance-attribute

step: float | None = None

pywry.chat_manager.SlashCommandDef

SlashCommandDef(**data: Any)

Bases: BaseModel

A slash command registration.

Attributes

name instance-attribute

name: str

description class-attribute instance-attribute

description: str = ''

Functions

pywry.chat_manager.TodoItem

Bases: BaseModel

Single todo item in the agent's task list.

Rendered as a collapsible list above the chat input bar. The agent manages items; the user can clear the list.

Attributes:

Name Type Description
id int | str

Stable todo-item identifier.

title str

User-visible todo label.

status Literal['not-started', 'in-progress', 'completed']

Current progress state for the item.

Attributes

id instance-attribute

id: int | str

title instance-attribute

title: str

status class-attribute instance-attribute

status: Literal['not-started', 'in-progress', 'completed'] = 'not-started'

pywry.chat_manager.TodoUpdateResponse

Bases: BaseModel

Push the full todo list to the UI.

Yielded from a handler to update the todo list above the input bar. The list is NOT stored in conversation history.

Attributes:

Name Type Description
type Literal['todo']

Response discriminator for todo-list updates.

items list[TodoItem]

Full replacement set of todo items to display.

Attributes

type class-attribute instance-attribute

type: Literal['todo'] = 'todo'

items class-attribute instance-attribute

items: list[TodoItem] = Field(default_factory=list)

pywry.chat_manager.InputRequiredResponse

Bases: BaseModel

Pause generation to request user input mid-stream.

When yielded from a handler, the current streaming batch is finalized and the chat input is re-enabled so the user can respond. The handler then calls ctx.wait_for_input() to block until the response arrives.

Compatible with:

  • OpenAI API: maps to the pattern where the assistant asks a clarifying question and the conversation continues with the user's reply.
  • MCP A2A: maps to Task status input_required — the agent pauses execution until the client supplies additional input.

Example::

def handler(messages, ctx):
    yield "Which file should I modify?"
    yield InputRequiredResponse(placeholder="Enter filename...")
    filename = ctx.wait_for_input()
    if not filename:
        return  # Cancelled
    yield f"Modifying **{filename}**..."

Attributes:

Name Type Description
type Literal['input_required']

Response discriminator for interactive pauses.

prompt str

Optional prompt shown above the resumed input control.

placeholder str

Placeholder text for the temporary input control.

request_id str

Stable identifier for correlating the user response.

input_type Literal['text', 'buttons', 'radio']

Input control variant to render.

options list[str] | None

Choices for button or radio-style prompts.

Attributes

type class-attribute instance-attribute

type: Literal['input_required'] = 'input_required'

prompt class-attribute instance-attribute

prompt: str = ''

placeholder class-attribute instance-attribute

placeholder: str = 'Type your response...'

request_id class-attribute instance-attribute

request_id: str = Field(default_factory=lambda: f'input_{hex[:8]}')

input_type class-attribute instance-attribute

input_type: Literal['text', 'buttons', 'radio'] = 'text'

options class-attribute instance-attribute

options: list[str] | None = None