Go SDK

Go SDK for Tinfoil’s secure AI inference API
GitHub: tinfoil-go



Installation

Then run:

go get github.com/tinfoilsh/tinfoil-go

tinfoil-go currently relies on a specific feature in go-sev-guest that hasn’t been upstreamed yet. This requires adding the following line to your go.mod:

replace github.com/google/go-sev-guest v0.0.0-00010101000000-000000000000 => github.com/jraman567/go-sev-guest v0.0.0-20250117204014-6339110611c9

Migration from OpenAI

Migrating from OpenAI to Tinfoil is straightforward. The client is designed to be compatible with the OpenAI Go client:

// Before (OpenAI)
- import (
- 	"os"
- 	"github.com/openai/openai-go"
- 	"github.com/openai/openai-go/option"
- )
- 
- client := openai.NewClient(option.WithAPIKey(os.Getenv("OPENAI_API_KEY")))

// After (Tinfoil)
+ import (
+ 	"os"
+ 	"github.com/openai/openai-go"
+ 	"github.com/openai/openai-go/option"
+ 	"github.com/tinfoilsh/tinfoil-go"
+ )
+ 
+ client, err := tinfoil.NewClientWithParams(
+ 	"enclave.example.com",
+ 	"org/model-repo", 
+ 	option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
+ )

All method signatures remain the same since tinfoil.NewClientWithParams() returns a standard OpenAI client with built-in security features.

Quick Start

The Tinfoil Go client is a wrapper around the OpenAI Go client and provides secure communication with Tinfoil enclaves. It has the same API as the OpenAI client, with additional security features:

  • Automatic attestation validation to ensure enclave integrity verification
  • TLS certificate pinning to prevent man-in-the-middle attacks
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/openai/openai-go"
	"github.com/openai/openai-go/option"
	"github.com/tinfoilsh/tinfoil-go" // imported as tinfoil
)

func main() {
	// Create a client for a specific enclave and model repository
	client, err := tinfoil.NewClientWithParams(
		"enclave.example.com",
		"org/model-repo",
		option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Make requests using the OpenAI client API
	// Note: enclave verification happens automatically
	chatCompletion, err := client.Chat.Completions.New(context.TODO(), openai.ChatCompletionNewParams{
		Messages: []openai.ChatCompletionMessageParamUnion{
			openai.UserMessage("Say this is a test"),
		},
		Model: "llama3-3-70b", // see https://docs.tinfoil.sh for supported models
	})

	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(chatCompletion.Choices[0].Message.Content)
}

Usage

// 1. Create a client
client, err := tinfoil.NewClientWithParams(
	"enclave.example.com",  // Enclave hostname
	"org/repo",             // GitHub repository
	option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
)
if err != nil {
	log.Fatal(err)
}

// 2. Use client as you would openai.Client 
// see https://pkg.go.dev/github.com/openai/openai-go for API documentation

Running the Chat Example

This example demonstrates how to use the Tinfoil client to interact with OpenAI’s chat completion API in both streaming and non-streaming modes.

Setup

  1. Make sure you have Go installed and the Tinfoil repository cloned
  2. Set up your environment variable:
    export TINFOIL_API_KEY="your-api-key"
    
  3. Run the example

What the Example Does

The example will:

  1. Create an OpenAI client configured with Tinfoil settings

  2. Demonstrate a streaming chat completion with real-time output

The code shows both the basic usage pattern and error handling for each approach.

Audio

Speech-to-Text (Transcription)

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/openai/openai-go"
	"github.com/openai/openai-go/option"
	"github.com/tinfoilsh/tinfoil-go"
)

func main() {
	client, err := tinfoil.NewClientWithParams(
		"audio-processing.model.tinfoil.sh",
		"tinfoilsh/confidential-audio-processing",
		option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
	)
	if err != nil {
		log.Fatal(err)
	}

	audioFile, err := os.Open("audio.mp3")
	if err != nil {
		log.Fatal(err)
	}
	defer audioFile.Close()

	transcription, err := client.Audio.Transcriptions.New(context.TODO(), openai.AudioTranscriptionNewParams{
		Model: "whisper-large-v3-turbo",
		File:  openai.File(audioFile, "audio.mp3", "audio/mpeg"),
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(transcription.Text)
}

Text-to-Speech (Synthesis)

package main

import (
	"context"
	"io"
	"log"
	"os"

	"github.com/openai/openai-go"
	"github.com/openai/openai-go/option"
	"github.com/tinfoilsh/tinfoil-go"
)

func main() {
	client, err := tinfoil.NewClientWithParams(
		"audio-processing.model.tinfoil.sh",
		"tinfoilsh/confidential-audio-processing",
		option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
	)
	if err != nil {
		log.Fatalf("Error creating client: %v", err)
	}

	response, err := client.Audio.Speech.New(
		context.Background(),
		openai.AudioSpeechNewParams{
			Model: "kokoro",
			Voice: "af_sky+af_bella",
			Input: "Hello world! This is a test of text-to-speech synthesis.",
		},
	)
	if err != nil {
		log.Fatalf("Error creating speech: %v", err)
	}
	defer response.Body.Close()

	out, err := os.Create("output.mp3")
	if err != nil {
		log.Fatalf("Error creating output file: %v", err)
	}
	defer out.Close()

	_, err = io.Copy(out, response.Body)
	if err != nil {
		log.Fatalf("Error writing audio file: %v", err)
	}

	fmt.Println("Speech saved to output.mp3")
}

Embeddings

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/openai/openai-go"
	"github.com/openai/openai-go/option"
	"github.com/tinfoilsh/tinfoil-go"
)

func main() {
	client, err := tinfoil.NewClientWithParams(
		"nomic-embed-text.model.tinfoil.sh",
		"tinfoilsh/confidential-nomic-embed-text",
		option.WithAPIKey(os.Getenv("TINFOIL_API_KEY")),
	)
	if err != nil {
		log.Fatal(err)
	}

	response, err := client.Embeddings.New(context.TODO(), openai.EmbeddingNewParams{
		Model: "nomic-embed-text",
		Input: openai.EmbeddingNewParamsInputUnion{
			OfArrayOfStrings: []string{"The quick brown fox jumps over the lazy dog"},
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	embeddingVector := response.Data[0].Embedding
	fmt.Printf("Embedding dimension: %d\n", len(embeddingVector))
}

Advanced Functionality

// For manual verification and direct HTTP access, use SecureClient directly
secureClient := tinfoil.NewSecureClient("enclave.example.com", "org/repo")

// Manual verification
groundTruth, err := secureClient.Verify()
if err != nil {
	return fmt.Errorf("verification failed: %w", err)
}

// Get the raw HTTP client 
httpClient, err := secureClient.HTTPClient()
if err != nil {
	return fmt.Errorf("failed to get HTTP client: %w", err)
}

// Make HTTP requests directly 
resp, err := secureClient.Get("/api/status", map[string]string{
	"Authorization": "Bearer token",
})

API Documentation

This library is a drop-in replacement for the official OpenAI Go client that can be used with Tinfoil. All methods and types are identical. See the OpenAI Go client documentation for complete API usage and documentation.