///|
/// ModelPort: the LLM calling interface. Every ext-deepseek / ext-openai /
/// ext-anthropic implements this. `chat` is the primary call; `chat_streaming`
/// has a default that ignores on_chunk and falls back to chat().
pub(open) trait ModelPort {
async fn chat(
Self,
messages : Array[Message],
tools : Array[ToolDef],
options : ChatOptions,
) -> ModelResponse raise ModelError
/// Streaming chat. Default: ignores on_chunk, falls back to chat().
async fn chat_streaming(
Self,
messages : Array[Message],
tools : Array[ToolDef],
options : ChatOptions,
on_chunk : (StreamChunk) -> Unit,
) -> ModelResponse raise ModelError = _
}