Skip to content

Commit 793b5e5

Browse files
JiaDeclaude
andcommitted
feat: employee-scoped session_id for cross-channel memory coherence
All channels for the same employee now share one AgentCore session: feis__ou_1a8a... + pt__emp-wjd... → emp__emp-wjd__dailyhash This aligns with OpenClaw's original single-process Gateway design where all channel sessions are managed in one process's memory. Benefits: - Cross-channel MEMORY.md write conflicts eliminated (single container) - Cross-channel context naturally preserved (same Gateway in-memory state) - No OpenClaw code changes required (zero-invasion) - Concurrent messages from same employee serialized (correct behavior) Runtime routing still works: invoke_agent_runtime extracts emp_id from tenant_id parts[1] and resolves the correct Runtime via DynamoDB routing config. Unmapped users (no DDB mapping) fall back to channel__userId session (backward compat). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent f77c4e2 commit 793b5e5

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

enterprise/gateway/tenant_router.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -504,22 +504,25 @@ def _handle_route(self):
504504
self._respond(400, {"error": "message required"})
505505
return
506506

507-
# Derive tenant and route.
508-
# For IM channels (feishu, telegram, discord etc.), user_id may be a platform ID
509-
# (e.g. Feishu OU ID). Resolve to emp_id via DynamoDB MAPPING# so that routing
510-
# uses the employee's position and runtime config correctly.
507+
# Resolve IM channel user IDs (Feishu OU IDs, Discord numeric IDs, etc.) to emp_id.
511508
resolved_emp_id = _resolve_emp_id(user_id, channel)
512-
routing_id = resolved_emp_id if resolved_emp_id else user_id
513509

514510
try:
515-
tenant_id = derive_tenant_id(channel, user_id)
511+
if resolved_emp_id:
512+
# Employee-scoped session: all channels for the same employee share ONE
513+
# AgentCore session, just like standard OpenClaw Gateway manages multiple
514+
# channels in a single process. This eliminates cross-channel MEMORY.md
515+
# write conflicts and preserves natural cross-channel context — no changes
516+
# to OpenClaw required.
517+
tenant_id = derive_tenant_id("emp", resolved_emp_id)
518+
else:
519+
# Fallback for users not yet in DynamoDB user-mapping (e.g. new users
520+
# before pairing, or admin test accounts).
521+
tenant_id = derive_tenant_id(channel, user_id)
516522
except ValueError as e:
517523
self._respond(400, {"error": str(e)})
518524
return
519525

520-
# Resolve runtime using the resolved emp_id (fixes IM channel routing to correct tier)
521-
runtime_id = _get_runtime_id_for_tenant(routing_id) or RUNTIME_ID
522-
523526
try:
524527
# Check if this routes to an always-on Docker container
525528
always_on_url = _get_always_on_endpoint(user_id, channel)

0 commit comments

Comments
 (0)