Use an Agent from Any OpenAI Client

Every agent is a model behind an OpenAI-compatible endpoint: point an OpenAI SDK or a tool that takes a base URL at it, and the agent answers with its own tools, skills and knowledge.

Every agent in your workspace is also a model behind an OpenAI-compatible endpoint. Anything that speaks OpenAI's Chat Completions API can talk to it: the official openai SDKs, and tools that let you set a base URL. The agent answers as it does in Chat, with its own system prompt, model, tools, skills and knowledge bases.

The endpoint

WhereBase URL
Self-hostedhttp://localhost:3000/api/v1/openai — your SynapseOrch address and the web UI's port
SynapseOrch Cloudhttps://api.synapseorch.com/api/v1/openai

Authenticate with an API key as the Bearer token, which every OpenAI client sends when you give it the key.

MethodPathWhat it does
GET/modelsLists the agents the key may use, workflow agents included
GET/models/{id}One agent
POST/chat/completionsOne turn with the agent the model names; stream: true for SSE

Name the agent as the model

model is the agent's id or its exact name, in any case. GET /models lists both, so "model": "Support Bot" and "model": "agent_7f3a…" reach the same agent. An unknown name is a 404 with the code model_not_found.

Python

from openai import OpenAI

client = OpenAI(base_url="https://api.synapseorch.com/api/v1/openai", api_key="sk-syn-...")

reply = client.chat.completions.create(
    model="Support Bot",
    messages=[{"role": "user", "content": "Where is my order 4417?"}],
)
print(reply.choices[0].message.content)

JavaScript

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.synapseorch.com/api/v1/openai", apiKey: "sk-syn-..." });

const stream = await client.chat.completions.create({
  model: "Support Bot",
  messages: [{ role: "user", content: "Where is my order 4417?" }],
  stream: true,
});
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");

curl

curl https://api.synapseorch.com/api/v1/openai/chat/completions \
  -H "Authorization: Bearer sk-syn-..." \
  -H "Content-Type: application/json" \
  -d '{"model": "Support Bot", "messages": [{"role": "user", "content": "Hi"}]}'

The conversation is the request

OpenAI's API is stateless, and so is this endpoint: each request carries the whole conversation.

  • The earlier user and assistant messages are the agent's history.
  • The last message must be the user's: it is the turn the agent answers.
  • A system or developer message is added after the agent's own system prompt, as instructions from the calling app. The agent's own prompt comes first, and wins where the two disagree.
  • Nothing is saved as a conversation in Chat. Every turn appears in Runs › Logs, with the source openai.

What the agent decides, and what you cannot send

The agent's tools run on SynapseOrch's side, as they do in Chat. So a request cannot bring its own tools:

SentAnswer
tools, functions with any entries, or a tool_choice other than none or auto400, code tools_unsupported
A message with the tool or function role, or an assistant message with tool_calls400, code tools_unsupported
n above 1400
An image as an https:// URL400: send images inline, as data:image/…;base64,… URIs
temperature, top_p, max_tokens, seed and other sampling fieldsAccepted and ignored: the agent's own model settings apply

On a self-hosted install, images sent as data URIs reach an agent whose model reads images; one that cannot is a 400. On SynapseOrch Cloud, images are not accepted on this endpoint yet.

Streaming

With stream: true the answer arrives as chat.completion.chunk events while the agent's model writes it, ending with data: [DONE]. The first chunk carries the role, and the last carries finish_reason: "stop". Set stream_options: {"include_usage": true} for a final chunk with usage.

An agent often works in rounds: it calls a tool, reads the result and then answers. During a tool round the stream stays open with SSE comments, which every OpenAI client skips. Text a model writes before it calls a tool ("Let me look that up.") is sent as it comes, because a stream cannot take words back, and the answer that follows starts a new paragraph. A workflow agent's answer arrives in one piece when its workflow ends. A Team agent answers with its lead's final answer only; its members' work is not streamed.

The answer is not streamed when the model's provider does not stream (a CLI model, a local Hugging Face model). It then arrives whole, as one chunk.

When a person has to approve

An agent's tool policy can require a person to approve a call. A program calling the endpoint cannot press Approve, so the turn parks instead:

  • The answer says a person has been asked and someone will follow up, with finish_reason: "stop".
  • The response carries "synapse": {"status": "awaiting_approval", "approval_id": "…", "session_id": "…"}. OpenAI's SDKs keep unknown fields, so you can read it.
  • The bell asks the workspace's builders and admins, and the question also appears under Waiting on you. Approving there carries the turn on from where it stopped, and a second item says how it ended.
  • Nobody answering within 24 hours expires the call. It is not run.

A Team agent's member that needs approval parks the turn the same way, and the client is told the answer waits for a person.

Usage, billing and limits

Every answer has a usage block (and a streamed one has one when asked): the tokens of all the turn's model calls, with prompt_tokens_details.cached_tokens when a cache served some of the input.

On SynapseOrch Cloud a turn is billed as a chat turn: execution credits by its minutes, plus the model calls it makes. It is subject to the key's limits: 300 requests a minute, 60 turns started a minute, and 25 open streams. A workspace out of credits answers 402 with the code insufficient_quota, and a limit answers 429 with Retry-After.

Errors

Errors are in OpenAI's shape, so the SDKs raise their usual exceptions:

{"error": {"message": "The model 'gpt-4o' does not exist: …", "type": "invalid_request_error", "param": "model", "code": "model_not_found"}}

A model failure in the middle of a stream is an error event, then [DONE]. Its message says what kind of failure it was (a provider out of credit, a rate limit, a provider that could not be reached) and never quotes the provider.

On this page