pipedog is an unofficial community port of Pipecat, not affiliated with Daily.
pipedog
LLM

Anthropic

Claude models with streaming, function calling, thinking and prompt caching through AnthropicLLMService.

Overview

AnthropicLLMService runs Claude models through the Anthropic Messages API. It streams text, calls functions, supports thinking and prompt caching, and accepts any client with the same beta.messages.create() shape.

  • AnthropicLLMService: the LLM service, with AnthropicLLMSettings for runtime-updatable settings and AnthropicThinkingConfig for thinking.

Installation

bun add @pipedog/anthropic
import { AnthropicLLMService, AnthropicThinkingConfig } from "@pipedog/anthropic/llm";

The package depends on the official @anthropic-ai/sdk, which is installed with it.

Prerequisites

  • An Anthropic account and an API key from the Anthropic Console.
  • Pass the key as apiKey. The examples read it from ANTHROPIC_API_KEY.

AnthropicLLMService

Configuration

Prop

Type

apiKey is required even when you pass your own client, which doesn't use it.

Settings

Runtime-updatable settings, passed as settings: new AnthropicLLMService.Settings({...}). Any setting you leave out keeps the default below. null means the field is not sent, so Anthropic uses its own default.

SettingTypeDefaultDescription
modelstring"claude-sonnet-4-6"Claude model id.
systemInstructionstring | nullnullSystem prompt.
maxTokensnumber | null4096Maximum tokens to generate.
temperaturenumber | nullnullSampling temperature. Sent through extra_body.
topKnumber | nullnullTop-k sampling. Sent through extra_body.
topPnumber | nullnullTop-p sampling. Sent through extra_body.
enablePromptCachingbooleanfalseAdd cache-control markers to the system prompt and recent messages.
systemPromptCacheTtl"5m" | "1h" | nullnull (Anthropic: 5 minutes)Lifetime of the system prompt's cache entry when caching is on.
thinkingAnthropicThinkingConfig | nullnullThinking configuration. See below.
effort"low" | "medium" | "high" | "xhigh" | "max" | nullnullSent as output_config.effort. null uses the model's default.
useProviderThinkingDefaultbooleanfalseRun at Anthropic's default when neither thinking nor effort is set.
extraRecord<string, unknown>{}Extra request parameters, merged into the request.

frequencyPenalty, presencePenalty and seed exist on the base LLMSettings and default to null; the Anthropic API does not use them.

AnthropicThinkingConfig

Prop

Type

When the model thinks, the service emits LLMThoughtStartFrame, LLMThoughtTextFrame and LLMThoughtEndFrame. Claude 4.7 and later return empty thinking text unless display is "summarized".

Usage

llm.ts
import { AnthropicLLMService, AnthropicThinkingConfig } from "@pipedog/anthropic/llm";
import { LLMUpdateSettingsFrame } from "@pipedog/core/frames/frames";

const llm = new AnthropicLLMService({
  apiKey: process.env.ANTHROPIC_API_KEY ?? "",
  settings: new AnthropicLLMService.Settings({
    model: "claude-sonnet-4-6",
    systemInstruction: "You are a helpful voice assistant. Keep answers short.",
    maxTokens: 1024,
    enablePromptCaching: true,
  }),
});

llm.addEventHandler("on_completion_timeout", async () => {
  console.log("LLM completion timed out");
});

Adaptive thinking with readable thinking text:

const thinkingLlm = new AnthropicLLMService({
  apiKey: process.env.ANTHROPIC_API_KEY ?? "",
  settings: new AnthropicLLMService.Settings({
    model: "claude-opus-4-7",
    maxTokens: 16384,
    thinking: new AnthropicThinkingConfig({ type: "adaptive", display: "summarized" }),
  }),
});

Change settings mid-call with an LLMUpdateSettingsFrame:

// Queue it on the worker, or push it from a processor upstream of the service.
const update = new LLMUpdateSettingsFrame({
  delta: new AnthropicLLMService.Settings({ temperature: 0.3, maxTokens: 512 }),
});

Event handlers

Inherited from LLMService:

EventDescription
on_completion_timeoutA completion request timed out.
on_function_calls_startedFunction calls arrived and are about to run.
on_function_calls_cancelledOne or more running function calls were cancelled.

Notes

  • Consumes LLMContextFrame and emits LLMFullResponseStartFrame, LLMTextFrames and LLMFullResponseEndFrame. An LLMEnablePromptCachingFrame turns prompt caching on or off.
  • When neither thinking nor effort is set, the service sends the lowest thinking setting Anthropic documents for the model, for the fastest responses: thinking: { type: "disabled" } on most Claude 4 and 5 models, "between_tools" on Claude Sonnet 5.5, and effort: "low" on Claude Opus 5.5 and Fable models. It logs what it sent. A Claude model not in that list runs at Anthropic's default, with a warning. Set useProviderThinkingDefault: true to skip this.
  • Bedrock and Vertex model ids (us.anthropic.claude-sonnet-5-..., claude-sonnet-5@...) and dated snapshots are matched to their model's entry.
  • Models from the 4.6 generation on reject assistant prefill. For those, the service adds a trailing user message when the context ends with an assistant message.
  • runInference accepts a responseSchema. It is sent as output_config.format and needs a 4.5 model or later.
  • With retryOnTimeout: true, the first attempt is limited to retryTimeoutSecs (5 by default). If it times out, the request is retried once with no timeout.
  • The service logs a warning when Claude stops for a reason other than a normal end, such as max_tokens or a refusal. The text that arrived is still passed on.
  • Token usage metrics include cache creation, cache read and reasoning tokens.

Runtime notes

RuntimeWorksWhat it needs
Bun✅ yesNothing.
Node.js✅ yesNothing.
Deno✅ yesNothing.
Cloudflare Workers✅ yesNothing.

Generated from pipecat.runtimes and pipecat.compat in packages/anthropic/package.json: ✅ means the compat smoke test passes on that runtime.

  • @anthropic-ai/sdk is fetch-based and runs on Bun, Node, Deno and Cloudflare Workers.
  • client takes any object with a beta.messages.create(params, { signal }) method, such as AnthropicBedrock or AnthropicVertex from Anthropic's Bedrock and Vertex SDKs (not dependencies of this package).
  • The Python SDK's NOT_GIVEN has no JS counterpart: sampling settings and thinking use null for "not sent". An explicit null sampling value is left out of the request, where upstream sends JSON null.
  • The JS SDK has no extra_body option. pipedog merges extra_body into the request JSON itself, as the Python SDK does.
  • The JS SDK has no RequestTooLargeError; a 413 is recognized by its status.
  • Not ported: the deprecated AnthropicLLMService.InputParams and the model / params constructor arguments. Use settings.

pipedog is an unofficial community TypeScript port of Pipecat. It is not affiliated with or endorsed by Daily or the Pipecat project.

Portions adapted from the Pipecat documentation, Copyright (c) 2024–2025 Daily, BSD-2-Clause (see apps/docs/LICENSE-pipecat-docs).

On this page