All posts

Migrate Agent Builder ChatKit Before the November Shutdown

Migrate Agent Builder ChatKit Before the November Shutdown

If your product embeds a ChatKit interface backed by an Agent Builder workflow, the deadline is close: OpenAI says Agent Builder will no longer be available after November 30, 2026. The important distinction is that ChatKit itself is not going away. The hosted workflow path is in transition; new ChatKit apps and migrations should connect the interface to an agent you run on your own server.

That makes this a good week to inventory dependencies, export the workflow, and test the replacement in parallel—not to assume that a code export is a finished migration. Here’s a practical plan based on OpenAI’s current documentation, at the time of writing.

First, confirm what actually needs to move

OpenAI documents two ChatKit paths: a custom server integration, and an existing integration backed by an Agent Builder-hosted workflow. The latter is intended for existing users during the transition window. For new apps or migration, the guidance points to the advanced integration, where your server handles ChatKit requests and connects them to your own agent implementation.

If you use Agent Builder without ChatKit, the same retirement still matters, but your target may be an Agents SDK application or a ChatGPT Workspace Agent. The official migration guide offers those as separate choices. Pick based on where the workflow must run: use the SDK for an agent inside an application you build and deploy; consider a Workspace Agent for team-facing work managed in ChatGPT.

Before changing code, make a short inventory: workflow IDs, entry points, connected tools, authentication rules, data stores, file uploads, approval steps, and expected outputs. This becomes the checklist for checking whether the replacement preserves behavior.

Export the graph, then inspect it

In Agent Builder, open the workflow, choose Code, select Agents SDK, and export TypeScript or Python. Treat that export as a starting point, not a guarantee. OpenAI explicitly says migration does not convert every workflow graph or guarantee identical behavior. Triggers, connected apps, permissions, and some control flow need separate review.

Put the exported code in a branch and make the smallest runnable version first. Resolve dependencies, provide test configuration, and run the SDK quickstart checks in your own runtime. Keep secrets out of the export and source control. Recreate each external tool as an application-controlled integration, with explicit authorization and narrow permissions.

If the original graph relied on visual conditions or approvals, write down the behavior in plain language and turn it into tests. For example: “A refund above the configured threshold must be routed to a human; the agent may explain the policy but cannot issue the refund.” Tests should check both the normal path and the forbidden action.

Keep the ChatKit surface; move the server boundary

For a custom integration, ChatKit runs against a server endpoint you own. The ChatKit server receives requests, loads the thread, calls your agent, and streams events to the frontend. OpenAI’s Python integration uses a ChatKitServer implementation and can bridge agent output with the Agents SDK. You also own the persistence contracts for threads and messages; use durable storage for production rather than an in-memory store.

At the HTTP layer, the documented pattern is to process the request and return a streaming response when the server produces one. Keep this route behind your application’s authentication middleware. Pass the authenticated identity as server context and enforce tenant and resource access in your store and tools—not in the prompt alone.

from fastapi import FastAPI, Request, Response
from fastapi.responses import StreamingResponse

app = FastAPI()
server = MyChatKitServer(production_store)

@app.post("/chatkit")
async def chatkit_endpoint(request: Request):
    user = require_authenticated_user(request)
    result = await server.process(
        await request.body(),
        {"user_id": user.id, "tenant_id": user.tenant_id},
    )
    if isinstance(result, StreamingResult):
        return StreamingResponse(result, media_type="text/event-stream")
    return Response(content=result.json, media_type="application/json")

This illustrates the server boundary, not a complete drop-in app: MyChatKitServer, production_store, authentication, and StreamingResult must come from your implementation and installed ChatKit SDK. Follow the current SDK server guide for exact imports and types. Do not trust IDs or action payloads sent by the browser; validate them and check ownership before reading or changing records.

Preserve identity and permission checks

For OpenAI-hosted ChatKit sessions, the official guide requires a unique user value and says your server must authenticate the application user before creating the session. That principle applies equally to a self-hosted path: derive user and tenant identifiers from verified credentials, never from a client-provided chat field.

Review every tool as a privileged endpoint. Give read-only agents read-only tools. Check authorization on each operation, validate input schemas, and require confirmation for consequential actions. ChatKit widget actions are also untrusted client input: the actions guide explicitly warns that payloads arrive from the client. A hidden button or a restrictive instruction is not an access-control mechanism.

If users can upload files, migrate storage and deletion behavior too. The advanced integration guide describes a FileStore contract and direct or signed-URL uploads. Decide retention, access scope, previews, and cleanup before enabling uploads in production.

Test against the old behavior

Build a compact regression set from real, permission-cleared examples: successful requests, ambiguous prompts, missing records, tool errors, unauthorized access, and attempts to trigger restricted actions. Run those against the old workflow and your new agent where possible, then compare outcomes against explicit expected behavior—not just whether the final answer sounds plausible.

For code-first agents, OpenAI’s evaluation guide recommends inspecting traces while debugging: traces show model calls, tool calls, guardrails, and handoffs. Once the failure modes are understood, make a repeatable dataset and eval run so prompt or tool changes can be compared over time. Add human review for high-impact actions, and log enough metadata to investigate failures without retaining sensitive message contents unnecessarily.

A migration checklist for this week

  • Identify every production workflow and its owner; distinguish ChatKit-hosted workflows from standalone Agent Builder uses.

  • Export the SDK code and record integrations that did not come across automatically.

  • Choose the target runtime and implement server-side authentication, storage, tools, and approvals.

  • Route a small internal test group to the new path while keeping a rollback option.

  • Compare representative cases, test permissions and failure modes, and review traces.

  • Set a firm cutover date before November 30; verify the old dependency is removed and document operations.

The deadline is not a reason to rush a direct copy into production. ChatKit remains an option, but the application server becomes more important: it owns identity, persistence, tool authorization, and operational behavior. Export early, test the gaps, and migrate the workflow—not just its generated code.

Sources