Client
AutoLLMClient, its methods, and the helpers exported next to it.
AutoLLMClient is the one class you call. It creates the client its client_type names and forwards to it.
Create a client
import { AutoLLMClient } from "@prismshadow/mmsp";
// the official OpenAI client, named by the model id's family
const client = new AutoLLMClient({ model: "gpt-5.5" });
// the same, spelled out, with the key and the endpoint given in code
const withEndpoint = new AutoLLMClient({
model: "gpt-5.5",
clientType: "openai-official",
apiKey: "your-openai-api-key",
baseUrl: "https://api.openai.com/v1",
});
// a compatible client, for any endpoint that serves OpenAI Chat Completions
const withType = new AutoLLMClient({
model: "custom-model",
clientType: "openai-chat",
baseUrl: "http://127.0.0.1:8000/v1/",
apiKey: "none",
});
from mmsp import AutoLLMClient
# the official OpenAI client, named by the model id's family
client = AutoLLMClient(model="gpt-5.5")
# the same, spelled out, with the key and the endpoint given in code
client = AutoLLMClient(
model="gpt-5.5",
client_type="openai-official",
api_key="your-openai-api-key",
base_url="https://api.openai.com/v1",
)
# a compatible client, for any endpoint that serves OpenAI Chat Completions
client = AutoLLMClient(
model="custom-model",
client_type="openai-chat",
base_url="http://127.0.0.1:8000/v1/",
api_key="none",
)
| Option | Python | TypeScript | Meaning |
|---|---|---|---|
| Model | model |
model |
The exact model id. |
| Client | client_type |
clientType |
An official client such as openai-official, or a compatible one such as openai-chat. May be omitted for a model id that begins with a known family, which names its official client; any other id raises. See Models and endpoints. |
| Key | api_key |
apiKey |
Defaults to the client's <P>_API_KEY, for the endpoint the environment names or the client's default endpoint only. |
| Endpoint | base_url |
baseUrl |
Defaults to the client's <P>_BASE_URL, then to its default endpoint. |
| Headers | default_headers |
defaultHeaders |
Sent with every request, for endpoints that demand their own. |
A key goes only where it was given for. Every client follows one rule, <P> being its variable prefix (DEEPSEEK for deepseek-official, OPENAI for openai-chat; see Models and endpoints):
- A key passed in is used. The endpoint is the base URL passed in, else
<P>_BASE_URL, else the client's default endpoint. - Without a key, the client reads
<P>_API_KEYonly when no base URL is passed, the endpoint then being<P>_BASE_URLor the default, or when the base URL passed is the client's own default endpoint, trailing slashes and the host's case aside. Adeepseek-officialclient given no base URL, orhttps://api.deepseek.com, usesDEEPSEEK_API_KEY. - Without a key, any other base URL raises
ApiKeyRequiredErrorat construction, and the environment's key is never sent there. Pass the key, or drop the base URL and set<P>_API_KEY, plus<P>_BASE_URLwhen the endpoint is not the default. - The rest of OpenAI's environment (
OPENAI_ORG_ID,OPENAI_PROJECT_ID,OPENAI_ADMIN_KEY,OPENAI_WEBHOOK_SECRET, the headersOPENAI_CUSTOM_HEADERSlists) followsOPENAI_API_KEY: a client built on the OpenAI SDK sends it only to the endpoint that key goes to, never to a gateway, a vLLM server or another vendor's API. - The clients of a server that may take no key are the exception: for
mmspandopenai-chat-vllm-adapter, a base URL without a key is an open server, called with no key, and so is the default endpoint when<P>_API_KEYis unset (http://127.0.0.1:25752/v1formmsp;http://127.0.0.1:8000/v1, wherevllm serveanswers, for the vLLM adapter, which sends vLLM's placeholder keyEMPTY).
The same rule ships as data: @prismshadow/mmsp/credentials in TypeScript, which imports nothing and fits a browser bundle, and mmsp.credentials in Python. environmentCredential(clientType, baseUrl) (environment_credential) answers what a client handed no key will do, routedClientType(model, clientType) (routed_client_type) which client a model reaches, and CLIENT_CREDENTIALS lists each client type's variables and default endpoint. The clients resolve their credentials through the same table.
Methods
streamingResponse(options: { messages: UniMessage[]; config: UniConfig }): AsyncGenerator<UniEvent>;
streamingResponseStateful(options: { message: UniMessage; config: UniConfig }): AsyncGenerator<UniEvent>;
listModels(): Promise<string[]>;
getHistory(): UniMessage[];
setHistory(history: UniMessage[]): void;
clearHistory(): void;
async def streaming_response(messages: list[UniMessage], config: UniConfig) -> AsyncIterator[UniEvent]:
"""Stream one response from a full message list. Keeps nothing."""
async def streaming_response_stateful(message: UniMessage, config: UniConfig) -> AsyncIterator[UniEvent]:
"""Stream one response to a new message, and record both in the history."""
async def list_models() -> list[str]:
"""The model ids the configured endpoint serves."""
def get_history() -> list[UniMessage]: ...
def set_history(history: list[UniMessage]) -> None: ...
def clear_history() -> None: ...
Both streaming methods yield delta events, then exactly one stop event. The stateful method records the turn before it yields the stop event, so you may stop iterating as soon as you see it.
The history holds deep copies: the stateful method records copies of the message you sent and of the reply, get_history returns a deep copy and set_history stores one, so neither your objects nor the events you were handed can change it. A message you pass without created_at is stamped with one on your own object. One stateful call runs at a time on a client: another one started before the first has yielded its stop event, raised or been aborted raises ConcurrentCallError. An aborted call releases the client at once and records nothing; a stream you leave earlier holds the client until it is closed (await stream.aclose() in Python). A message with nothing the client can send, no content items or thinking alone, raises InvalidMessageError before the request goes out.
list_models lists everything the endpoint serves when the client was named with client_type. A client deduced from a model id lists only the ids of that family.
Helpers
import { listSupportedModels, normalizeLegacyMessages } from "@prismshadow/mmsp";
const models = listSupportedModels("CNY"); // "USD" by default
const messages = normalizeLegacyMessages(storedMessages);
from mmsp import list_supported_models, normalize_legacy_messages
models = list_supported_models(currency="CNY") # "USD" by default
messages = normalize_legacy_messages(stored_messages)
list_supported_modelsreturns one entry per model and endpoint: the model id, the base URL, the client, the input and output modalities, the context window, and the list price per million tokens.normalize_legacy_messagesconverts messages saved before 0.5.0. It is removed in 0.6.0.