Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/badlogic/pi-mono/llms.txt

Use this file to discover all available pages before exploring further.

The complete() and completeSimple() functions provide a synchronous interface for getting LLM responses. They internally use stream() and streamSimple() but await the full result.

Import

import { complete, completeSimple } from "@mariozechner/pi-ai";

complete

Get a complete response with provider-specific options.
complete<TApi extends Api>(
  model: Model<TApi>,
  context: Context,
  options?: ProviderStreamOptions
): Promise<AssistantMessage>
model
Model<TApi>
required
The model to use for generation
context
Context
required
Conversation context
options
ProviderStreamOptions
Same options as stream() (see Stream Functions)
AssistantMessage
object

Example

import { complete, getModel } from "@mariozechner/pi-ai";

const model = getModel("anthropic", "claude-4.5-sonnet-20250514");

const message = await complete(model, {
  systemPrompt: "You are a helpful assistant.",
  messages: [
    { role: "user", content: "Explain TypeScript generics", timestamp: Date.now() }
  ],
}, {
  temperature: 0.7,
  maxTokens: 1000,
});

console.log(message.content);
console.log(`Tokens used: ${message.usage.input + message.usage.output}`);

completeSimple

Get a complete response with unified reasoning parameter.
completeSimple<TApi extends Api>(
  model: Model<TApi>,
  context: Context,
  options?: SimpleStreamOptions
): Promise<AssistantMessage>
model
Model<TApi>
required
The model to use for generation
context
Context
required
Conversation context
options
SimpleStreamOptions
Same options as streamSimple() (see Stream Functions)

Example

import { completeSimple, getModel } from "@mariozechner/pi-ai";

const model = getModel("openai", "gpt-5.3-codex");

const message = await completeSimple(model, {
  systemPrompt: "You are a coding assistant.",
  messages: [
    { role: "user", content: "Write a Fibonacci function", timestamp: Date.now() }
  ],
}, {
  reasoning: "medium",
  temperature: 0.7,
});

// Extract thinking and text
const thinking = message.content.filter(c => c.type === "thinking");
const text = message.content.filter(c => c.type === "text");

console.log("Thinking:", thinking);
console.log("Response:", text);

Error Handling

Both functions throw errors on failure:
try {
  const message = await complete(model, context, options);
  console.log(message.content);
} catch (error) {
  if (error.name === "AbortError") {
    console.log("Request was cancelled");
  } else if (error.message.includes("context_length_exceeded")) {
    console.log("Context too long");
  } else {
    console.error("API error:", error);
  }
}

Cancellation

Use AbortSignal to cancel requests:
const controller = new AbortController();

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10000);

try {
  const message = await complete(model, context, {
    signal: controller.signal,
  });
  console.log(message.content);
} catch (error) {
  if (error.name === "AbortError") {
    console.log("Request timed out");
  }
}

Tool Calls

When the response includes tool calls:
const message = await complete(model, {
  systemPrompt: "You are a helpful assistant.",
  messages: [
    { role: "user", content: "What's the weather?", timestamp: Date.now() }
  ],
  tools: [
    {
      type: "function",
      function: {
        name: "get_weather",
        description: "Get current weather",
        parameters: {
          type: "object",
          properties: {
            location: { type: "string" },
          },
          required: ["location"],
        },
      },
    },
  ],
});

// Check for tool calls
const toolCalls = message.content.filter(c => c.type === "toolCall");
if (toolCalls.length > 0) {
  console.log("Tool calls:", toolCalls);
  // Execute tools and send results back
}

Usage Statistics

All responses include token usage:
const message = await complete(model, context);

console.log("Input tokens:", message.usage.input);
console.log("Output tokens:", message.usage.output);
console.log("Cache read:", message.usage.cacheRead);
console.log("Cache write:", message.usage.cacheWrite);
console.log("Cost:", message.usage.cost.total);

Comparison with Stream

Use CaseFunctionWhen to Use
Real-time outputstream() / streamSimple()Interactive applications, showing progress
Batch processingcomplete() / completeSimple()Background tasks, API servers
Tool executionstream()Need to show tool execution progress
Simple Q&Acomplete()Just need the final answer

Performance

complete() and completeSimple() have the same performance as their streaming counterparts - they just buffer the events internally:
// These are equivalent:
const message1 = await complete(model, context);

const stream = stream(model, context);
const message2 = await stream.result();

// Both take the same time and use the same network requests