Skip to content

Ohualtex/Prismatic

Repository files navigation

Prismatic

Send one prompt to one or more LLM providers across a spread of sampling temperatures — several responses, side by side, in your terminal.

What it does

The same prompt is dispatched in parallel to a set of personas. Each persona pairs a temperature with a backend provider, so you can compare how temperature shifts a model from precise and terse to vivid and exploratory — and, when you configure more than one provider, how Gemini, Claude, and OpenAI answer the same prompt differently. Each response is rendered as its own panel.

The name is a metaphor: one beam — the prompt — entering a prism becomes multiple colours, each a different answer.

Demo

$ python main.py "What is the capital of France?"

╭─ gemini (creative, temp=0.9) ──────────────────────╮
│ The capital is Paris, a city famed for its         │
│ riverside elegance and centuries of layered        │
│ history beneath every street corner.               │
│                                                    │
│ ⏱  1.2s · 📊 142 tokens                            │
╰────────────────────────────────────────────────────╯

╭─ gemini (balanced, temp=0.5) ──────────────────────╮
│ Paris is the capital of France.                    │
│                                                    │
│ ⏱  0.8s · 📊 98 tokens                             │
╰────────────────────────────────────────────────────╯

╭─ gemini (precise, temp=0.1) ───────────────────────╮
│ Paris.                                             │
│                                                    │
│ ⏱  0.6s · 📊 12 tokens                             │
╰────────────────────────────────────────────────────╯

When a persona fails (rate limit, timeout, auth error, etc.) its panel turns red and the error category is shown in place of the text; the other personas still complete and render.

Options

JSON output

Pass --json to emit a JSON array instead of panels, for piping into other tools:

python main.py "What is the capital of France?" --json | jq '.[] | {persona: .persona_name, kind}'

Each element carries a kind discriminator ("success" or "failure") so consumers can branch on one field.

Custom personas

Personas are configurable via a YAML file passed with --personas. Copy personas.example.yaml and edit it:

personas:
  - name: creative
    temperature: 0.9
    system_prompt: "Lean into vivid, exploratory framings."
  - name: precise
    temperature: 0.1
python main.py "Explain recursion." --personas personas.yaml

Each persona needs a unique name and a temperature in [0.0, 2.0]; system_prompt is optional. Without --personas, the built-in creative / balanced / precise set is used.

Multiple providers

A persona can name a providergemini (default), claude, or openai. With the matching API keys set, a single prompt fans out across backends at once:

personas:
  - name: gemini-take
    temperature: 0.7
    provider: gemini
  - name: claude-take
    temperature: 0.7
    provider: claude
  - name: openai-take
    temperature: 0.7
    provider: openai

A persona whose provider has no configured key renders as a ProviderUnavailable panel rather than aborting the run.

Quickstart

Requirements

Install

git clone https://github.com/Ohualtex/Prismatic.git
cd Prismatic
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Configure

cp .env.example .env
# Open .env and set at least one of GEMINI_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY

Run

python main.py "What is the capital of France?"

How it works

Each persona fires in parallel via asyncio.gather. Every provider client (GeminiClient, ClaudeClient, OpenAIClient) satisfies a common LLMClient protocol, and the orchestrator dispatches each persona to its provider through a registry — so adding a provider needs no change to the orchestrator. Each call is wrapped in a retry loop with jittered exponential backoff for transient failures (429, 5xx, timeout); permanent failures (4xx, auth) fail fast. Results are gathered in the original persona order regardless of completion order, then rendered — green panels for success, red for failure.

Both successful and failed responses are first-class data: the orchestrator returns a list of ModelResponse values where every element is either a ModelSuccess or a ModelFailure, never an exception. Callers branch on response type, not try/except.

Development

pip install -r requirements-dev.txt

# Run the test suite (fully mocked — no API calls)
pytest

# Format, lint, type-check
ruff format .
ruff check .
mypy --strict .

Prismatic (Türkçe)

Tek bir prompt'u bir veya daha fazla LLM sağlayıcısına, bir dizi sıcaklık (temperature) değeriyle gönderin — birkaç cevap, yan yana, terminalinizde.

Ne yapar?

Aynı prompt bir persona kümesine paralel olarak dağıtılır. Her persona bir sıcaklığı bir arka uç sağlayıcısıyla eşler; böylece temperature'ün bir modeli kesin ve özlü olmaktan canlı ve keşifçi olmaya nasıl kaydırdığını — ve birden fazla sağlayıcı yapılandırdığınızda Gemini, Claude ve OpenAI'nin aynı prompt'a nasıl farklı yanıt verdiğini — karşılaştırabilirsiniz. Her cevap kendi paneline render edilir.

İsim bir metafor: tek bir ışın — yani prompt — prizmadan geçince birden fazla renge, yani farklı cevaplara ayrılır.

Bir persona başarısız olduğunda (rate limit, timeout, auth hatası vb.) paneli kırmızıya döner ve metin yerine hata kategorisi gösterilir; diğer personalar yine de tamamlanır ve render edilir.

Seçenekler

JSON çıktı

Paneller yerine JSON dizisi üretmek için --json geçin; başka araçlara aktarmak (pipe) için:

python main.py "Fransa'nın başkenti nedir?" --json | jq '.[] | {persona: .persona_name, kind}'

Her eleman bir kind ayırıcısı ("success" veya "failure") taşır; böylece tüketiciler tek alan üzerinden dallanabilir.

Özel personalar

Personalar --personas ile geçirilen bir YAML dosyasıyla yapılandırılabilir. personas.example.yaml'ı kopyalayıp düzenleyin:

personas:
  - name: creative
    temperature: 0.9
    system_prompt: "Lean into vivid, exploratory framings."
  - name: precise
    temperature: 0.1
python main.py "Özyinelemeyi açıkla." --personas personas.yaml

Her persona benzersiz bir name ve [0.0, 2.0] aralığında bir temperature gerektirir; system_prompt opsiyoneldir. --personas olmadan yerleşik creative / balanced / precise kümesi kullanılır.

Birden fazla sağlayıcı

Bir persona bir provider adlandırabilir — gemini (varsayılan), claude veya openai. Eşleşen API anahtarları ayarlıyken, tek bir prompt aynı anda arka uçlara dağılır:

personas:
  - name: gemini-take
    temperature: 0.7
    provider: gemini
  - name: claude-take
    temperature: 0.7
    provider: claude
  - name: openai-take
    temperature: 0.7
    provider: openai

Sağlayıcısının yapılandırılmış anahtarı olmayan bir persona, çalışmayı iptal etmek yerine ProviderUnavailable paneli olarak render edilir.

Hızlı başlangıç

Gereksinimler

Kurulum

git clone https://github.com/Ohualtex/Prismatic.git
cd Prismatic
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Yapılandırma

cp .env.example .env
# .env'yi açın ve GEMINI_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY'den en az birini ayarlayın

Çalıştırma

python main.py "Fransa'nın başkenti nedir?"

Nasıl çalışır?

Her persona asyncio.gather ile paralel çalışır. Her sağlayıcı client'ı (GeminiClient, ClaudeClient, OpenAIClient) ortak bir LLMClient protokolünü karşılar ve orchestrator her personayı bir registry aracılığıyla sağlayıcısına yönlendirir — böylece sağlayıcı eklemek orchestrator'da değişiklik gerektirmez. Her çağrı, geçici hatalar (429, 5xx, timeout) için jitter'lı üstel backoff retry döngüsüyle sarılır; kalıcı hatalar (4xx, auth) hızlıca başarısız olur. Sonuçlar, tamamlanma sırasından bağımsız olarak orijinal persona sırasında toplanır ve render edilir — başarı için yeşil, hata için kırmızı paneller.

Başarılı ve başarısız cevaplar birinci sınıf veridir: orchestrator bir ModelResponse listesi döner — her eleman ya ModelSuccess ya ModelFailure, asla exception değil. Çağıran taraf try/except yerine cevap tipi üzerinden dallanır.

Geliştirme

pip install -r requirements-dev.txt

# Test suite'i çalıştır (tamamen mock'lu — API çağrısı yok)
pytest

# Format, lint, tip kontrolü
ruff format .
ruff check .
mypy --strict .

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages