You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Gateway: routing binds a chat to an agent but not to an isolated tenant profile — memory, credentials and model are shared across every route, so one gateway cannot safely multiplex tenants #3189
The gateway can route inbound messages to different agents behind one process (RouteBinding / ChannelRouteConfig), and it can scope the toolset per route (trust tiers, allow_tools/deny_tools). What it cannot do is give each route its own isolated tenant profile — a separated memory store, credential/secret scope, model and config home.
Concretely, every route on a single gateway shares:
one memory store (agent memory is a bare on/off flag, not a namespace);
one credential space (tokens resolve from the shared process environment / per-channel secret refs, not a per-tenant secret scope);
one implicit config home (no per-profile working directory / knowledge / policy).
This blocks the single most valuable "world-class gateway" deployment shape: one gateway serving many communities/customers/workspaces at once, each fully isolated. Today an operator who wants tenant A's Discord server and tenant B's Slack workspace to have separate memory and separate secrets must run two gateway processes. That is the opposite of "easy to use, robust, world-class". Memory bleed across tenants is also a correctness/privacy hazard: a group in one route can surface context (or a resolved secret in logs) belonging to another.
Current behaviour
Routing selects an agent, and nothing else.RouteBinding carries an agent id plus tool-scoping fields, but no memory / credential / home dimension:
Memory is a shared boolean, not a namespace.AgentConfigSchema.memory: bool = False (_config_schema.py:39) toggles memory on/off; two agents behind one gateway with memory: true write into the same store — there is no per-route memory namespace.
Credentials are one shared pool. Channel tokens resolve from the shared process environment (src/praisonai-bot/praisonai_bot/bots/bot.py:43_TOKEN_ENV_MAP) or per-channel secret refs (_config_schema.py:291); there is no per-tenant secret scope so an authz check or a tool call on route A can read route B's credentials.
Absence confirmed:grep -rniE "secret_scope|per.route.*memory|memory.*namespace|credential.*scope|home.*scope|tenant_id" across src/praisonai-bot/praisonai_bot/ returns nothing; tenant appears in core only as a rate-limit scope token (gateway/protocols.py rate-limit comments), never as an isolation boundary.
Desired behaviour
A route (or a channel) can name an isolated profile, and the gateway enters that profile's scope for the whole turn:
memory reads/writes are namespaced to the profile (no cross-tenant bleed);
secrets/credentials resolve from the profile's scope first (a route can only see its own tokens);
model / instructions / knowledge / policy may be overridden per profile;
resolution is most-specific-wins and fails closed (a route with no profile binding never silently falls back to another tenant's memory or secrets).
One gateway.yaml should be able to run N isolated tenants from one process, via CLI, YAML and Python alike.
Layer placement
Primary layer: wrapper (src/praisonai-bot/praisonai_bot/ — routing, session, secret resolution, memory wiring). The value is runtime isolation wiring: namespacing the memory store, scoping secret resolution, and entering a per-profile home for the duration of a turn.
Why not core: core must stay protocol-only with no heavy imports; the memory/secret/home side-effects are impl, not contract. Core's role is limited to the contract (see secondary touch).
Why not tools: this is framework lifecycle wiring the gateway performs around a turn, not an agent-callable integration.
Why not plugins: isolation is a first-class gateway guarantee (safety by default), not an optional cross-cutting policy a user opts into — a plugin cannot retrofit a namespace boundary onto the session/secret/memory paths.
Secondary touch (core protocol): extend RouteBinding with a profile field and add a small ProfileScopeProtocol (resolve a profile → memory namespace + secret scope + home) alongside the existing resolve_route (gateway/protocols.py:1857), mirroring how ToolPolicy/SendPolicy are pure-decision protocols in core with side-effects owned by the wrapper.
# Before (today): one memory store + one secret pool for the whole gatewaygateway: { host: 0.0.0.0, port: 8080 }agents:
support: { instructions: "Be helpful", memory: true }channels:
discord-acme: { platform: discord, token: ${ACME_DISCORD}, routes: { default: support } }slack-globex: { platform: slack, token: ${GLOBEX_SLACK}, routes: { default: support } }# support's memory mixes ACME and Globex conversations; a tool on either# route can read both tokens from the shared environment.
Critical — multi-tenant isolation is the defining capability of a production, world-class gateway and it is currently absent; the only workaround (one process per tenant) defeats the point of a multiplexing gateway, and the shared memory/secret space is an active cross-tenant privacy/correctness hazard.
Validation
RouteBinding fields enumerated — no memory/credential/home/profile dimension: src/praisonai-agents/praisonaiagents/gateway/protocols.py:1662-1699.
session_scope restricted to per_user/per_chat: src/praisonai-bot/praisonai_bot/bots/_config_schema.py:140,157-163.
Memory is a shared boolean, not a namespace: src/praisonai-bot/praisonai_bot/bots/_config_schema.py:39.
Credentials come from the shared process env / per-channel secret refs, no per-tenant scope: src/praisonai-bot/praisonai_bot/bots/bot.py:43-67, _config_schema.py:288-372.
Absence of any per-route/per-tenant memory or secret scoping confirmed by grep -rniE "secret_scope|memory.*namespace|credential.*scope|home.*scope|tenant_id" over src/praisonai-bot/praisonai_bot/ → no matches.
Summary
The gateway can route inbound messages to different agents behind one process (
RouteBinding/ChannelRouteConfig), and it can scope the toolset per route (trust tiers,allow_tools/deny_tools). What it cannot do is give each route its own isolated tenant profile — a separated memory store, credential/secret scope, model and config home.Concretely, every route on a single gateway shares:
memoryis a bare on/off flag, not a namespace);This blocks the single most valuable "world-class gateway" deployment shape: one gateway serving many communities/customers/workspaces at once, each fully isolated. Today an operator who wants tenant A's Discord server and tenant B's Slack workspace to have separate memory and separate secrets must run two gateway processes. That is the opposite of "easy to use, robust, world-class". Memory bleed across tenants is also a correctness/privacy hazard: a group in one route can surface context (or a resolved secret in logs) belonging to another.
Current behaviour
Routing selects an agent, and nothing else.
RouteBindingcarries anagentid plus tool-scoping fields, but no memory / credential / home dimension:src/praisonai-agents/praisonaiagents/gateway/protocols.py:1662Session isolation stops at
per_user/per_chat. There is noper_tenant/per_profilescope:src/praisonai-bot/praisonai_bot/bots/_config_schema.py:140Memory is a shared boolean, not a namespace.
AgentConfigSchema.memory: bool = False(_config_schema.py:39) toggles memory on/off; two agents behind one gateway withmemory: truewrite into the same store — there is no per-route memory namespace.Credentials are one shared pool. Channel tokens resolve from the shared process environment (
src/praisonai-bot/praisonai_bot/bots/bot.py:43_TOKEN_ENV_MAP) or per-channel secret refs (_config_schema.py:291); there is no per-tenant secret scope so an authz check or a tool call on route A can read route B's credentials.Absence confirmed:
grep -rniE "secret_scope|per.route.*memory|memory.*namespace|credential.*scope|home.*scope|tenant_id"acrosssrc/praisonai-bot/praisonai_bot/returns nothing;tenantappears in core only as a rate-limit scope token (gateway/protocols.pyrate-limit comments), never as an isolation boundary.Desired behaviour
A route (or a channel) can name an isolated profile, and the gateway enters that profile's scope for the whole turn:
One
gateway.yamlshould be able to run N isolated tenants from one process, via CLI, YAML and Python alike.Layer placement
src/praisonai-bot/praisonai_bot/— routing, session, secret resolution, memory wiring). The value is runtime isolation wiring: namespacing the memory store, scoping secret resolution, and entering a per-profile home for the duration of a turn.RouteBindingwith aprofilefield and add a smallProfileScopeProtocol(resolve a profile → memory namespace + secret scope + home) alongside the existingresolve_route(gateway/protocols.py:1857), mirroring howToolPolicy/SendPolicyare pure-decision protocols in core with side-effects owned by the wrapper.gateway.yamlprofiles:+ per-routeprofile:; PythonRouteBinding(profile=...)/BotOS(profiles=...); CLIpraisonai gateway starthonours the same config (plusgateway profiles list).Proposed approach
RouteBinding.profile+ProfileScopeProtocol) + wrapper resolver that enters the scope; config surface in_config_schema.py.Resolution sketch
Severity
Critical — multi-tenant isolation is the defining capability of a production, world-class gateway and it is currently absent; the only workaround (one process per tenant) defeats the point of a multiplexing gateway, and the shared memory/secret space is an active cross-tenant privacy/correctness hazard.
Validation
RouteBindingfields enumerated — no memory/credential/home/profile dimension:src/praisonai-agents/praisonaiagents/gateway/protocols.py:1662-1699.session_scoperestricted toper_user/per_chat:src/praisonai-bot/praisonai_bot/bots/_config_schema.py:140,157-163.src/praisonai-bot/praisonai_bot/bots/_config_schema.py:39.src/praisonai-bot/praisonai_bot/bots/bot.py:43-67,_config_schema.py:288-372.grep -rniE "secret_scope|memory.*namespace|credential.*scope|home.*scope|tenant_id"oversrc/praisonai-bot/praisonai_bot/→ no matches.mervinpraison/praisonaiissues for gateway + tenant/profile/multiplex/isolation — nothing overlaps (Three high-impact gaps in src/praisonai/praisonai: broken ollama publish, multi-tenant-unsafe tool resolver, sync-only auto-generator with unreliable cleanup #1735 concerns the tool resolver, not gateway routing/session isolation).