Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
databricks avatar

Supervisor Api Client Function Calling

  • 8 installs
  • 179 repo stars
  • Updated July 28, 2026
  • databricks/app-templates

supervisor-api-client-function-calling skill documents Add client-side function tools to the Supervisor API.

About

supervisor-api-client-function-calling skill documents Add client-side function tools to the Supervisor API. Use when: (1) User wants to mix Python callables with hosted tools, (2) User asks about function tools with Supervisor API, (3) User needs to execute custom business logic alongside hosted tool calls.. name: supervisor-api-client-function-calling description: "Add client-side function tools to the Supervisor API. Use when: (1) User wants to mix Python callables with hosted tools, (2) User asks about function tools with Supervisor API, (3) User needs to execute custom business logic alongside hosted tool calls."

  • Add client-side function tools to the Supervisor API.
  • Platform-specific setup patterns for supervisor-api-client-function-calling.
  • Evidence-backed steps from upstream SKILL.md.
  • When-to-use criteria for supervisor-api-client-function-calling versus alternatives.

Supervisor Api Client Function Calling by the numbers

  • 8 all-time installs (skills.sh)
  • Ranked #12,321 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 4, 2026 (Skillselion catalog sync)
At a glance

supervisor-api-client-function-calling capabilities & compatibility

Capabilities
supervisor api client function calling quick sta · supervisor api client function calling when to u · supervisor api client function calling integrati
Works with
databricks
Use cases
orchestration
From the docs

What supervisor-api-client-function-calling says it does

**Tool declaration constraints:**
SKILL.md
`name` must match `^[a-zA-Z0-9_-]{1,64}$` (no dots, spaces, or other characters).
SKILL.md
npx skills add https://github.com/databricks/app-templates --skill supervisor-api-client-function-calling

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs8
repo stars179
Last updatedJuly 28, 2026
Repositorydatabricks/app-templates

How do I use supervisor-api-client-function-calling correctly?

Add client-side function tools to the Supervisor API. Use when: (1) User wants to mix Python callables with hosted tools, (2) User asks about function tools with Supervisor API, (3) User needs to exec

Who is it for?

Teams implementing supervisor-api-client-function-calling workflows from the catalog.

Skip if: Skip when requirements clearly match a different specialized stack.

When should I use this skill?

User asks about supervisor-api-client-function-calling, add client-side function tools to the supervisor api. use when: (1) user wants to mix pyth.

What you get

Working supervisor-api-client-function-calling setup with validated configuration and next steps.

Files

SKILL.mdMarkdownGitHub ↗

Client-Side Function Tools with the Supervisor API

Client-side function tools (type: "function") let you declare callables your application executes — business logic, calls to your own database, external APIs, etc. The Supervisor API returns the pending function_call, your app executes the function, and you resume the conversation by appending a function_call_output to the next request's input.

Tool declaration constraints:

  • name must match ^[a-zA-Z0-9_-]{1,64}$ (no dots, spaces, or other characters).
  • parameters must be a JSON Schema object, or omitted.

Continuation pattern: the Supervisor API uses full-history echo. On each subsequent request, append the prior response.output to your input list, then add function_call_output items for every client function_call you executed. (previous_response_id chaining is on the roadmap.)

Function-Only Flow

The simplest case: a single client-side function tool, no hosted tools.

import json
from databricks.sdk import WorkspaceClient
from databricks_openai import DatabricksOpenAI

client = DatabricksOpenAI(workspace_client=WorkspaceClient(), use_ai_gateway=True)
MODEL = "databricks-claude-sonnet-4-5"

GET_WEATHER = {
    "type": "function",
    "name": "get_weather",
    "description": "Get current weather for a location.",
    "parameters": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
        "additionalProperties": False,
    },
}

def run_get_weather(args):
    return json.dumps({
        "location": args["location"],
        "temp_c": 18,
        "condition": "sunny",
    })

CLIENT_TOOLS = {"get_weather": run_get_weather}
TOOLS = [GET_WEATHER]

input_list = [{"role": "user", "content": "What's the weather in Paris?"}]

# Turn 1 — model emits a function_call
resp = client.responses.create(model=MODEL, input=input_list, tools=TOOLS)

# Echo the model's turn into history, then execute pending client function_calls
input_list += [item.model_dump() for item in resp.output]
for item in resp.output:
    if item.type == "function_call" and item.name in CLIENT_TOOLS:
        args = json.loads(item.arguments)
        input_list.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": CLIENT_TOOLS[item.name](args),
        })

# Turn 2 — model produces the final assistant message using the tool result
final = client.responses.create(model=MODEL, input=input_list, tools=TOOLS)
print(final.output_text)

Streaming Function-Only Flow

The same pattern works with streaming. Collect the full response from the stream, execute pending function calls, then resume with a second streamed call.

import json
from databricks.sdk import WorkspaceClient
from databricks_openai import DatabricksOpenAI

client = DatabricksOpenAI(workspace_client=WorkspaceClient(), use_ai_gateway=True)
MODEL = "databricks-claude-opus-4-6"

GET_WEATHER = {
    "type": "function",
    "name": "get_weather",
    "description": "Get the current weather for a location.",
    "parameters": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
        "additionalProperties": False,
    },
}

def run_get_weather(args):
    return json.dumps({
        "location": args["location"],
        "temp_c": 18,
        "condition": "sunny",
    })

CLIENT_TOOLS = {"get_weather": run_get_weather}
TOOLS = [GET_WEATHER]

input_list = [{"role": "user", "content": "What's the weather in Paris?"}]

# ── First streamed call: collect the response containing function_call(s) ──
stream = client.responses.create(
    model=MODEL,
    tools=TOOLS,
    input=input_list,
    stream=True,
)

first_response = None
for event in stream:
    if event.type == "response.completed":
        first_response = event.response

# ── Execute pending client function calls and echo into history ──
input_list += [item.model_dump() for item in first_response.output]
for item in first_response.output:
    if item.type == "function_call" and item.name in CLIENT_TOOLS:
        args = json.loads(item.arguments)
        input_list.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": CLIENT_TOOLS[item.name](args),
        })

# ── Second streamed call: model produces the final answer ──
followup = client.responses.create(
    model=MODEL,
    tools=TOOLS,
    input=input_list,
    stream=True,
)

for event in followup:
    if event.type == "response.completed":
        print(event.response.output_text)

Mixed Flow: Hosted UC Function + Client-Side Function Tool

When you combine hosted tools (e.g. uc_function) with client-side function tools, the server executes hosted tool calls and returns their results in response.output alongside any pending client-side function_call items. Your code only needs to execute the client-side calls — skip hosted ones.

import json
from databricks.sdk import WorkspaceClient
from databricks_openai import DatabricksOpenAI

client = DatabricksOpenAI(workspace_client=WorkspaceClient(), use_ai_gateway=True)
MODEL = "databricks-claude-sonnet-4-5"

GET_WEATHER = {
    "type": "function",
    "name": "get_weather",
    "description": "Get the current weather for a location.",
    "parameters": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"],
        "additionalProperties": False,
    },
}

def run_get_weather(args):
    return json.dumps({
        "location": args["location"],
        "temp_c": 18,
        "condition": "sunny",
    })

CLIENT_TOOLS = {"get_weather": run_get_weather}

uc_function = {"type": "uc_function", "uc_function": {"name": "system.ai.python_exec"}}

TOOLS = [GET_WEATHER, uc_function]

input_list = [
    {
        "role": "user",
        "content": (
            "Run python_exec to get 15th fibonacci number "
            "AND call get_weather for Paris. Use both tools."
        ),
    }
]

# ── First call: server executes hosted UC function; client-side get_weather is pending ──
first = client.responses.create(
    model=MODEL,
    tools=TOOLS,
    input=input_list,
)

# Echo response.output back; only execute client-side function calls.
# Hosted calls (e.g. system__ai__python_exec) and their outputs are already
# in response.output — just echo them as conversation history.
input_list += [item.model_dump() for item in first.output]
for item in first.output:
    if item.type != "function_call":
        continue
    impl = CLIENT_TOOLS.get(item.name)
    if impl is None:        # hosted tool — server already ran it, skip
        continue
    args = json.loads(item.arguments)
    input_list.append({
        "type": "function_call_output",
        "call_id": item.call_id,
        "output": impl(args),
    })

# ── Second call: model sees both tool results and produces the final answer ──
final = client.responses.create(
    model=MODEL,
    tools=TOOLS,
    input=input_list,
)
print(final.output_text)

Mixed Flow: MCP Approval + Client-Side Function Tools

When you mix MCP-approval-gated hosted tools with client-side function tools, both kinds need handling each turn. The supervisor serializes turns (one tool at a time per response), so a given response will have at most one kind pending — but the client loop has to cover both.

import json
from databricks.sdk import WorkspaceClient
from databricks_openai import DatabricksOpenAI
from openai.types.responses.response_output_item import McpApprovalResponse

client = DatabricksOpenAI(workspace_client=WorkspaceClient(), use_ai_gateway=True)
MODEL = "databricks-claude-sonnet-4-5"

# Hosted MCP server (require_approval flow) + client-side function tool
TOOLS = [
    {
        "type": "uc_connection",
        "uc_connection": {
            "name": "<uc-connection-name>",
            "description": "Searches the web for current information",
        },
    },
    {
        "type": "function",
        "name": "get_weather",
        "description": "Get current weather for a location.",
        "parameters": {
            "type": "object",
            "properties": {"location": {"type": "string"}},
            "required": ["location"],
            "additionalProperties": False,
        },
    },
]

def run_get_weather(args):
    return json.dumps({
        "location": args["location"],
        "temp_c": 18,
        "condition": "sunny",
    })

CLIENT_TOOLS = {"get_weather": run_get_weather}


def has_pending(resp, client_tools):
    """Any pending client-side work in this response?"""
    return any(
        o.type == "mcp_approval_request"
        or (o.type == "function_call" and getattr(o, "name", None) in client_tools)
        for o in resp.output
    )


def execute_pending(prev_resp, input_list, client_tools):
    """Echo response.output + append the user-side responses for any pending items."""
    next_input = list(input_list) + [item.model_dump() for item in prev_resp.output]
    for item in prev_resp.output:
        if item.type == "mcp_approval_request":
            approval = McpApprovalResponse(
                id=item.id,
                approval_request_id=item.id,
                approve=True,
                type="mcp_approval_response",
            )
            next_input.append(approval.to_dict())
        elif item.type == "function_call":
            impl = client_tools.get(getattr(item, "name", None))
            if impl is None:
                # Hosted-tool function_call — server already executed it; do not run locally.
                continue
            args = json.loads(item.arguments)
            next_input.append({
                "type": "function_call_output",
                "call_id": item.call_id,
                "output": impl(args),
            })
    return next_input


input_list = [
    {
        "type": "message",
        "role": "user",
        "content": (
            "Search the web for what Databricks is, "
            "then call get_weather for Paris and summarize both."
        ),
    }
]

resp = client.responses.create(model=MODEL, input=input_list, tools=TOOLS)
while has_pending(resp, CLIENT_TOOLS):
    input_list = execute_pending(resp, input_list, CLIENT_TOOLS)
    resp = client.responses.create(model=MODEL, input=input_list, tools=TOOLS)

print(resp.output_text)

What's happening per turn (typical):

  • Turn 1 — model picks the search tool first → output: [..., mcp_approval_request]
  • Turn 2 (after approval) — server executes MCP, returns its function_call_output, model decides to call get_weather → output: [..., function_call_output, function_call]
  • Turn 3 (after client executes get_weather) — model has both tool results and writes the final answer → output: [message]

The exact number of turns depends on the prompt and on retry behavior (e.g., the MCP server may reject the model's first-attempt arguments and the model self-corrects on the next turn). The drain loop handles all cases — it keeps iterating until response.output has no pending items.

Why client tools must be filtered by name: hosted tools (UC functions, executed MCP calls) also emit items with type: "function_call" in response.output. These represent work Databricks already executed; you must NOT execute them locally. Filter by client_tools.get(item.name) and skip when None — the hosted function_call is already paired with its function_call_output in the same response and just needs to be echoed back as conversation history.

Troubleshooting

"function tool 'name' must match ^[a-zA-Z0-9_-]{1,64}$" — The name field on a type: "function" tool contains invalid characters (dots, spaces, etc.) or is longer than 64 chars. Rename the tool.

"No tool output found for function call ." — A prior client-side function_call in the input list has no matching function_call_output. Append the output before resuming.

"No tool call found for function call output with call_id ." — A function_call_output in input references a call_id no prior item introduced. Echo the originating function_call (or mcp_approval_request) in the input list.

Related skills

FAQ

What does supervisor-api-client-function-calling do?

supervisor-api-client-function-calling skill documents Add client-side function tools to the Supervisor API.

When should I use supervisor-api-client-function-calling?

User asks about supervisor-api-client-function-calling, add client-side function tools to the supervisor api. use when: (1) user wants to mix pyth.

Is this skill safe to install?

Review the Security Audits panel on this page before installing in production.

AI & Agent Buildingagentsautomation

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.