Manifests

Every Smarter resource is declared in a Smarter Application Manifest (SAM), and the SDK writes resources exactly as the CLI does: through the brokered manifest API. The platform’s broker for the manifest’s kind validates it with the kind’s Pydantic models and applies its business rules, so a manifest that the CLI accepts, the SDK accepts, and the other way round.

The manifest API

client.manifests has the CLI’s verbs, for any kind:

from smarter import Smarter

client = Smarter()

client.manifests.validate("pii-redactor.yaml")              # without applying it
client.manifests.apply("pii-redactor.yaml")                 # create or update
client.manifests.get("Guardrail").names                     # every Guardrail's name
manifest = client.manifests.describe("Guardrail", "pii_redactor")
client.manifests.delete("Guardrail", "pii_redactor")

client.manifests.example_manifest("LLMClient")              # a valid manifest to start from
client.manifests.json_schema("LLMClient")                   # the kind's JSON Schema
client.kinds()                                              # every kind, and which are deployable

apply() and validate() accept a manifest in any form: the path of a YAML or JSON file, YAML text, a dict, a Manifest, or a typed SAM model (see below).

deploy() and undeploy() deploy a deployable resource, such as an LLMClient on its own host name. Deploying creates real, possibly billable, infrastructure in the platform’s cloud: DNS records, TLS certificates and Kubernetes ingresses.

Each resource’s own methods

Each resource family has the same operations, bound to its kind:

client.guardrails.apply("pii-redactor.yaml")     # refuses a manifest of another kind
client.guardrails.describe("pii_redactor")
client.guardrails.delete("pii_redactor")
client.guardrails.example_manifest()
client.guardrails.json_schema()

Typed manifests

describe() returns a Manifest, whose spec is a plain JSON object, because its fields depend on the kind. to_sam() turns it into the kind’s typed model, with your editor’s completion and Pydantic’s validation:

guardrail = client.guardrails.describe("pii_redactor").to_sam()     # a SAMGuardrail
print(guardrail.spec.config.action, guardrail.status.created)

The typed models build manifests in code, too:

import os

from smarter.models.sam import SAMSecret

secret: SAMSecret = client.secrets.example_manifest().to_sam()
secret.metadata.name = "stripe_api_key"
secret.spec.config.value = os.environ["STRIPE_API_KEY"]
client.secrets.apply(secret)

There is a model of every kind: see Models.

Manifests in CI/CD

Because manifests are files, the usual way to manage production resources is to keep them in a repository, review changes in pull requests, and apply them from CI/CD:

from pathlib import Path
from smarter import Smarter

with Smarter() as client:
    for path in sorted(Path("manifests").glob("*.yaml")):
        result = client.manifests.validate(path)
        if not result.valid:
            raise SystemExit(f"{path}: {result.errors}")
    for path in sorted(Path("manifests").glob("*.yaml")):
        print(client.manifests.apply(path).message)