Key facts
| Endpoint | POST https://api.plugsky.com/v1/chat/completions |
| Request fields | tools (JSON-Schema definitions) and tool_choice (auto, none or a named function) |
| Response | message.tool_calls with function name and JSON-string arguments |
| Parallel calls | Multiple tool calls per turn are supported |
| Streaming | Tool calls stream with the completion |
| Model support | Capability varies by model — check the catalogue before choosing |
| Schema helper | The docs link a function-schema generator tool |
| Product status | Live |
TL;DR
- Tools are JSON-Schema functions; the model picks, your code executes.
- Append tool results with the matching tool_call_id and loop until a final answer.
- Design small, single-purpose functions with heavily described parameters.
- Validate arguments server-side before any side effect.
- Allowlist tools per agent and cap loop iterations.
How it works, step by step
- Write each tool as the smallest useful action with a clear name and description.
- Define parameters as JSON Schema with enums and required fields where possible.
- Send the tools array with tool_choice set to auto on chat completions.
- Parse tool_calls, validate arguments, and execute the function in a sandbox.
- Append one tool message per call with the same tool_call_id and the JSON result.
- Call the model again until it returns content and no tool calls.
- Log every tool call and result, and require human approval for irreversible actions.
Try it yourself
Open the function calling schema generator →
The request and response contract
Tools are declared inline with the messages. The model either answers or asks for a function, and the response tells you exactly which one and with what arguments:
tools = [{
"type": "function",
"function": {
"name": "get_invoice_status",
"description": "Look up the status of a customer invoice by ID",
"parameters": {
"type": "object",
"properties": {"invoice_id": {"type": "string"}},
"required": ["invoice_id"],
},
},
}]
resp = client.chat.completions.create(
model="plugsky-pro", messages=messages, tools=tools, tool_choice="auto")
msg = resp.choices[0].message
if msg.tool_calls:
call = msg.tool_calls[0]
args = json.loads(call.function.arguments)Arguments arrive as a JSON string. Parse defensively — models occasionally emit arguments your schema only loosely constrains.
Parallel calls and streaming
When a question needs two independent lookups, the model can return multiple entries in tool_calls in a single turn. Execute them concurrently, then return every result as its own tool message before the next call. This cuts round trips and latency on workflows like order-plus-shipping lookups.
With stream=True, tool-call deltas arrive in the stream alongside text. Accumulate argument fragments by index, then act once the stream finishes. The final chunk carries usage, which helps you meter tool-heavy conversations.
Schema design that reduces failures
- One action per function. A
manage_accounttool invites guessing;freeze_carddoes not. - Describe every parameter. The description is prompt surface — write it for the model, not for a human reviewer.
- Use enums and formats. Constrain country codes, currencies and date strings at the schema level.
- Return structured results. Small JSON objects with explicit error fields beat prose your parser must interpret.
- Limit the toolset. Accuracy degrades as tool count grows; expose only what the current task needs.
Guardrails before production
Function calling gives a model a path to your systems, so treat the execution layer as untrusted input. Validate every argument against the schema and against business rules, enforce authorization in the tool implementation — not in the prompt — and rate-limit per user. Never expose a tool that executes arbitrary code, SQL or shell commands; wrap read and write operations behind narrow, auditable endpoints. Require confirmation for anything that moves money, deletes data or sends external communications, and record the model, arguments, result and key ID for every call so audits can reconstruct the decision path. Scoped API keys and audit logs cover the platform side; the tool layer is yours to secure.
Honest comparison
| Capability | Plugsky function calling | Prompt-based JSON | Framework tool agents |
|---|---|---|---|
| Contract | JSON-Schema tools, structured tool_calls | Free text you parse | Framework abstractions |
| Parallel calls | Supported in one turn | Manual orchestration | Framework-dependent |
| Streaming | Tool calls stream with completion | Fragile | Usually supported |
| Validation | You validate arguments server-side | You validate everything | Framework helpers |
| Model choice | 30+ models behind one API | Same | Whatever you wire up |
| Status | Live | Live but brittle | Live on top of Plugsky |
Frequently asked questions
Is function calling available on every Plugsky model?
Capability varies by model in the 30+ model catalogue. Check the model card before standardising a workflow on it, and test your tool schemas against the exact model you plan to use.
How many tools can I pass?
There is no fixed small limit, but accuracy and latency degrade as the toolset grows. Keep the active list to the handful the current task needs and route by intent.
Can the model call several functions at once?
Yes. Parallel tool calls are supported; execute them concurrently and return one tool message per call with the matching tool_call_id before continuing.
Does streaming work with tool calls?
Yes. Tool-call deltas arrive in the stream; accumulate argument fragments by index and execute once the stream completes. The final chunk includes usage.
What happens if the model sends invalid arguments?
Your code must validate before executing. Parse the JSON string defensively, check required fields and enums, and return a structured error to the model so it can correct course.
Should tools be allowed to write data?
Only with explicit authorization checks inside the tool and human confirmation for irreversible actions. Prefer read tools; gate writes behind approval workflows and audit logging.
How is this different from the Assistants API?
Assistants and responses endpoints are coming soon on Plugsky. Function calling on chat completions is the live, portable way to build tool-using apps today.
Does function calling cost more?
Self-serve plans are flat monthly with fair-use usage rather than per-token billing, so tool-heavy loops do not create per-token charges. Token counts are still returned for observability.