Skip to content
Dynamic Workflow
Developer documentation/Tools and integrations

Dynamic Workflow

Let an Agent generate JavaScript that calls, combines, and summarizes its Session tools.

On this pageEnable Dynamic WorkflowExecution contractWhat the generated program looks likeWhich tools are availableClient function handoffLifetime, cancellation and recoveryIsolation and results

A Dynamic Workflow is a short JavaScript program the Agent writes for the current task. The program can call several tools, branch on results, and return a compact answer to the model. You configure the available tools; the model chooses how to combine them.

Dynamic Workflow is a Rebyte extension to the Agents API. The JavaScript example uses the official openai@7.15.0 package. CLI version 0.2.3 or later supports this tool declaration.

Enable Dynamic Workflow

Add { type: 'dynamic_workflow' } to the Agent's tools. It is opt-in and adds the model-facing run_code tool. It does not add any external tools or allocate a Session VM by itself.

This complete example connects to a public MCP server and asks the Agent to discover and call a tool inside one program. Set REBYTE_API_KEY to a key for your organization with tasks:read and tasks:write.

javascript
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.REBYTE_API_KEY,
  baseURL: 'https://api.rebyte.ai/v1',
  maxRetries: 0,
});

const stream = await client.beta.agents.sessions.create({
  agent: {
    model: 'gpt-5.6-luna',
    instructions: 'Use run_code exactly once: within that program, call tools.search_tools with server docs and query read_wiki_structure, then call tools.call_tool with the returned server/name and arguments { repoName: "modelcontextprotocol/python-sdk" } to read its actual output. Return { output: actualToolResult } and summarize it. Do not call MCP tools outside the program.',
    tools: [
      { type: 'dynamic_workflow' },
      {
        type: 'mcp',
        server_label: 'docs',
        connection_origin: 'service',
        required: true,
        allowed_tools: ['read_wiki_structure'],
        transport: {
          type: 'http',
          server_url: 'https://mcp.deepwiki.com/mcp',
        },
      },
    ],
  },
  input: 'Find the documentation structure for modelcontextprotocol/python-sdk.',
  stream: true,
});

let sessionId;
try {
  for await (const event of stream) {
    if (event.type === 'agent.session.created') sessionId = event.session.id;
    if (event.type === 'agent.session.turn.output_text.delta') {
      process.stdout.write(event.delta);
    }
    if (event.type === 'agent.session.turn.failed' ||
        event.type === 'agent.session.failed') {
      throw new Error(JSON.stringify(event));
    }
  }
} finally {
  if (sessionId !== undefined) {
    await client.beta.agents.sessions.delete(sessionId);
  }
}

The official TypeScript types do not include dynamic_workflow. For typed code, use the official client’s post() method with an explicit response type and OpenAI-Beta: agents=v1, or configure the saved Agent through the CLI and reference its ID. The JavaScript example above sends the extension without modifying the SDK.

The SDK sets OpenAI-Beta: agents=v1 automatically. Raw HTTP requests need that header and Authorization: Bearer <REBYTE_API_KEY>. The same tool declaration works on saved Agents and Session overrides. An explicit Session agent.tools array replaces the entire saved tool list; include both dynamic_workflow and the tools it should use.

With Rebyte CLI 0.2.3 or later, a saved Agent manifest can include:

toml
model = "gpt-5.6-luna"
instructions = "Use Dynamic Workflow to combine web searches sequentially."

[[tools]]
type = "dynamic_workflow"

[[tools]]
type = "web_search"

Execution contract

  1. The Agent calls run_code({code}) with an async JavaScript function.
  2. The program calls configured tools as await tools.NAME(arguments). Await each call before making the next one; parallel tool calls are not supported.
  3. Server tools execute on Rebyte. Application functions pause the program and appear in the Session's required_actions.
  4. Your application supplies a function result using the normal Session events endpoint. The same program continues with that result.
  5. The program's return value becomes the run_code result. The Agent can then answer or continue its Turn.

The program uses the Session's selected model and tools. Enabling Dynamic Workflow adds no credentials or permissions. Ordinary direct tool calls remain available.

What the generated program looks like

For the MCP configuration above, a program could be:

javascript
async () => {
  const matches = await tools.search_tools({
    server: 'docs',
    query: 'read_wiki_structure',
    limit: 5,
  });
  const match = matches.find(tool => tool.name === 'read_wiki_structure');
  if (!match) throw new Error('The wiki tool is unavailable');

  const result = await tools.call_tool({
    server: match.server,
    name: match.name,
    arguments: { repoName: 'modelcontextprotocol/python-sdk' },
  });
  return result;
}

tools.call_tool returns an object with output containing the MCP result and error: null on success. Tool failures reject the call. For example, text content is under result.output.content.

The SDK normalizes and parses the source before execution. Syntax errors and tool errors are returned to the Agent as execution errors. Tool arguments are checked by the existing tool handlers. These checks do not prove that a valid program solves the user's task correctly.

A Session with an openai_hosted environment also exposes its command, stdin, patch and image tools. Commands operate in that Session's environment; its files follow the normal environment lifecycle. They survive the end of an individual program.

Which tools are available

Tool categoryAvailable inside the programConfiguration
Commands, stdin, patches, imagesYesSession has a managed environment.
MCP discovery, calls, and resourcesYesCorresponding MCP connections are configured for this Session. Server allowlists and credential rules still apply.
Web searchYesweb_search is configured in live mode.
Application/client functionsYesDirectly available functions use normal required_actions and client tool results.
Client function discovery (tool_search)NoRemains in the outer Agent loop.
run_code itselfNoA program cannot recursively start another Dynamic Workflow through this tool.

A Dynamic Workflow does not automatically get the platform's complete tool catalog. Adding the feature alone exposes no new commands, connectors, or customer credentials. Ordinary direct tool calls remain available alongside run_code.

Deferred application functions must first be discovered by the Agent before they are available inside a program. A configured MCP tool or application function may call another model; there is no implicit call_model helper.

Client function handoff

For a configured function named get_number, the program may contain:

js
async () => {
  const number = await tools.get_number({ account: 'account-123' });
  return { doubled: number * 2 };
}

Read required_actions from GET /v1/agents/sessions/:sessionId, or observe agent.session.requires_action. Execute the requested function in your application and submit the exact turn_id and call_id:

http
POST /v1/agents/sessions/:sessionId/events
Authorization: Bearer <organization-api-key>
OpenAI-Beta: agents=v1
Idempotency-Key: number-result-123
Content-Type: application/json

{
  "events": [{
    "type": "agent.session.input.tool_result",
    "turn_id": "turn_...",
    "call_id": "call_...",
    "success": true,
    "output": "21"
  }]
}

Submit a nested function result in its own request, with exactly one event. Do not combine it with messages, cancellation or other results. To report a failure, use success: false and an error string instead of output. The program can catch that error; an uncaught error fails run_code and returns the failure to the Agent. The Agent may continue or choose another action.

Keep the same Idempotency-Key and identical body when retrying a submission. A conflicting key, wrong Turn, stale call or expired result is rejected with 409. Only execute calls listed in required_actions: the outer run_code Item itself is server-executed and does not ask your application for a result.

Lifetime, cancellation and recovery

The enclosing Turn waits while its program is running or waiting for a function. A program finishing does not finish the Turn: the Agent receives its result and continues. Cancelling the Turn also cancels its program. Cancellation is asynchronous and does not undo completed external actions. Disconnecting an HTTP request or event stream does not cancel execution.

BoundaryContract
Waiting for one application functionUp to 24 hours from that call's pause
A later function in the same programA new 24-hour waiting deadline
One active execution segment, before completion or the next pauseAt most 60 seconds; client waiting is outside this limit
Whole ordinary Turn or whole programNo separate fixed total lifetime; 24 hours is not a total runtime allowance
Scheduled TurnThe Schedule's timeout_seconds also covers preparation, execution and waiting
Program sourceAt most 32,768 JavaScript string code units

A pending call survives service restarts. Resume with its existing IDs rather than submitting the original prompt again. An expired nested wait fails the program and returns an error to the Agent. An ordinary direct function wait has the separate Turn timeout behavior.

When continuing after a pause, completed calls return their recorded results. JavaScript computation may run again to reach the pending call, so call tools sequentially and capture nondeterministic values explicitly:

js
const requestId = await codemode.step('request-id', () => crypto.randomUUID());
const result = await tools.create_order({ request_id: requestId });

Use stable step names and JSON-compatible step values. Do not depend on an unrecorded random value or current time to choose tool arguments or call order. If an active execution fails with an ambiguous tool outcome, Rebyte does not blindly restart the program. Your application and tool providers remain responsible for idempotency of external side effects.

Isolation and results

Programs cannot directly use the network, filesystem, Node.js packages or subprocesses. External actions go through the configured tools, with the same organization, Session and tool permissions as ordinary calls. Tool credentials are never exposed to program source. Separate invocations do not share JavaScript globals; use an environment or your own service for persistent business data.

The outer run_code call is a function_call Item containing arguments.code. Nested application functions have their own call/result Items and required actions. Server calls inside the program are not separate public Session Items. Returning an image from a nested tool gives the program image data; it does not automatically attach it to the outer model's visual context.

For code you want to run repeatedly without an outer model, create a Workflow Agent. It has its own run resource, client-result endpoint, and explicit create, test and publish lifecycle.