smarter-api v0.2 – v0.6 Release: The Smarter Python SDK, Typed From End to End

smarter-api is the official Python SDK of Smarter. It’s meant to be to Smarter what the openai package is to the OpenAI api, so one pip install gives your Python code typed access to your own Smarter platform, whether it runs on your laptop or on Kubernetes. This is its first announcement, and it covers everything from v0.2, which replaced the SDK’s two-year-old predecessor with a new one, to v0.6, released today.

pip install --upgrade smarter-api

The old SDK covered a single endpoint and a resource kind that the platform no longer has. The new one covers the whole api, returns Pydantic models instead of JSON, and raises typed exceptions instead of returning error dictionaries. It installs as smarter-api and imports as smarter.

What you getIn one sentence
Every resource kindApply, validate, get, describe, delete, deploy and undeploy any of the 25 kinds through the same manifest api as the smarter cli.
Prompts and chatPrompt an LLMClient, hold a chat session that the platform remembers, and stream a prompt’s progress as it runs.
Each resource’s own actionsEvaluate Guardrails, call MCP servers’ tools, add documents to and search vectorstores, and plan and deploy self-hosted LLMs.
Typed modelsA Pydantic model for every response, and a generated model of every manifest kind, so your editor and type checker know every field.
Typed errorsOne SmarterError hierarchy, with a subclass for each http status, such as NotFoundError.
Zero setup if you use the cliIt reads the cli’s ~/.smarter/config.yaml, or SMARTER_API_KEY and SMARTER_BASE_URL.
The platform’s own kindsSAMKinds and its apply order now come from smarter-types, the same package that the platform uses.

Using it

from smarter import Smarter

client = Smarter()  # SMARTER_API_KEY, or the smarter cli's ~/.smarter/config.yaml

me = client.whoami()
print(f"Hello, {me.user.username}!")

llmclient = client.llm_clients.find("customer_support")
print(client.llm_clients.prompt(llmclient.id, "Where is my order #1234?").text)

chat = client.llm_clients.chat(llmclient.id)
print(chat.send("What is 2 to the 10th power?").text)
print(chat.send("And divided by 4?").text)  # the session remembers the question before
  • Every write goes through the manifest api. client.manifests.apply() sends a manifest exactly as smarter apply -f does, so the SDK, the cli and the web console change resources the same way, with the same validation.
  • Retries that know the platform. Timeouts, connection errors, rate limits and gateway errors are retried with backoff, twice by default, and honor Retry-After. A 503 that the platform itself sends, for a resource that isn’t ready yet, isn’t retried, because a retry wouldn’t change it.
  • Your api key never reaches a log. Logging is off unless you set SMARTER_LOG, and keys are always masked.
  • It keeps working when the platform grows. The response models accept fields they don’t know yet, and values that the platform may add to, such as kinds, are strings rather than closed enumerations, so a newer platform doesn’t break an older SDK.

Getting Started With smarter-api has a complete walkthrough, including a script that applies a folder of manifests in dependency order, the way a CI/CD job would.

📖 smarter-api documentation


What changed from v0.2 to v0.6

v0.6 and the platform’s own manifest kinds

  • SAMKinds comes from smarter-types. The SDK used to have no way to know which kinds exist, or the order to apply them in, without copying the platform’s definitions. Now it depends on smarter-types, the package the platform uses, and from smarter import SAMKinds is that class. SAMKinds.apply_rank() sorts manifests so that each resource comes after the resources it names, such as a Secret before its Connection, a Connection before its plugin.
  • Manifests with unquoted dates are accepted. YAML reads an unquoted 2024-06-15 as a date, which isn’t a JSON value, so Manifest rejected a manifest that the platform accepts, such as one with a release-date annotation. A date is now kept as the text it was written as.

v0.5 follows the platform

  • Functions became extensions (v0.5.1). The platform replaced an LLMClient’s built-in functions with installable Extensions, and renamed them everywhere. The SDK follows, with no deprecated aliases, because an alias could only call a route that the platform no longer serves. llm_clients.functions() is now llm_clients.extensions(), LLMClient.functions is LLMClient.extensions, and the models named after functions are named after extensions. If your code used them, rename them.
  • config(verbose=True) (v0.5.2). Since Smarter v0.36.6, an LLMClient’s configuration is short unless you ask for all of it. llm_clients.config() returns the short one by default, and verbose=True adds the plugin and extension lists and the tool-call history.
  • An LLMClient’s MCPClients, Guardrails and tools. The LLMClient model has mcpclients, guardrails and tools, everything that the LLMClient adds to a prompt, each an empty list on an older platform.

v0.3 and v0.4 cover the rest of the api

  • User profiles and plugin uses. client.accounts.user_profiles lists each user’s memberships of accounts, and client.history.plugin_use(id) retrieves one use of a plugin.
  • Typed Orchestrators and Vectorsearches, whose own fields used to arrive as untyped extras.

Built to be depended on

A client library sits under its users’ own code, so v0.5.3 rebuilt how smarter-api is tested, released and documented, on the same pattern as cache-results.

  • Tested on Python 3.10 to 3.14 on every push and pull request, at 99% branch coverage, against recorded responses from a running platform. A contract test fails when the platform’s api has a field that the SDK doesn’t declare, and the SDK keeps a pinned copy of the platform’s OpenAPI document and the JSON Schema of every manifest kind.
  • Typed. The package ships py.typed, and its manifest models are generated from the schemas that the platform publishes.
  • Released by a workflow, not a laptop. Every push to main runs the whole test matrix, and semantic-release decides from the commit messages whether to release. The release is rehearsed on TestPyPI and installed back, then published to PyPI with trusted publishing, so no PyPI token exists anywhere, and installed back again.
  • Documented on its own site. docs.smarter-python.smarter.sh has a quickstart, a user guide (configuration, manifests, chat, resources, models and errors), an api reference generated from the code, including a page for every manifest kind, and 25 architecture decision records.
  • Licensed like Smarter, under the AGPL-3.0-or-later, and published by The Smarter Project.

Try it, and tell people about it

  • Install it and prompt one of your LLMClients in a few lines, after pip install smarter-api. If you don’t have a platform yet, the Quick Start Guide runs one on your laptop.
  • Star the repository at github.com/smarter-sh/smarter-python.
  • Open an issue for a bug, or for a part of the api that you’d like a better shape for. The contributing guide explains how to make a change.
  • Prefer JavaScript or Go? The Node.js and Go SDKs follow this one’s design, resources and errors.

What’s next

  • An async client. smarter-api is synchronous today, and async applications call it in a thread with asyncio.to_thread. Its transport and resources are built so that an AsyncSmarter can be added without changing the public api, as ADR-018 explains.
  • Keeping in step with the platform. Each Smarter release that changes its api is followed by a smarter-api release that syncs the contracts and models.

The changelog is on GitHub, with the v0.6.0 release. The package is on PyPI, the docs are at docs.smarter-python.smarter.sh, and the source is at github.com/smarter-sh/smarter-python.