Tools

Let Olive call your functions, or search your vector stores, in a Responses request.

Define a function tool, run it in your code, and send the result back so Olive can finish its answer. Send tools with POST /responses.

When to use it

  • A value must come from your code, not from the model's text. For example, a BMI calculated from weight and height.
  • Olive should search your vector store with file_search.
Tool typeWho runs itStatus
functionYour codeAvailable
file_searchAvey, inside the requestAvailable
web_searchAveyComing soon. Returns 400 for now. See Web search.
mcpNoneNot available. Returns 400.

Every other tool type returns 400.

The SDK samples assume the client from the Quickstart.

Define a function

Describe the function with a name and a JSON schema. Olive never runs it. It asks for a call when it needs the result.

curl https://api.avey.ai/llm/responses \
  -H "Authorization: Bearer $AVEY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "olive",
    "input": "Calculate the BMI for a patient who weighs 82 kg and is 1.75 m tall.",
    "tools": [{
      "type": "function",
      "name": "calculate_bmi",
      "description": "Body mass index from weight in kilograms and height in metres.",
      "parameters": {
        "type": "object",
        "properties": {
          "weight_kg": { "type": "number" },
          "height_m": { "type": "number" }
        },
        "required": ["weight_kg", "height_m"]
      }
    }]
  }'

The Go samples reuse the Quickstart client. Add the imports each sample uses.

Return the result

When Olive wants the function, output holds a function_call item. Its arguments is a JSON string. Run the function, then send the result as a function_call_output item with the same call_id. Chain it to the response that asked for the call, and send tools again.

import json

call = next((item for item in response.output if item.type == "function_call"), None)

if call is not None:
    args = json.loads(call.arguments)
    result = {"bmi": round(args["weight_kg"] / args["height_m"] ** 2, 1)}

    response = client.responses.create(
        model="olive",
        previous_response_id=response.id,
        input=[{
            "type": "function_call_output",
            "call_id": call.call_id,
            "output": json.dumps(result),
        }],
        tools=tools,
    )

print(response.output_text)

Olive can ask for more than one call, or for another call after your result. Loop until a response has no function_call item.

Arguments are model output

Olive writes the arguments as it writes any text. They can be malformed JSON, miss a required field, or carry a plausible wrong value. Validate them against your schema and check clinical values for range. A function that changes a record, places an order or sends a message needs a clinician's confirmation, not only Olive's request.

Pass file_search with the IDs of the stores to search. Avey runs the search inside the request, so your code does not answer a call.

response = client.responses.create(
    model="olive",
    input="What is the recommended first-line antiplatelet therapy?",
    tools=[{"type": "file_search", "vector_store_ids": [store.id]}],
)

Only stores you own are searched. Citations come back as file_citation annotations on the output text. See Vector stores.

Errors

StatusMessageCause
400tool type "<type>" is not availableA tool type other than function or file_search, such as web_search or code_interpreter.
400unknown tool "<label>"; send only the server_label of a tool you have access toAn mcp tool.
400'tools' must be sent once.The request body has two tools keys.

Things to know

  • Send tools on POST /responses.
  • Function tools on Chat Completions are passed to Olive as sent, but they are untested. Use POST /responses for tools.
Last updated