Skip to content

fix(ai): read the assistant model from the account data - #4886

Merged
paultranvan merged 1 commit into
masterfrom
fix/assistant-model-update
Aug 26, 2026
Merged

fix(ai): read the assistant model from the account data#4886
paultranvan merged 1 commit into
masterfrom
fix/assistant-model-update

Conversation

@paultranvan

@paultranvan paultranvan commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

Changing an AI assistant's model has no effect unless the API key is retyped at the same time: the conversation keeps running on the model the assistant was created with.

The provider account stores the model in auth.login and the API key in auth.password, and the stack bundles the two into auth.credentials_encrypted (encryptMap, model/account/credentials.go). That blob is only rebuilt when a password is present in the incoming document, so editing only the model leaves it encrypting the previous model — and buildLLMOverride read the blob in preference to the plain fields.

The model therefore exists in two places that drift apart, and the stale one won.

Fix

Rather than picking the fresher of the two copies, stop duplicating the model.

The model is configuration, not a credential, so it moves to data.model, next to the data.baseUrl that was already there — out of reach of the encryptor, which only ever touches auth. The two concerns are split into llmModel and llmAPIKey:

before after
model auth.login, duplicated into the encrypted blob data.model
API key auth.password → encrypted blob unchanged
base URL data.baseUrl unchanged

auth now holds what must be encrypted, data holds the rest, and the resulting triplet maps one-to-one onto OpenRAG's llm_override = {model, api_key, base_url}.

The encrypted blob is deliberately never consulted for the model: its copy is precisely the one that goes stale, and resurrecting it would turn a missing field into a silently wrong value.

Impact

No migration required. Accounts written before the move still carry the model in auth.login, which is never encrypted and therefore always up to date, so llmModel falls back to it. Every existing assistant is fixed as soon as this is deployed, and the stack can ship independently of the client.

The fallback is marked as transitional: it can be dropped once cozy-client writes data.model and existing accounts have been rewritten.

Follow-up on the client side

cozy-client must write data.model and stop writing auth.login. Note the ordering constraint: an account's display label is derived from auth[account.identifier], falling back to auth.login (cozy-harvest-lib getLabel, cozy-doctypes Account.getAccountName). Once auth.login is gone, that falls through to account._id, so the client change that sets identifier: 'accountName' and auth.accountName must land first.

That naming is a separate symptom of the same root cause — with the model sitting in auth.login, ComputeName labelled these accounts gemini-2.5-flash instead of Google — and is handled in its own client-side PR.

Tests

TestLLMModel and TestLLMAPIKey cover the data/login precedence, the legacy fallback, the encrypted-key paths, and one case that explicitly locks in that a stale encrypted model is never resurrected.

@paultranvan
paultranvan force-pushed the fix/assistant-model-update branch from 1f9c777 to 2280bd1 Compare July 29, 2026 16:16
@paultranvan
paultranvan marked this pull request as ready for review July 29, 2026 16:16
@shepilov

Copy link
Copy Markdown
Member

Does it make sense not to store a model in auth.login at all?

@shepilov

Copy link
Copy Markdown
Member

And how we update the model in the account info?

@paultranvan

Copy link
Copy Markdown
Contributor Author

Does it make sense not to store a model in auth.login at all?

actually yes, it makes more sense. I change it, so it is now on account.data.model, at the same level than account.data.baseUrl

@paultranvan

Copy link
Copy Markdown
Contributor Author

And how we update the model in the account info?

On user-side, we can edit an external LLM provider account with a new model name (gpt-4, opus5, mistral-large, ...)

@paultranvan
paultranvan force-pushed the fix/assistant-model-update branch from 2280bd1 to 0764e1b Compare August 26, 2026 09:39
@paultranvan paultranvan changed the title fix(ai): read the assistant model from the account login fix(ai): read the assistant model from the account data Aug 26, 2026
Changing an AI assistant's model had no effect unless the API key was
retyped at the same time: the conversation kept running on the model the
assistant was created with.

The provider account stored the model in `auth.login` and the API key in
`auth.password`, and `encryptMap` bundles that pair into
`auth.credentials_encrypted`. The blob is only rebuilt when a password is
present in the incoming document, so editing only the model left it
encrypting the previous model — and `buildLLMOverride` preferred the blob.

Rather than picking the fresher of two copies, stop duplicating the model.
It is configuration, not a credential, so it now lives in `data.model`
next to `data.baseUrl`, out of reach of the encryptor. `llmModel` and
`llmAPIKey` split the two concerns, and the encrypted blob is never
consulted for the model: its copy is the one that goes stale.

Accounts written before the move still carry the model in `auth.login`,
which is always up to date, so `llmModel` falls back to it and no
migration is required. That fallback can be dropped once cozy-client
writes `data.model` and existing accounts have been rewritten.
@paultranvan
paultranvan force-pushed the fix/assistant-model-update branch from 0764e1b to 3dcceb0 Compare August 26, 2026 09:43
@paultranvan
paultranvan merged commit 63c60f3 into master Aug 26, 2026
4 checks passed
@paultranvan
paultranvan deleted the fix/assistant-model-update branch August 26, 2026 13:56
paultranvan added a commit to linagora/cozy-client that referenced this pull request Aug 26, 2026
The stack bundles `auth.login` and `auth.password` into
`auth.credentials_encrypted`, and only rebuilds that blob when a
password is sent. Keeping the model in `auth.login` therefore
duplicated it into an encrypted copy that went stale as soon as the
model was edited without retyping the API key — and that copy was the
one forwarded to the LLM.

The model is configuration, not a credential, so it moves to
`data.model` next to `data.baseUrl`. `auth` is now what the stack
encrypts (the API key), `data` is the rest, and the triplet maps onto
the stack's `llm_override` = `{model, api_key, base_url}`.

`editAssistant` drops a leftover `auth.login`, so accounts created
before the move migrate as soon as they are edited. The encrypted blob
is left alone: the stack reads the API key from it and never the model.

Requires cozy-stack reading `data.model` (linagora/cozy-stack#4886).
paultranvan added a commit to linagora/cozy-client that referenced this pull request Aug 26, 2026
The stack bundles `auth.login` and `auth.password` into
`auth.credentials_encrypted` and only rebuilds that blob when a password
is sent. Keeping the model in `auth.login` duplicated it into an
encrypted copy that went stale as soon as the model was edited without
retyping the API key — and that copy was the one forwarded to the LLM.

The model is configuration, not a credential, so it moves to
`data.model` next to `data.baseUrl`. The triplet then maps onto the
stack's `llm_override` = `{model, api_key, base_url}`.

Dropping a leftover `auth.login` migrates accounts created before the
move as soon as they are edited. The encrypted blob is left alone: the
stack reads the API key from it and never the model.

Requires cozy-stack reading `data.model` (linagora/cozy-stack#4886).
paultranvan added a commit to linagora/cozy-client that referenced this pull request Aug 27, 2026
The stack bundles `auth.login` and `auth.password` into
`auth.credentials_encrypted` and only rebuilds that blob when a password
is sent. Keeping the model in `auth.login` duplicated it into an
encrypted copy that went stale as soon as the model was edited without
retyping the API key — and that copy was the one forwarded to the LLM.

The model is configuration, not a credential, so it moves to
`data.model` next to `data.baseUrl`. The triplet then maps onto the
stack's `llm_override` = `{model, api_key, base_url}`.

Dropping a leftover `auth.login` migrates accounts created before the
move as soon as they are edited. The encrypted blob is left alone: the
stack reads the API key from it and never the model.

Requires cozy-stack reading `data.model` (linagora/cozy-stack#4886).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants