Implementation guide

Sakana Fugu API quickstart

A copyable integration is useful only if it fails clearly, keeps retries bounded, and captures the billable orchestration work. This walkthrough does all three without inventing unsupported parameters.

1. Choose the model before you write the request

The API surface is shared, but routing control, price predictability, access, and intended workload differ. Treat model choice as configuration, not a magic quality switch.

Model IDUse it forImportant constraint
fuguInteractive coding, chat, normal reviews, first evaluation passPay-as-you-go cost varies with the routed model; specific agents may be excluded
fugu-ultraDifficult multi-step reasoning where quality is worth added time and costFixed full agent pool; current docs say one to three agents
fugu-ultra-20260615Pinning the documented dated Ultra versionUse the stable ID unless version pinning is a deliberate requirement
fugu-cyberAuthorized defensive security reasoning and investigationPay-as-you-go only and returned only when access is approved

Call GET /v1/models during setup rather than assuming a model ID is available to every key. That boundary check turns an ambiguous generation failure into a precise deployment error.

2. Validate configuration at startup

Secrets belong in environment variables. Missing values should stop the program immediately with the exact variable name, not surface later as a vague authentication or URL error.

client.py
import os
from openai import OpenAI


def require_environment_value(name: str) -> str:
    value = os.environ.get(name, "").strip()
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value


def create_fugu_client() -> OpenAI:
    base_url = require_environment_value("FUGU_BASE_URL").rstrip("/")
    if not base_url.endswith("/v1"):
        base_url += "/v1"
    return OpenAI(
        api_key=require_environment_value("FUGU_API_KEY"),
        base_url=base_url,
        timeout=120.0,
        max_retries=2,
    )
Why two retries?

A small bounded retry count can absorb a transient connection or rate-limit response. An unbounded loop can repeat an expensive autonomous task, hide a persistent outage, and make the caller impossible to reason about.

3. Prefer the Responses API for new integrations

Sakana AI currently supports Responses, Chat Completions, and Models endpoints. Its model documentation recommends Responses for tool use, multimodal input, reasoning controls, and function calls.

Direct response
from client import create_fugu_client


def review_change(change_description: str) -> str:
    if not change_description.strip():
        raise ValueError("change_description must not be empty")

    response = create_fugu_client().responses.create(
        model="fugu",
        instructions="Find correctness risks first. State uncertainty explicitly.",
        input=change_description,
        max_output_tokens=2000,
    )
    return response.output_text


print(review_change("Review this database migration for rollback risks."))

The input check is intentionally local. It prevents an empty, billable request and provides a specific error before the network boundary.

4. Stream long responses without losing the final object

Streaming improves perceived latency, but the final response object is still important because that is where you inspect status and usage. Do not discard it after printing text deltas.

Streaming response
from client import create_fugu_client


def stream_answer(prompt: str):
    client = create_fugu_client()
    with client.responses.stream(model="fugu-ultra", input=prompt) as stream:
        for event in stream:
            if event.type == "response.output_text.delta":
                print(event.delta, end="", flush=True)
        return stream.get_final_response()


final_response = stream_answer("Compare two rollback plans and show failure modes.")
print()
print(final_response.usage)

If a caller disconnects, decide whether the server should cancel the upstream work. Do not automatically submit the same task again unless the operation is safe to repeat and the prior request is known not to have completed.

5. Know which OpenAI-shaped fields behave differently

Compatibility describes the request shape, not identical semantics. The current Sakana model page documents these differences.

Field or behaviorCurrent documented behaviorIntegration consequence
temperatureAccepted but ignored on ResponsesDo not build quality controls around it
top_p, penalties, seed, stopAccepted but ignored on Chat CompletionsValidate required determinism with actual outputs
previous_response_idNot acceptedSend the full conversation history in input
max_output_tokensFor Ultra, limits the final model output, not the orchestrator's own maximumIt is not a complete cost ceiling
reasoning.effortSupports high, xhigh, and max; xhigh and max are aliasesDo not assume three distinct effort levels
Built-in web searchSupported through the Responses tool shapeTest citation and tool output handling before production

6. Capture all billable usage fields

For Ultra and Cyber, Sakana AI documents orchestration token details outside the usual input and output fields. It states that these represent real usage and count toward final price at the same category rate.

Relevant usage shape
{
  "input_tokens": 120,
  "output_tokens": 80,
  "input_tokens_details": {
    "cached_tokens": 0,
    "orchestration_input_tokens": 450,
    "orchestration_input_cached_tokens": 100
  },
  "output_tokens_details": {
    "orchestration_output_tokens": 220
  }
}

For cost accounting, add normal and orchestration input, add normal and orchestration output, and add normal and orchestration cached input. Store raw usage beside your calculated estimate so later pricing or interpretation changes remain auditable.

See the exact formula and examples

7. Turn common failures into specific actions

401 or 403

Check that the key is present, active, and tied to the expected billing mode. For Cyber, confirm that access was approved. Never log the secret itself.

404 model not found

Call the Models API with the same key and base URL. Fail startup with the missing model ID instead of silently switching to a different model.

429 rate limit

Respect any retry guidance, keep the total attempt count bounded, and surface the final error. Queueing can help, but a queue must also have a capacity and expiry policy.

Timeout

Separate connect time from task time in logs. A hard multi-agent task may legitimately take longer, but a larger timeout is not a substitute for cancellation, observability, or a user-visible status.

Unexpected cost

Compare the full usage object with the pricing formula. Check orchestration fields and whether requests exceeded 272K context. Do not infer cost from visible answer length alone.

Good-looking but wrong output

Do not retry blindly. Save the prompt, tools, model ID, and response ID; score it against a fixed rubric and route high-risk tasks to human review.

8. Production readiness checklist

  • API key and base URL are required and validated at startup.
  • The selected model is verified through /v1/models.
  • Timeouts and retries have explicit finite values.
  • Requests are safe to retry or have an idempotency strategy at the application layer.
  • Logs include model, duration, status, and request correlation ID, but never secrets or sensitive prompt content by default.
  • The complete usage object is retained for cost reconciliation.
  • Ignored fields are not presented to users as active controls.
  • Fallback behavior is explicit: return a clear failure, or use a named approved fallback with a visible quality tradeoff.
  • EU and EEA availability is checked against current official policy before deployment.
  • Security testing uses Cyber only with approved access, authorization, and a written scope.

Sources and verification boundary

This page describes documented behavior, not a private compatibility certification. Recheck the official Models endpoint and documentation before a production release.