Cozy AI chat doctypes¶
Cozy can store and manipulate the data of a chat with an AI, distributed across several doctypes.
Cf the stack documentation for AI.
io.cozy.ai.chat.conversations¶
The io.cozy.ai.chat.conversations doctype is used to keep history of chat
conversations with an assistant (AI).
messages: {array} An array of the messages of a conversationid: {string} Identifier of the messagerole: {string} Can beuser,assistantorsystemcontent: {string} What was said by the user or the assistantcreatedAt: {date} When the message was publishedattachmentIDs?: {array} Identifiers of theio.cozy.filesattached to a user messagesources?: {array} On anassistantmessage, the documents and web pages used to build the answer. Each entry is an object:sourceType: {string} Can bedocumentorweb- On a
documentsource: id: {string} Identifier of the source documentdoctype: {string} Doctype of the source document, likeio.cozy.filesorcom.linagora.emailfilename?: {string} Name of the filepage?: {int} Page of the file the extract comes fromfileUrl?: {string} URL of the source filechunkUrl?: {string} URL of the extract of the file used for the answerdatetime?: {date} Date of the source documentemail.subject?: {string} Subject of the mailemail.preview?: {string} Preview of the content of the mailparent_id?: {string} Identifier of the parent of the source documentrelationship_id?: {string} Identifier of the relationship of the source document- On a
websource: doctype: {string} Alwaysio.cozy.urlsurl: {string} URL of the web pagetitle: {string} Title of the web pagesnippet: {string} Extract of the web page used for the answer
relationships.assistant?: {object} Theio.cozy.ai.chat.assistantsdocument bound to the conversation, as{ "data": { "_id": ..., "_type": "io.cozy.ai.chat.assistants" } }. It is set by the stack when the conversation is created with anassistantID, and it drives both the knowledge base scoping and the LLM configuration of every query of that conversation.
A system message is not written by the clients: it is added by the stack when
the conversation is created with an assistant that has a prompt, see
io.cozy.ai.chat.assistants. Clients should
not render it as a regular conversation turn.
Example¶
{
"_id": "e21dce8058b9013d800a18c04daba326",
"_rev": "1-23456",
"cozyMetadata": {
"createdAt": "2024-09-24T13:24:07.576Z",
"createdOn": "http://cozy.localhost:8080/",
"doctypeVersion": "1",
"metadataVersion": 1,
"updatedAt": "2024-09-24T13:24:07.576Z"
},
"messages": [
{
"id": "eb17c3205bf1013ddea018c04daba326",
"role": "user",
"content": "Why the sky is blue?",
"createdAt": "2024-09-24T13:24:07.576Z"
},
{
"id": "0192756f2428758abe0aec7ecefc0c60",
"content": "The sky appears blue because of a phenomenon called Rayleigh scattering.",
"createdAt": "2024-09-24T13:24:08.987Z",
"role": "assistant",
"sources": [
{
"sourceType": "document",
"doctype": "io.cozy.files",
"id": "3fa17b7c5d1e013e9c2a18c04daba326",
"filename": "why-is-the-sky-blue.pdf",
"page": 2,
"fileUrl": "http://cozy.localhost:8080/files/3fa17b7c5d1e013e9c2a18c04daba326",
"chunkUrl": "http://cozy.localhost:8080/files/3fa17b7c5d1e013e9c2a18c04daba326#page=2"
},
{
"sourceType": "document",
"doctype": "com.linagora.email",
"id": "d90a1f4e2b73013e9c2a18c04daba327",
"email.subject": "Physics newsletter",
"email.preview": "This month, we look at why the sky is blue…",
"datetime": "2024-09-20T08:12:00.000Z"
},
{
"sourceType": "web",
"doctype": "io.cozy.urls",
"url": "https://en.wikipedia.org/wiki/Rayleigh_scattering",
"title": "Rayleigh scattering",
"snippet": "Rayleigh scattering is the scattering of light by particles much smaller than the wavelength."
}
]
}
],
"relationships": {
"assistant": {
"data": {
"_id": "e21dce8058b9013d800a18c04daba326",
"_type": "io.cozy.ai.chat.assistants"
}
}
}
}
io.cozy.ai.chat.events¶
This doctype is not persisted, it is only used on the realtime websockets to allow the application to display the tokens of the response step by step.
id: {string} the identifier of the message of the user (the question)object: {string} can bedeltafor a token ordonewhen it’s finishedcontent: {string} the content of the tokenposition: {int} the index of the token in the stream (as the events can be received in the wrong order)
io.cozy.ai.chat.assistants¶
The io.cozy.ai.chat.assistants doctype is used to keep configuration of an assistant (AI).
name: {string} The name of assistantprompt?: {string} Define a custom prompt to personalize the assistant. This can typically be used to give personality to the LLM, change the tone, the level of details, etc. But it cannot add functionality, nor infer or make incorrect claims about your data.icon?: {string} The avatar of assistant, as a base64 encoded string. It can also be explicitlynullwhen the assistant has no avatar.knowledgeBase?: {array} A list of{doctype, dirId?}entries scoping the assistant’s retrieval to specific sources. When empty or absent, the assistant’s retrieval is not scoped. Two kinds of entries exist:{"doctype": "io.cozy.files", "dirId": "..."}scopes retrieval to a Drive folder. Only a single folder is currently supported: if several are given, the stack keeps the first one and ignores (with a warning) any other distinct folder.{"doctype": "com.linagora.email"}(nodirId) scopes retrieval to the user’s mails. This entry is not interpreted by cozy-stack, only by the clients.
LLM provider¶
The relationships.provider.data object identifies the LLM account (an
io.cozy.accounts document) used by the assistant. Note that the assistant
document itself does not carry the model, the base URL, nor the API key: they
all live on that account.
_id: {string} The id of theio.cozy.accountsdocument_type: {string}io.cozy.accountsmetadata.providerId: {string} The provider of the account (openai,mistral, …). It is used by the stack to decide whether to forward a custom LLM configuration to OpenRAG instead of the stack’s default RAG configuration.
When providerId is empty or equal to "openrag", the stack’s default RAG
configuration is used. For any other value, the stack reads the linked account
and forwards:
- the model:
auth.login, - the API key:
auth.password, which the stack stores encrypted asauth.credentials_encrypted, - the base URL:
data.baseUrl.
If the account cannot be read, or if none of those three fields is set, the default configuration is used.
Assistant prompt and conversations¶
When a conversation is created via the cozy-stack POST /ai/chat/conversations/:id
route with an assistantID, if the assistant has a non-empty prompt, a
role: "system" message carrying that prompt is prepended to the conversation’s
messages (before the user’s own message), and consumed as-is by OpenRAG’s chat
completion format. It is persisted in the
io.cozy.ai.chat.conversations document,
and clients should not render system messages as regular conversation turns.
The prompt is only injected at creation time: editing an assistant’s prompt
does not update the conversations already created with it.
If a conversation references an assistant that no longer exists, the stack answers with an error rather than falling back to unscoped retrieval, which would silently widen a folder-scoped conversation to the whole instance.
Example¶
{
"_id": "e21dce8058b9013d800a18c04daba326",
"_rev": "1-23456",
"cozyMetadata": {
"createdAt": "2024-09-24T13:24:07.576Z",
"createdOn": "http://cozy.localhost:8080/",
"doctypeVersion": "1",
"metadataVersion": 1,
"updatedAt": "2024-09-24T13:24:07.576Z"
},
"name": "My assistant",
"prompt": "This is my assistant",
"icon": "[encoded base64 string of the content of the icon or svg binary]",
"knowledgeBase": [
{
"doctype": "io.cozy.files",
"dirId": "b21dce8058b9013d800a18c04daba333"
}
],
"relationships": {
"provider": {
"data": {
"_type": "io.cozy.accounts",
"_id": "e21dce8058b9013d800a18c04daba322",
"metadata": {
"providerId": "openrag"
}
}
}
}
}
io.cozy.ai.chat.rag¶
The io.cozy.ai.chat.rag doctype is used to keep the RAG indexation status of
a document. Its identifier is the identifier of the document it describes. Only
files are indexed for now, and the relationship always points to an
io.cozy.files document.
indexed: {boolean} Whether a version of the document has been indexed. A failed indexation does not reset it tofalse, soindexedcan betruewhilestatusiserror: a previous version is still indexedstatus: {string} Can besuccess,errorornotsupported. Thenotsupportedstatus is not reported by the indexer, it is the stack that decides a document will not be indexeddocRev: {string} The revision of the document this status describes. Compare it to the current revision of the document to know whether it is the current content that is indexed.lastSuccessDate?: {date} When the document was last indexed successfully. Absent as long as no indexation has succeededlastErrorDate?: {date} When the last indexation of the document failed. Absent as long as no indexation has failedrelationships: {object}doc: {object} The document this status describes
A status is only replaced by one about a revision that is not older than the
recorded docRev, so a callback that comes in late cannot bring an outdated
status back. The status document is deleted along with the document it
describes.
Example¶
{
"_id": "e21dce8058b9013d800a18c04daba326",
"_rev": "1-23456",
"indexed": true,
"status": "success",
"docRev": "3-6a1b0b8a51a4e0e0a3b7f0f1d2c3b4a5",
"lastSuccessDate": "2026-08-28T13:24:07.576Z",
"relationships": {
"doc": {
"data": {
"_id": "e21dce8058b9013d800a18c04daba326",
"_type": "io.cozy.files"
}
}
}
}