Skip to main content
Polpo exposes an OpenAI-compatible chat completions endpoint. You can talk to any agent using the same format as the OpenAI API — streaming or non-streaming.

How it works

  1. You send a message to a specific agent via POST /v1/chat/completions
  2. The agent receives your message along with its system prompt, skills, identity, and memory
  3. The agent responds using its configured model and tools
  4. Conversation history is stored in a session for multi-turn chat

Streaming

curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "backend-dev",
    "messages": [
      { "role": "user", "content": "Explain how the auth module works" }
    ],
    "stream": true
  }'
The response is a standard SSE stream of OpenAI-compatible chunks:
data: {"choices":[{"delta":{"role":"assistant","content":"The auth"},"index":0}]}

data: {"choices":[{"delta":{"content":" module uses"},"index":0}]}

data: {"choices":[{"delta":{"content":" JWT tokens..."},"index":0}]}

data: [DONE]

Non-streaming

curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "backend-dev",
    "messages": [
      { "role": "user", "content": "Explain how the auth module works" }
    ],
    "stream": false
  }'

Sessions

Each conversation is tracked as a session. The response includes a x-session-id header containing the session ID. Without an x-session-id request header, a new session is always created. To continue an existing conversation, pass the session ID explicitly:
# First message — creates a new session
curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "agent": "dev", "messages": [{ "role": "user", "content": "Hello" }] }'
# Response header: x-session-id: sess_abc123

# Continue the conversation — pass the session ID
curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "x-session-id: sess_abc123" \
  -H "Content-Type: application/json" \
  -d '{ "agent": "dev", "messages": [{ "role": "user", "content": "Follow up" }] }'

# Force a new session even when a header is present
curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "x-session-id: new" \
  -H "Content-Type: application/json" \
  -d '{ "agent": "dev", "messages": [{ "role": "user", "content": "Fresh start" }] }'
There is no automatic session reuse. If you omit x-session-id, every request starts a new conversation. Your client is responsible for storing and passing the session ID.

SDK usage

Streaming

import { PolpoClient } from "@polpo-ai/sdk";

const client = new PolpoClient({
  baseUrl: "https://{project}.polpo.cloud",
  apiKey: "sk_live_...",
});

const stream = client.chatCompletionsStream({
  agent: "backend-dev",
  messages: [{ role: "user", content: "Refactor the payment module" }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

console.log("\nSession:", stream.sessionId);

Aborting

const stream = client.chatCompletionsStream({ agent: "dev", messages });
setTimeout(() => stream.abort(), 10_000); // cancel after 10s

Non-streaming

const response = await client.chatCompletions({
  agent: "backend-dev",
  messages: [{ role: "user", content: "Explain the auth flow" }],
});

console.log(response.choices[0].message.content);

What the agent receives

When you send a chat completion, the agent’s full context includes:
  1. System prompt — base Polpo prompt + agent’s systemPrompt field
  2. Identity — display name, title, tone, personality, responsibilities
  3. Skills — domain knowledge from assigned skills
  4. Memory — shared + agent-specific memory
  5. Tools — all tools from allowedTools
  6. Your messages — the conversation history

File attachments

To attach a file to a conversation, upload it to the workspace and reference it in your message.

1. Upload the file

curl -X POST https://{project}.polpo.cloud/api/v1/files/upload \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -F "file=@report.pdf" \
  -F "path=workspace"

2. Reference it in the message

Pass a file content part with the workspace path as file_id:
curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "coder",
    "messages": [{
      "role": "user",
      "content": [
        { "type": "text", "text": "Analyze this report" },
        { "type": "file", "file_id": "workspace/report.pdf" }
      ]
    }],
    "stream": true
  }'
The agent receives a reference to the file and uses its built-in tools to access the content. Images are analyzed visually, text files are read directly. Files live in the workspace filesystem and persist across messages in the same session.

Tool calls

Agents can use tools during the conversation (read files, run commands, fetch URLs, etc.). Most tool calls happen server-side — the agent executes them automatically and you receive the final response.

Client-side tools

Some tools require interaction with the user. These are client-side tools — the agent calls them, but instead of executing on the server, the tool call is returned to your client for handling. The built-in client-side tool is ask_user_question. When the agent needs clarification, it calls this tool with structured questions and options. Your client renders the questions, collects the user’s response, and sends it back. The flow:
  1. Agent calls ask_user_question — server returns finish_reason: "ask_user" with the questions
  2. Your client shows the question UI
  3. User responds
  4. Client sends the answer as a tool result message in the next request
  5. Agent continues with the answer
# Step 1: Agent responds with a tool call
# Response chunk:
{
  "choices": [{
    "delta": {
      "tool_calls": [{
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "ask_user_question",
          "arguments": "{\"questions\":[{\"id\":\"deploy-target\",\"question\":\"Where should I deploy?\",\"options\":[{\"label\":\"Staging\"},{\"label\":\"Production\"}]}]}"
        }
      }]
    },
    "finish_reason": "ask_user"
  }]
}

# Step 4: Send the answer back
curl -X POST https://{project}.polpo.cloud/v1/chat/completions \
  -H "Authorization: Bearer $POLPO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent": "coder",
    "messages": [
      {"role": "user", "content": "Deploy the app"},
      {"role": "tool", "tool_call_id": "call_abc123", "name": "ask_user_question", "content": "{\"answers\":[{\"questionId\":\"deploy-target\",\"selected\":[\"Staging\"]}]}"}
    ],
    "stream": true
  }'
The completions API is fully compatible with OpenAI client libraries. You can use the official openai Python/Node.js package by pointing it at your Polpo endpoint.