Is it fine to send arbitrary values for the "id" fields in the API, during a conversation?

I am trying to build an abstraction layer that can be used with any AI provider. That abstraction layer should ideally not contain any provider specific data, so it’s rather tricky to store the id of the various items (messages, reasoning, tool calls etc.), because that id has to work with other providers as well.

So right now what I am doing is generating a random UUID string and using that as the id for the items in the abstraction layer.

Then, when I want to continue a conversation, I parse the abstracted chat history back into OpenAI models and put the UUID as the “id” of the various items (prefixing it for things like function calls with “fc_”).

This does seem to work. The API is accepting those ids.

But I wanted to ask if this is fine to do or if this might just be a fluke/bug that it’s working?

I’m using the Responses API

Thanks!

A function call ID is not enforced on a stateless API call. It is used for pairing up the return message back to emitted call order of the preceding assistant tool_call output. Self-service IDs can do the same, for a conversation that was never even had with a real AI.

The exception is when you use a server-side conversation state, employing the Responses endpoint previous response ID. Then the ID attached to the assistant message is not under your control, but already awaiting an immediate tool return message item addition as input.

That likely completes your inquiry. Other IDs either reference real API objects, or are not information needing to be returned in chat.

You can see you would not make up your own:

  • vector store ID
  • file ID
  • previous response ID
  • returned code interpreter container ID
  • Responses prompt ID
  • Assistants’ assistant,thread, run ID
  • Batch job ID
  • fine-tuning
  • audio output id
  • etc

You can send your own string for:

  • end-user ID
  • caching match ID
  • metadata keys and fields
  • vector store file attribute keys and fields

and more cases I don’t need to illustrate further.

2 Likes

Thank you! That helps a lot. So my approach can actually work. I was worried about that.

Appreciate your thorough reply!

1 Like

Hm, I’ve discovered one problem. Apparently, I can’t set the reasoning output item id for myself. The API gives me a 400 response with the message: “Item with id ‘rs_4187A413-F319-4E88-A746-6E62120A2719’ not found.”

Maybe I’m misunderstand something, but shouldn’t this also be an id under my control? It’s just an item for the stateless version of the Responses API. Or is the reasoning actually part of the server side stuff, aka. I couldn’t “make up my own” reasoning summary and send it to the AI? I can’t find anything in the specification about this.

EDIT: Okay, so apparently I have had store set to true, which makes this maybe not entirely stateless? But when I set it to false, it wants the encrypted_content, but when I include that, it just says

The encrypted content for item rs_96075180-A54A-4700-9029-7C5DAF4E166A could not be verified.\

Is the proper id here maybe needed to decrypt the content? That would mean I have to store that reasoning id somehow in my abstraction layer

You are not allowed to see what the AI produces into its “reasoning” container.

You have to pointlessly reuse an ID that should already be a part of what’s in OpenAI’s previous_response_id state.

If doing self-management of conversation, you must use the encoded and only-when-requested encrypted reasoning part that OpenAI can decode back to the context input. Otherwise, you drop it and make a reasoning model re-think each time.

(preventing you from getting your full conversation and AI responses off of server-state and off of Responses endpoint, you are correct that they don’t return the encrypted reasoning without turning off store and stopping the logged collection.)

To have a successful reuse of the AI’s thinking item, it must be put back in the assistant previous response output list just as it was received. The document writers don’t clearly communicate per-model that this is put back in mostly around tool use to maintain flow, otherwise silently dropped.

It is sufficient to say you cannot make up a reasoning ID that you send, or place encrypted reasoning wrong, or damage the string. Responses will need an “input list” and “output list” supporting every type.

1 Like

Ah, okay yes, that’s where I had a twist in my logic.

This makes my entire “abstraction layer that is 100% provider agnostic” kind of impossible because obviously (which I only know realize) OpenAI wouldn’t want another provider getting access to the raw reasoning data, so it makes complete sense that this is “exclusive” to OpenAI with no way of abstracting it.

So I have to re-evaluate my approach. I can still have an abstraction layer whose public surface is identical for all providers, but each instance must be tied to one specific provider (with internal provider-specific metadata like the actual reasoning id from OpenAI) that cannot simply swap providers mid-conversation, unless it’s fine to lose reasoning items in the process.

I think that makes the most sense.

Thank you very much for your help!