mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(mattermost): converge the Agents bot against the store the plugin reads
Agents 2.5.1 migrates config->'bots' into its own agents_useragents table on startup and logs "Migrated legacy config bots to self-service agents table". The wiring still treated the legacy location as the source of truth, which broke in three ways. set-ai-service.sql.j2 re-inserted the bot into config->'bots' unconditionally, so both stores held a bot named `agent`. EnsureBots aborts on that with `duplicate bot name: agent`, leaves its in-memory bot list empty, and handleMessages then returns without logging: no reply, no gateway request, no error. Only write the legacy entry while no live agent row owns the name. set-ai-agent.sql.j2 retargets the migrated row, because once legacy_config_bots_migrated is set, writing config->'bots' is a permanent no-op and the role could never change its model or service again. select/ai/service.sql.j2 asserts against agents_useragents and additionally reports stale when a legacy entry collides with a live agent row; the old check reported converged over a plugin whose bot list had failed to load. ai_gateway.yml fixes two orderings: the retarget now runs before the plugin cycle, because the plugin reads its agents into memory at startup, and the cycle is unconditional, because a converged-looking database was preventing the very reload that repairs a drifted plugin. Verified live: legacy bots 0, no duplicate bot name, the bot posting real replies, and test-litellm-agent.js passing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8f6e869791
commit
43f6ff62e6
4 files changed
+40
-21
No files matched your search
@@ -31,16 +31,6 @@
|
||||
delegate_to: "{{ STACK_HOST }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🔎 Mattermost | Count the Agents bot accounts the plugin has provisioned"
|
||||
database_query:
|
||||
config: "{{ lookup('database', application_id) }}"
|
||||
query: "{{ lookup('template', role_path ~ '/templates/sql/select/ai/bot-user.sql.j2') }}" # nocheck: database-query-raw the bot username is templated into the predicate
|
||||
expect_rows: true
|
||||
register: mattermost_ai_bot_state
|
||||
changed_when: false
|
||||
delegate_to: "{{ STACK_HOST }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🤖 Mattermost | Point the Agents bot at the platform gateway"
|
||||
when: (mattermost_ai_state.rows[0][0] | trim) != 'converged'
|
||||
database_query:
|
||||
@@ -51,11 +41,17 @@
|
||||
delegate_to: "{{ STACK_HOST }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🤖 Mattermost | Retarget the migrated agent row at the gateway"
|
||||
database_query:
|
||||
config: "{{ lookup('database', application_id) }}"
|
||||
query: "{{ lookup('template', role_path ~ '/templates/sql/set-ai-agent.sql.j2') }}" # nocheck: database-query-raw the desired bot is rendered from role vars
|
||||
mask_values: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
changed_when: true
|
||||
delegate_to: "{{ STACK_HOST }}"
|
||||
run_once: true
|
||||
|
||||
- name: "🔁 Mattermost | Cycle the Agents plugin so it adopts the merged config"
|
||||
ansible.builtin.include_tasks: "{{ role_path }}/tasks/utils/agents/reload.yml"
|
||||
when: >-
|
||||
(mattermost_ai_state.rows[0][0] | trim) != 'converged'
|
||||
or (mattermost_ai_bot_state.rows[0][0] | int) == 0
|
||||
vars:
|
||||
mattermost_agents_cid: "{{ MATTERMOST_AI_LOCAL_CID }}"
|
||||
mattermost_agents_node: "{{ MATTERMOST_AI_HOST_NODE }}"
|
||||
|
||||
@@ -6,13 +6,22 @@ SELECT CASE
|
||||
ELSE '[]'::jsonb END
|
||||
) AS s
|
||||
WHERE s ->> 'id' = d.service ->> 'id') = d.service
|
||||
AND (SELECT b
|
||||
FROM jsonb_array_elements(
|
||||
CASE WHEN jsonb_typeof(a.config::jsonb -> 'bots') = 'array'
|
||||
THEN a.config::jsonb -> 'bots'
|
||||
ELSE '[]'::jsonb END
|
||||
) AS b
|
||||
WHERE b ->> 'id' = d.bot ->> 'id') = d.bot
|
||||
AND EXISTS (SELECT 1
|
||||
FROM agents_useragents u
|
||||
WHERE u.username = d.bot ->> 'name'
|
||||
AND u.serviceid = d.bot ->> 'serviceID'
|
||||
AND u.model = d.bot ->> 'model'
|
||||
AND u.deleteat = 0
|
||||
AND u.botuserid <> '')
|
||||
AND NOT EXISTS (SELECT 1
|
||||
FROM jsonb_array_elements(
|
||||
CASE WHEN jsonb_typeof(a.config::jsonb -> 'bots') = 'array'
|
||||
THEN a.config::jsonb -> 'bots'
|
||||
ELSE '[]'::jsonb END
|
||||
) AS legacy
|
||||
JOIN agents_useragents u2
|
||||
ON u2.username = legacy ->> 'name'
|
||||
AND u2.deleteat = 0)
|
||||
THEN 'converged'
|
||||
ELSE 'stale'
|
||||
END
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
UPDATE agents_useragents u
|
||||
SET serviceid = d.bot ->> 'serviceID',
|
||||
model = d.bot ->> 'model',
|
||||
updateat = (extract(epoch from now()) * 1000)::bigint
|
||||
FROM (SELECT $infinito${{ MATTERMOST_LITELLM_BOT | to_json }}$infinito$::jsonb AS bot) AS d
|
||||
WHERE u.username = d.bot ->> 'name'
|
||||
AND u.deleteat = 0
|
||||
AND (u.serviceid IS DISTINCT FROM d.bot ->> 'serviceID'
|
||||
OR u.model IS DISTINCT FROM d.bot ->> 'model');
|
||||
@@ -23,7 +23,12 @@ UPDATE agents_confighistory a
|
||||
ELSE '[]'::jsonb END
|
||||
) AS b
|
||||
WHERE b ->> 'id' <> d.bot ->> 'id'
|
||||
), '[]'::jsonb) || jsonb_build_array(d.bot)
|
||||
), '[]'::jsonb) || CASE WHEN EXISTS (SELECT 1
|
||||
FROM agents_useragents u
|
||||
WHERE u.username = d.bot ->> 'name'
|
||||
AND u.deleteat = 0)
|
||||
THEN '[]'::jsonb
|
||||
ELSE jsonb_build_array(d.bot) END
|
||||
)
|
||||
|| jsonb_build_object('defaultBotName', d.bot ->> 'name')
|
||||
)::text
|
||||
|
||||
Reference in new issue
Block a user