JournalEngineering

Field guide / 6 min read

Programmatic tool calling in GPT-5.6: when JavaScript should orchestrate your tools

A practical guide to routing bounded, tool-heavy work through GPT-5.6 Programmatic Tool Calling without losing evidence, approvals, or control.

Aug 23, 20266 min readBy ISH Team
Programmatic tool calling in GPT-5.6: when JavaScript should orchestrate your tools
Advertisement

Programmatic tool calling in GPT-5.6: when JavaScript should orchestrate your tools

Most tool-using agents work one call at a time. The model chooses a tool, your application runs it, and the result goes back to the model for the next decision. That exchange is worth keeping when each result can change the plan. For a job such as "fetch these records, remove duplicates, total the values, and return five rows," it adds turns without adding judgment.

GPT-5.6 adds Programmatic Tool Calling (PTC) to the Responses API for that second kind of work. The model writes JavaScript that coordinates eligible tools inside an OpenAI-hosted runtime. The program can run calls in parallel, use conditions and loops, and reduce bulky intermediate results before the model writes its answer.

Ordinary function calling still handles work that needs model judgment. PTC gives predictable stages a separate route through code.

What runs where

The generated program runs in a fresh, isolated V8 runtime. It supports JavaScript and top-level await, but it is not Node.js. There is no package installation, direct network access, general filesystem, subprocess execution, console, or persistent JavaScript state. The program reaches outside the runtime only through tools that your request permits.

Your application still executes client-owned functions. If the program calls get_inventory, the Responses API returns a function_call item. Your code runs the implementation and sends back a function_call_output. The hosted runtime then resumes the waiting program.

The model can compose the workflow without acquiring an unlisted network client or an unrestricted shell. Tool definitions remain the capability boundary, which makes the split useful for security reviews and debugging. Our least-privilege checklist for AI agent tools covers how to keep that boundary narrow.

The task-shape test

PTC fits a bounded stage where ordinary code can turn several results into one smaller structured result. Good candidates include:

  • filtering a set of records against fixed rules
  • joining inventory and demand by SKU
  • ranking candidates with a documented score
  • removing duplicates by a stable identifier
  • validating that every required field is present
  • aggregating counts, totals, or status values

Use direct tool calls when one lookup is enough, when the model must interpret each result before choosing the next query, or when an action needs approval. Direct calls are also safer for final citation checks and native artifacts unless the program preserves everything the final answer must show.

Call count alone is a poor test. Ten lookups may need direct calls if every answer can send the investigation in a new direction. Two calls may suit PTC when their outputs are large and a deterministic join removes most of the data.

Configure the boundary explicitly

Add the hosted programmatic_tool_calling tool, then opt individual tools into program access with allowed_callers:

const tools = [
  {
    type: "function",
    name: "get_inventory",
    description: "Return inventory for one SKU.",
    parameters: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
      additionalProperties: false,
    },
    output_schema: {
      type: "object",
      properties: {
        sku: { type: "string" },
        available_units: { type: "number" },
      },
      required: ["sku", "available_units"],
      additionalProperties: false,
    },
    allowed_callers: ["programmatic"],
  },
  { type: "programmatic_tool_calling" },
];

allowed_callers can permit direct calls, programmatic calls, or both. If you grant both, assign each route to a specific stage in the prompt. An unclear boundary can lead the model to switch routes or repeat work.

The output_schema is just as important as the input schema. Generated JavaScript needs to know which fields a tool returns and their types. Document error behavior too. If the return shape cannot be known before the call, use a direct call so the model can inspect it.

Give the program an operating contract

"Use PTC efficiently" is too vague. State the bounded stage, eligible tools, output shape, evidence fields, concurrency rules, retry limit, and stopping condition. Keep writes and approval-sensitive steps outside the program.

For an inventory check, the instruction could say:

Use Programmatic Tool Calling only to read inventory and demand.
Fetch both records concurrently. Return JSON with sku, available_units,
requested_units, and shortage_units. Retry a transient failure once.
Do not call tools that change inventory. Use a direct tool call for any
write after the user approves it.

The generated code now has a small, testable job. Missing evidence should produce a structured failure instead of a plausible-looking total.

Handle every response item

PTC uses the standard Responses API object, but the output array can contain several related item types:

  • program contains the generated JavaScript, its call_id, and replay state.
  • function_call describes a client-owned tool invocation and links back through caller.caller_id.
  • program_output contains the program result and a completed or incomplete status.
  • message contains the final assistant response.

When returning a function result, preserve both the original call_id and caller. With store: false, replay every output item, including program and reasoning items, before adding your function outputs. A program may pause more than once, so continue until the response includes a final message.

A valid program_output does not guarantee a complete answer. The final message is a separate output and can still omit a required field or caveat, so test both layers.

Measure the result that users receive

Compare direct calling and PTC on the same representative tasks. Track task success, answer completeness, required evidence, total tokens, latency, cost, calls, turns, and retries. Fewer turns are not a win if the reduction step drops a citation or hides a failed record.

PTC can also reduce the amount of intermediate tool data that reaches later model turns. That makes it relevant to the context-budget strategy for long-running agents: keep raw data in the bounded program, return the evidence the answer needs, and avoid hauling an entire result set through the conversation.

OpenAI says the hosted runtime adds no container charge, though normal model tokens and tool usage still apply. PTC supports Zero Data Retention workflows, but store: false alone does not enable ZDR. The organization or project must already be eligible, and the complete request, including tools and third-party services, determines retention.

If you expose models through api.ish.chat, keep this orchestration logic in your application rather than assuming every provider implements the same response items. PTC is an OpenAI Responses API feature, and a provider-neutral layer should treat it as an explicit capability.

A rollout checklist

  1. Pick one read-only stage with predictable control flow.
  2. Define strict input and output schemas for every eligible tool.
  3. Permit programmatic access only to the tools that stage needs.
  4. Specify output evidence, stop conditions, concurrency, and retries.
  5. Preserve call_id, caller, program items, and reasoning items in the continuation loop.
  6. Test program_output and the final message separately.
  7. Compare the result against a direct-calling baseline before expanding usage.

Use Programmatic Tool Calling when code can compress mechanical tool work while leaving judgment and authorization with the model and user.

Sources

#GPT-5.6#OpenAI API#tool calling#AI agents#JavaScript
Advertisement

Keep reading

Related stories

Browse the archive