Packages

Minimal Elixir SDK for the TypeSafe System One API, generated from TypeSafe OpenAPI and executed through Pristine.

Current section

Files

Jump to
Raw

README.md

<p align="center">
  <img src="assets/typesafe_api_sdk.svg" alt="TypeSafe API SDK" width="200" height="200"/>
</p>

<p align="center">
  <a href="https://hex.pm/packages/typesafe_api_sdk"><img src="https://img.shields.io/hexpm/v/typesafe_api_sdk.svg" alt="Hex.pm"/></a>
  <a href="https://hexdocs.pm/typesafe_api_sdk"><img src="https://img.shields.io/badge/hex-docs-blue.svg" alt="HexDocs"/></a>
  <a href="https://github.com/nshkrdotcom/typesafe_api_sdk"><img src="https://img.shields.io/badge/GitHub-repo-black?logo=github" alt="GitHub"/></a>
  <a href="https://hex.pm/packages/typesafe_api_sdk"><img src="https://img.shields.io/hexpm/l/typesafe_api_sdk.svg" alt="License"/></a>
</p>

# TypeSafe API SDK

> **Building with System One semantics?** New application code should use
> [`system_one_sdk`](https://github.com/nshkrdotcom/system_one_sdk), the
> provider-neutral Elixir/BEAM SDK. `typesafe_api_sdk` is the TypeSafe-specific
> API/provider SDK used by its built-in TypeSafe provider.
>

**Fast, reliable, and strongly typed Elixir client for TypeSafe AI's System One API.**

Instead of writing fragile string prompts, wrestling with token limits, or parsing unstructured JSON out of an LLM, `typesafe_api_sdk` gives you direct, probabilistic machine intelligence over structured data:

1. Provide your application state (a customer message, document, or structured map).
2. Ask targeted questions using typed primitives (`Noul`, `Choice`, and `Score`).
3. Receive validated Elixir structs with exact probabilities and answers.

Execution is powered by [Pristine](https://github.com/nshkrdotcom/pristine) for rock-solid HTTP/2 connection pooling, automatic retries with exponential backoff, and cooperative request cancellation.

---

## Quick Example

```elixir
# 1. Initialize your client
client = TypeSafeAPISDK.new_client(api_key: System.fetch_env!("TYPESAFE_API_KEY"))

# 2. Define questions with native wire primitives
questions = %{
  billing: TypeSafeAPISDK.noul(
    instructions: "Is this inquiry primarily about billing, invoices, or payment methods?"
  ),
  routing: TypeSafeAPISDK.choice(
    %{
      "tier1" => "Standard questions, password resets, basic FAQ",
      "engineering" => "Bug reports, API failures, infrastructure outages",
      "finance" => "Charge disputes, refunds, tax inquiries"
    },
    instructions: "Which team is best equipped to resolve this?"
  ),
  urgency: TypeSafeAPISDK.score(
    ["low", "medium", "critical"],
    instructions: "How urgent is the customer's request?"
  )
}

# 3. Query the model with your context
{:ok, response} = TypeSafeAPISDK.system_one(
  client,
  "Customer reports: 'Our production webhook endpoint received 500s during checkout.'",
  questions
)

# 4. Access typed answers directly
response.answers["billing"].noul           #=> false
response.answers["routing"].choice         #=> "engineering"
response.answers["urgency"].score          #=> "critical"
response.usage.input_tokens                #=> 42
```

---

## Key Highlights

- **Typed Wire Primitives**: First-class structs for every question type (`Noul`, `Choice`, `Score`) and answer type (`NoulAnswer`, `ChoiceAnswer`, `ScoreAnswer`). No string extraction or schema guessing.
- **Production-Ready HTTP Substrate**: Executes on [Pristine](https://github.com/nshkrdotcom/pristine) using Finch connection pools, HTTP/2 multiplexing, and jittered exponential backoff.
- **Resilient Retry Handling**: Automatic handling of transient 429 rate limits, 5xx server errors, and explicit server `Retry-After` headers.
- **Cooperative Cancellation**: Full integration with `Pristine.Cancellation` tokens so you can safely cancel running requests when client timeouts fire or callers disconnect.
- **Committed OpenAPI Code Generation**: Core operations and schemas are generated from reviewed TypeSafe OpenAPI specifications for exact wire fidelity.

---

## Installation

Add `typesafe_api_sdk` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:typesafe_api_sdk, "~> 0.1.0"}
  ]
end
```

Before Hex publication or in local development, use a path dependency:

```elixir
def deps do
  [
    {:typesafe_api_sdk, path: "../typesafe_api_sdk"}
  ]
end
```

---

## Question Types

TypeSafe System One answers questions probabilistically over your input state. Three fundamental primitives cover virtually any operational decision:

### 1. Noul (Boolean / Binary Decision)
Use `noul/1` when you need a definitive yes/no or true/false answer:

```elixir
question = TypeSafeAPISDK.noul(
  instructions: "Does this message contain a request to cancel an account?"
)
```

### 2. Choice (Categorical Routing)
Use `choice/2` when selecting one category from a defined set of options:

```elixir
question = TypeSafeAPISDK.choice(
  %{
    "en" => "English language text",
    "es" => "Spanish language text",
    "fr" => "French language text"
  },
  instructions: "What language is this text written in?"
)
```

### 3. Score (Ordered Spectrum)
Use `score/2` when evaluating quality, urgency, or sentiment along an ordered scale:

```elixir
question = TypeSafeAPISDK.score(
  ["minor", "moderate", "severe"],
  instructions: "Assess the severity of the reported issue."
)
```

---

## Discovering Models

TypeSafe regularly updates and optimizes its System One models. You can query available models at runtime:

```elixir
{:ok, catalog} = TypeSafeAPISDK.list_models(client)

for model <- catalog.models do
  IO.puts("#{model.name}: #{model.description} (released: #{model.release_date})")
end
```

By default, the SDK targets the `jev-latest` alias. You can override the default model on the client or per-request.

---

## Configuration

Clients can be configured with an explicit options keyword list or via application environment:

```elixir
client = TypeSafeAPISDK.new_client(
  api_key: "ts_live_...",
  base_url: "https://api.typesafe.ai",    # default
  model: "jev-latest",                   # default
  timeout_ms: 10_000,                     # 10s default
  retry: [max_retries: 2]                 # 2 retries default
)
```

### Environment Variables

When running as the root Mix application, `config/runtime.exs` automatically picks up:

| Variable | Description | Default |
|:---------|:------------|:--------|
| `TYPESAFE_API_KEY` | Your TypeSafe bearer API key | **Required** |
| `TYPESAFE_BASE_URL` | Root URL for the TypeSafe API | `https://api.typesafe.ai` |
| `TYPESAFE_DEFAULT_MODEL` | Default model alias | `jev-latest` |
| `TYPESAFE_LOG_LEVEL` | Logger level for API operations | `:info` |

---

## Runtime Controls & Resiliency

Every API call accepts per-request overrides for timeouts, custom retries, and cancellation:

```elixir
# Create a cancellation token
cancellation = Pristine.Cancellation.new()

# Execute request with custom overrides
task = Task.async(fn ->
  TypeSafeAPISDK.system_one(
    client,
    order_data,
    questions,
    model: "jev-latest",
    timeout_ms: 3_000,
    retry: [max_retries: 1],
    extra_headers: %{"X-Trace-ID" => "req_abc123"},
    cancellation: cancellation
  )
end)

# Cooperatively cancel if needed
# Pristine.Cancellation.cancel(cancellation)
result = Task.await(task)
```

---

## Architecture & Ecosystem Role

`typesafe_api_sdk` is intentionally designed as a lean, focused provider client. It sits directly on the Pristine runtime:

```text
       ┌──────────────────────────────┐
       │      Application / Domain    │
       └──────────────┬───────────────┘
                      │
                      ▼
       ┌──────────────────────────────┐
       │   system_one_sdk (Planned)   │  ◄── Orchestration, batching, OTP workflows
       └──────────────┬───────────────┘
                      │
                      ▼
 ┌──────────────────────────────────────────┐
 │             typesafe_api_sdk             │  ◄── Wire models, bearer auth,
 │  ┌────────────────────────────────────┐  │      OpenAPI schemas, status normalization
 │  │        Pristine HTTP Engine        │  │
 │  └─────────────────┬──────────────────┘  │
 └────────────────────┼─────────────────────┘
                      │
                      ▼
         [ TypeSafe System One API ]
```

- **`typesafe_api_sdk` owns**: TypeSafe OpenAPI operations, schemas, bearer authentication, wire structs (`Noul`, `Choice`, `Score`), response decoding, and status normalization.
- **Higher-level libraries own**: Domain-specific decision workflows, evaluation harnesses, speculative fan-out, batch pipelines, and OTP GenServers.

---

## Live Verification

The real-service matrix deliberately separates official TypeSafe credentials from
alternate-deployment credentials:

```bash
export TYPESAFE_API_KEY='...'
bash scripts/live_qc.sh official
```

The official matrix exercises both `/v1/models` and `/v1/systemone`, Noul, Choice,
Score, tuple and bang APIs, explicit/default model selection, request metadata,
and safe per-call controls. A separate opt-in alternate matrix verifies arbitrary
TypeSafe-compatible API roots (including deployment path prefixes) with a
credential issued for that exact root.

```bash
export TYPESAFE_LIVE_ALT_BASE_URL='https://provider.example/deployment/root'
export TYPESAFE_LIVE_ALT_API_KEY='...'
bash scripts/live_qc.sh alternate
```

See [`guides/live-verification.md`](guides/live-verification.md) for the complete
coverage matrix, including which failure/control paths are tested deterministically
rather than manufactured against a billable production service.

---

## Development & Maintenance

Clone the repository and fetch dependencies:

```bash
mix deps.get
mix test
```

### Running the Quality Gate

The quality gate validates formatting, strict Credo linter rules, Dialyzer types, documentation generation, and Hex packaging:

```bash
bash scripts/check_handoff.sh
```

### OpenAPI Refresh & Codegen

Generated code is committed directly to source control. To regenerate or verify the OpenAPI definitions against Pristine's codegen tools:

```bash
source scripts/ensure_tooling.sh
mix typesafe_api.verify --project-root .
```

---

## License

`typesafe_api_sdk` is open source software released under the [MIT License](LICENSE).