Pinecall

Hot-Reload

Change voice, language, prompt, tools — even during an active call.

This isn't a power-user feature you'll use rarely. It's the foundation of how Pinecall handles real-world conversation: switching languages when the user does, injecting CRM context when the call connects, swapping voices for different contexts.

The three scopes#

ScopeMethodAffects
Agent defaultspc.agent("id", config)All future calls
Agent hot-reloadagent.configure(updates)Updates defaults, future calls
Session (mid-call)call.configure(opts)This call only
Prompt (mid-call)call.setPrompt(text)This call's system prompt
Template varscall.setPromptVars(vars)This call's {{var}} values
Contextcall.addContext(text)Appended after prompt

Updating the agent's defaults#

agent.configure() updates the agent's defaults at runtime. Changes take effect on all future calls — existing calls keep their current config.

// Switch the default voice to French
agent.configure({ voice: "elevenlabs:frenchVoiceId", language: "fr" });

// Upgrade to a bigger model
agent.configure({
  llm: { provider: "openai", model: "gpt-4.1", enabled: true, prompt: "..." },
});

// Swap STT providers
agent.configure({ stt: "gladia" });

No REST call needed. agent.configure() uses the existing WebSocket — changes propagate to the server instantly.

Changing a live call#

call.configure() changes the active call only. Other calls on the same agent are unaffected.

// User asks for Spanish mid-conversation
call.configure({ voice: "elevenlabs:spanishVoiceId", language: "es" });
call.reply("¡Claro! Ahora hablo en español.");

The next TTS the bot produces uses the new voice. The next STT transcription uses the new language.

Prompt template variables#

Define a prompt with {{placeholders}}. The server resolves them before each LLM request. Built-in variables: {{date}}, {{time}}.

const agent = pc.agent("support", {
  llm: {
    provider: "openai",
    model: "gpt-4.1-mini",
    enabled: true,
    prompt: `You are {{agent_name}}, support agent at {{company}}.
Today is {{date}}, {{time}}.
Customer: {{customer_name}} ({{tier}} tier).`,
  },
});

agent.on("call.started", async (call) => {
  const customer = await lookupCaller(call.from);
  await call.setPromptVars({
    agent_name: "Nova",
    company: "Acme Corp",
    customer_name: customer.name,
    tier: customer.tier,
  });
  call.say(`Hi ${customer.name}! How can I help?`);
});

This pattern lets you keep a single canonical prompt but personalize it for every caller without rewriting the whole template.

Adding context mid-call#

Append dynamic context without replacing the prompt:

agent.on("call.started", async (call) => {
  const orders = await getRecentOrders(call.from);
  await call.addContext(
    `Recent orders:\n${orders.map((o) => `- ${o.id}: ${o.status}`).join("\n")}`,
  );
});

You can call addContext multiple times during a call — each call appends. Use it to inject anything that changes during the conversation: lookups, calculations, tool results you want the LLM to remember.

Replacing the prompt mid-call#

For more aggressive changes — escalation, new persona, mode switch — replace the whole prompt:

call.setPrompt(
  "You are now in escalation mode. Be more formal. Offer to connect to a human.",
);

The next LLM turn uses the new prompt. History is preserved.

Why this matters#

Most voice platforms treat the agent as a fixed config: you upload a JSON, the platform serves it, the end. Changes require redeploying or hitting a dashboard.

Pinecall treats the agent as live state inside your process. That changes what you can build:

  • Personalize every call — load CRM data on call.started, set prompt vars, the LLM knows about the customer from word one
  • Multi-language by default — detect language from the first user message, switch voice + STT accordingly
  • Phase transitionssetPrompt when the conversation enters a new mode (qualification → demo → close)
  • Live A/B testingagent.configure to flip the model or voice based on traffic without redeploying

What's next#