Preview · Markdown rendered with real HTML tables

Brief cho Claude Code: lỗi nhận sai phòng ban / Telegram topic trong CEO AI OS

Mục tiêu

Xử lý triệt để lỗi CEO AI OS / Hermes Gateway nhận sai phòng ban khi người dùng nhắn trong các Telegram forum topic khác nhau.

Kỳ vọng cuối cùng:

Bối cảnh hệ thống

Project chính:

Hermes runtime đang dùng:

Gateway/session store:

Telegram group đang debug:

Helper đang dùng để hỏi phòng ban:

Lệnh test:

python3 lib/whereami.py --debug

Triệu chứng chính

Người dùng nhắn trong nhiều Telegram forum topic khác nhau, nhưng bot/tool thường trả cùng một thread_id, hoặc nhận context không phải group mà là DM.

Các case đã thấy:

Case A — tin nhắn ở topic có chữ sg

Người dùng hỏi:

> Xin chào, tôi là Michael, hãy vui lòng cho tôi biết tôi đang ở phòng ban nào và thread id là gì, session lưu ở đâu để tôi thực hiện mapping (sg)?

Output từ whereami.py --debug từng trả:

Tạm hiểu: topic sg có thể là thread 59, nhưng chưa được xác nhận làm mapping chính thức.

Case B — ảnh chụp từ topic Marketing

Người dùng nói ảnh đó là tin nhắn ở topic Marketing, không có chữ sg, nhưng bot cũng từng trả thread_id = 59.

Tra transcript/session store cho message trong ảnh cho thấy message nằm ở:

Nhưng trong chính turn đó, terminal tool chạy whereami.py lại trả 59.

Kết luận từ case này:

Case C — sau restart, vẫn sai và còn thấy context DM

Sau khi patch và restart gateway, user hỏi lại trong group/topic:

> phòng hiện tại là phòng nào, có thread id là gì

Tool subprocess nhận env như sau:

{
  "HERMES_SESSION_ID": "20260625_164941_4f5943fb",
  "HERMES_SESSION_KEY": "agent:main:telegram:dm:1604824313",
  "HERMES_SESSION_CHAT_ID": "1604824313",
  "HERMES_SESSION_THREAD_ID": "81",
  "HERMES_SESSION_MESSAGE_ID": "195",
  "HERMES_SESSION_USER_ID": "1604824313",
  "HERMES_SESSION_PLATFORM": "telegram"
}

Tức là user đang hỏi trong group/topic, nhưng terminal tool lại thấy:

Đây là context DM, không phải group:

whereami.py sau đó phải fallback sang group session mới nhất trong sessions.json, nên có lúc trả 3832, có lúc trả 59. Các giá trị fallback này không đáng tin để mapping.

Mapping hiện tại không đáng tin

Mapping cũ từng có trong memory/index:

Nhưng mapping này đã bị đánh dấu không đáng tin vì thực tế Telegram UI và session store mâu thuẫn.

Hiện tại đã reset mapping phòng ban của user về {} để tránh bot trả tên phòng sai.

Yêu cầu: không lưu mapping mới cho đến khi whereami.py --debug cho thấy các nguồn metadata khớp nhau.

File đã chỉnh

1. /opt/ai-os/products/ceo/lib/whereami.py

Đã sửa để không chỉ tin HERMES_SESSION_THREAD_ID nữa.

Logic mới:

  1. Ưu tiên HERMES_SESSION_ID -> tra /root/.hermes/sessions/sessions.json -> lấy session_key / origin.thread_id.
  2. Nếu không có, parse HERMES_SESSION_KEY.
  3. Nếu không có nữa, mới dùng HERMES_SESSION_CHAT_ID + HERMES_SESSION_THREAD_ID.
  4. Cuối cùng mới fallback sang group session mới nhất.

Có mode debug:

python3 lib/whereami.py --debug

Mode này trả evidence các nguồn:

2. /usr/local/lib/hermes-agent/gateway/run.py

Đã patch _set_session_env() để truyền thêm session_id=context.session_id vào set_session_vars().

Trước patch, _set_session_env() truyền:

Nhưng thiếu:

Patch đã thêm:

session_id=context.session_id,

Kết quả compile check OK:

Test giả lập set_session_vars() + _make_run_env() sau patch cho thấy env inject đúng nếu context đúng:

Nhưng sau restart thật, bug vẫn còn vì context đi vào tool có thể đã là DM hoặc stale trước đó.

Kết luận kỹ thuật hiện tại

Patch session_id là đúng nhưng chưa đủ.

Root cause hiện tại nhiều khả năng nằm sâu hơn ở lớp gateway / runtime binding session context:

  1. Agent/transcript có thể nằm ở session group topic đúng, ví dụ thread 81.
  2. Terminal tool subprocess lại nhận HERMES_SESSION_* của thread khác, ví dụ 59, hoặc nhận context DM agent:main:telegram:dm:1604824313.
  3. Điều này chứng tỏ tool runtime không luôn được bind với đúng SessionContext của turn hiện tại.

Điểm đáng nghi trong /usr/local/lib/hermes-agent/gateway/run.py:

os.environ["HERMES_SESSION_KEY"] = session_key or ""

Dòng này nằm trong run_sync() quanh line khoảng 14340.

Comment nói session_key đã set qua contextvars, nhưng code vẫn ghi vào os.environ process-global:

Cần kiểm tra kỹ đoạn này và các đoạn tương tự với HERMES_SESSION_*.

Các file/code path cần Claude Code tập trung kiểm tra

Gateway session context

Kiểm tra:

Hiện get_session_env() ưu tiên ContextVar, sau đó mới fallback os.environ.

Gateway run flow

Điểm cần trace:

  1. Message inbound được convert thành SessionSource như thế nào.
  2. session_key được build từ source.chat_id + source.thread_id ra sao.
  3. _handle_message_with_agent hoặc equivalent gọi build_session_context()_set_session_env() ở đâu.
  4. run_sync() được chạy qua _run_in_executor_with_context() có bảo toàn ContextVar đúng không.
  5. Có đoạn nào ghi HERMES_SESSION_* vào os.environ sau _set_session_env() không.
  6. Có đoạn nào clear/reset contextvars quá sớm, trước khi tool call chạy xong không.
  7. Agent/tool dispatch có chạy trong thread/task khác không copy đúng context không.

Terminal subprocess env injection

Đoạn _make_run_env() inject ContextVar vào subprocess env:

from gateway.session_context import _UNSET, _VAR_MAP
for var_name, var in _VAR_MAP.items():
    value = var.get()
    if value is not _UNSET and value:
        run_env[var_name] = value

Cần xác nhận khi terminal tool chạy thật:

Terminal tool

Kiểm tra tool gọi environment execute như thế nào, có truyền env {} hay merge os.environ ra sao.

Hypothesis cần xác minh

Hypothesis 1 — os.environ global làm bẩn context

Một hoặc nhiều biến HERMES_SESSION_* vẫn bị ghi vào process global env. Sau đó _make_run_env() merge os.environ | env, rồi chỉ override các var nếu ContextVar có value truthy.

Nếu ContextVar thiếu hoặc empty, subprocess sẽ thừa hưởng stale env.

Cần kiểm tra tất cả chỗ ghi:

Hypothesis 2 — ContextVar không được copy qua đúng thread/tool execution path

Gateway có helper:

async def _run_in_executor_with_context(self, func, *args):
    loop = asyncio.get_running_loop()
    ctx = copy_context()
    return await loop.run_in_executor(None, ctx.run, func, *args)

Cần xác nhận toàn bộ agent/tool execution thật sự chạy bên trong context này. Có thể một số tool call hoặc nested execution chạy ngoài copied context.

Hypothesis 3 — Telegram inbound source bị parse sai thành DM

Sau restart vẫn thấy group question nhưng env tool là DM:

Cần kiểm tra adapter Telegram tạo SessionSource ra sao cho message trong forum topic:

Nếu inbound source đúng là DM thì bug nằm trước session context: platform adapter / event routing.

Nếu inbound source là group nhưng tool env là DM thì bug nằm giữa session context và tool dispatch.

Cách debug đề xuất

Thêm logging tạm thời hoặc debug hook ở 4 điểm, cùng một turn:

Point 1 — Ngay sau Telegram adapter tạo event/source

Log:

Point 2 — Ngay sau build_session_context()

Log:

Point 3 — Ngay trước gọi agent/run_sync

Log:

Point 4 — Trong terminal tool hoặc _make_run_env() ngay trước subprocess

Log:

Mục tiêu là một bảng cho cùng một message:

Pointchat_idchat_type/session_keythread_idsession_idmessage_id
Telegram source???n/a?
SessionContext?????
Agent before tool?????
Terminal subprocess env?????

Chỉ cần điểm đầu tiên bắt đầu lệch là biết root cause.

Tiêu chí fix đúng

Sau khi fix, test trong 2 topic khác nhau, ví dụ sgMarketing.

Trong mỗi topic, user gửi:

> map test phòng này

Assistant chạy:

python3 lib/whereami.py --debug

Kết quả phải thỏa:

  1. env/context.session_key là dạng group, không phải DM:
agent:main:telegram:group:-1003833933494:<thread_id>
  1. HERMES_SESSION_CHAT_ID là group id:
-1003833933494
  1. HERMES_SESSION_THREAD_ID bằng suffix của HERMES_SESSION_KEY.
  1. HERMES_SESSION_ID tra được trong /root/.hermes/sessions/sessions.json và record đó có cùng session key/thread.
  1. Không dùng fallback sessions.json/latest_group_fallback để trả kết quả.
  1. Hai topic khác nhau phải cho hai thread_id khác nhau, nếu Telegram UI thật sự là hai topic khác nhau.

Những điều không nên làm

Kết luận hiện tại

Vấn đề không còn là whereami.py đơn thuần.

whereami.py đã được sửa để đọc session store theo HERMES_SESSION_ID, nhưng tool subprocess vẫn có thể nhận sai HERMES_SESSION_*.

Kết luận mạnh nhất hiện tại:

> Hermes gateway/tool runtime đang bind sai hoặc làm bẩn session context giữa Telegram DM/group/forum topic. Cần sửa để tool subprocess nhận đúng SessionContext của turn hiện tại, thay vì nhận stale/global env hoặc DM context.

Patch đã làm với session_id=context.session_id là cần thiết, nhưng chưa đủ. Claude Code nên tập trung trace từ Telegram inbound source đến terminal _make_run_env() để tìm điểm đầu tiên context bị lệch.

Lệnh kiểm tra nhanh sau khi Claude Code sửa

cd /opt/ai-os/products/ceo
python3 lib/whereami.py --debug

Và nếu cần kiểm tra runtime files:

python3 -m py_compile /usr/local/lib/hermes-agent/gateway/run.py
python3 -m py_compile /usr/local/lib/hermes-agent/gateway/session_context.py
python3 -m py_compile /usr/local/lib/hermes-agent/tools/environments/local.py

Sau khi patch runtime, cần restart gateway từ shell ngoài gateway process:

hermes gateway restart

Không thể restart gateway từ chính bot Telegram vì Hermes chặn để tránh restart loop.