Attaching vector store to a thread?

Per the API documentation for File Search, I see that:

You can also attach files as Message attachments on your thread. Doing so will create another vector_store associated with the thread, or, if there is already a vector store attached to this thread, attach the new files to the existing thread vector store.

It happens that, when I run my code , I end up with an Assistant that has a VectorStore attached to it, but when I try to create the Thread, this Vector Store isn’t attached to it.

Our BaseConversationHelper looks like this:

public abstract class BaseConversationHelper {
	protected SimpleOpenAI openAI;
	protected String assistantName, assistantInstructions;
	protected Assistant assistant;
	protected VectorStore vectorStore;
	protected Thread thread;

	public BaseConversationHelper() {
		super();
	}

	public BaseConversationHelper(SimpleOpenAI openAI, String assistantName, String assistantInstructions) {
		super();
		this.openAI = openAI;
		this.assistantName = assistantName;
		this.assistantInstructions = assistantInstructions;
	}

	public Assistant getAssistant() {
		if (this.assistant == null) { 
			Assistants assistants = openAI.assistants();
			
			Assistant existingAssistant = assistants
				.getList()
				.get()
				.find { Assistant assistant -> return assistant.getName() == this.assistantName };
				
			this.assistant = existingAssistant;
					
			if (existingAssistant == null) { 
				this.assistant = assistants
					.create(this.createRequest())
					.join();
				
				KeywordUtil.logInfo("Assistant was created with id: ${this.assistant.getId()} and name '${this.assistant.getName()}'");
			}
		}

		return this.assistant;
	}

	public AssistantRequest createRequest() {
		AssistantRequestBuilder builder = AssistantRequest.builder()
				.name(this.assistantName)
				.model("gpt-4o")
				.instructions(this.assistantInstructions)
				.tool(AssistantTool.fileSearch())
					.toolResources(ToolResourceFull.builder()
							.fileSearch(FileSearch.builder().vectorStoreId(this.vectorStore.getId()).build())
							.build())
				.temperature(0);
					

		if (this.functionExecutor != null)
			builder.tools(functionExecutor.getToolFunctions());

		return builder.build();
	}

	public Thread getThread() {
		if (this.thread == null) { 
			this.thread = openAI.threads()
				.create(ThreadRequest.builder().build())
				.join();
			
			KeywordUtil.logInfo("Thread created with id: ${this.thread.getId()}")
		}

		return this.thread;
	}

	public FunctionExecutor getFunctionExecutor() {
		return null;
	}
	
	public abstract String getContent();
}

The builders used in the getThread() don’t seem to have a way to attach the vectorStore to them.

When I sendConversationMessage(), it looks like this:

	public String sendConversationMessage(BaseConversationHelper conversationHelper, File file) {
		final String threadId = conversationHelper.getThread().getId(),
		assistantId = conversationHelper.getAssistant().getId();

		openAI.threadMessages()
				.create(threadId, ThreadMessageRequest.builder()
				.role(ThreadMessageRole.USER)
				.content(conversationHelper.getContent())
				.attachment(Attachment.builder()
					.fileId(this.uploadFile(file))
						.tool(AttachmentTool.FILE_SEARCH)
						.build())
					.build())
				.join();

		return this.handleRunEvents(openAI.threadRuns()
				.createStream(threadId, ThreadRunRequest.builder()
					.assistantId(assistantId)
					.build())
				.join(),
				conversationHelper);
	}

	public String uploadFile(File file) {
		return openAI.files()
				.create(FileRequest.builder()
					.file(Paths.get(file.getPath()))
					.purpose(PurposeType.ASSISTANTS)
					.build())
				.join()
				.getId();
	}

We add the attachment to the ThreadMessage, and add the assistantId to the ThreadMessageRequest. The assistantId belongs to an Assistant that has a vectorStoreId attached to it via the FileSearch tool…

Somehow my API dashboard is getting spammed with nameless vector stores created from this code…

How can we put a stop to that?

@sashirestela

1 Like

@mwarren04011990 Thanks for using simple-openai!

According to the OpenAI documentation, there are two vector stores:

When you create a Run on this thread, the file search tool will query both the vector_store from your assistant and the vector_store on the thread.

When you attach files to the Thread or to the ThreadMessage, a nameless vector_store is created by OpenAI behind the scenes, which expires after 7 days (see docs to change this policy in OpenAI).

If you don’t want to keep those nameless vector_stores, you have to delete them explicitly. Take the following demos code as a reference:

1 Like

Thank you so much for not only this library, which is not only simple to use, but when used looks isomorphic to the code in the OpenAI documentation !

I was able to get started quickly and fix my issues before this easily with it!

I was able to get the deletion implemented in my BaseConversationHelper.close():

	public void close() { 
		if (this.thread == null)
			return;
			
		this.thread = openAI.threads()
			.getOne(this.thread.getId())
			.join();
			
		openAI.vectorStores().delete(this.thread
				.getToolResources()
				.getFileSearch()
				.getVectorStoreIds()
				.first())
			.join();
			
		Page<ThreadMessage> threadMessages = openAI.threadMessages().getList(this.thread.getId())
			.join();
			
		threadMessages.each({ThreadMessage threadMessage -> 
			threadMessage.getAttachments().each({ Attachment attachment -> 
				openAI.files()
					.delete(attachment.getFileId())
					.join();
			})
		}) 
		
		openAI.threads()
			.delete(this.thread.getId())
			.join();
	}