Skip to content

fix(streaming): pass agentId to resolveStorePath and remove fallback#422

Open
smallmj wants to merge 1 commit into
larksuite:mainfrom
smallmj:fix/footer-metrics-clean
Open

fix(streaming): pass agentId to resolveStorePath and remove fallback#422
smallmj wants to merge 1 commit into
larksuite:mainfrom
smallmj:fix/footer-metrics-clean

Conversation

@smallmj
Copy link
Copy Markdown

@smallmj smallmj commented Apr 16, 2026

Summary

Extract agentId from session key to route the store lookup to the correct per-agent session file. The original fallback mechanism was incorrect because it would read from the default agent's session file when the correct agent's file didn't have the entry, causing all non-default agents to show the same metrics values.

Changes

  1. Add parameter to type signatures
  2. Extract agentId from session key using regex: key.match(/^agent:([^:]+):/)?.[1]
  3. Pass agentId to both and calls
  4. Remove the fallback logic (defaultAgentId, fallbackKey, candidateKeys loop)
  5. Simplify entry lookup from loop to direct store[key]

Why remove fallback

The fallback was wrong because:

  • Each agent's metrics are correctly written to their own session file
  • The fallback would read from main's session file and return those values
  • This caused all non-default agents to display the same metrics (from main)

Fixes #347

@smallmj
Copy link
Copy Markdown
Author

smallmj commented Apr 16, 2026

Ping

This PR replaces the earlier PR #386 which has been ignored for a while.

Status: This fix has been locally verified to work correctly. After applying this change, each non-default agent now shows its own unique metrics values instead of all showing the same values from the main agent.

The fix is simple and clean: extract agentId from sessionKey and pass it to resolveStorePath, removing the incorrect fallback mechanism.

Please review. Thanks!

Extract agentId from session key (format: 'agent:<agentId>:feishu:...')
to route the store lookup to the correct per-agent session file.

The fallback mechanism from larksuite#504 is incorrect because it reads from the
default agent's session file when the correct agent's file doesn't have
the entry, causing all non-default agents to show the same metrics
values (from main). This approach avoids that by using the correct key
directly without any fallback.

Fixes larksuite#347
@smallmj smallmj force-pushed the fix/footer-metrics-clean branch from 5d1756a to 3bbd18b Compare May 13, 2026 17:19
@smallmj
Copy link
Copy Markdown
Author

smallmj commented May 13, 2026

Why #422 is better than #504 (no fallback approach)

The problem with fallback

#504 correctly passes agentId to resolveStorePath(...), but retains a fallback mechanism:

const defaultAgentId = resolveDefaultAgentId(cfg);
const fallbackKey = key.replace(/^(agent):[^:]+:/, `$1:${defaultAgentId}:`);
const candidateKeys = fallbackKey !== key ? [key, fallbackKey] : [key];

for (const candidate of candidateKeys) {
  const val = store[candidate];
  if (val && typeof val === 'object') { entry = val; break; }
}

The fallback activates when the primary lookup returns no data. It substitutes the agent-id segment with defaultAgentId (usually "main"), then reads from main's session store. This means:

  • im-operator processes a request → primary lookup finds nothing → falls back to main's store → im-operator footer shows main's metrics
  • claudebot processes a request → primary lookup finds nothing → falls back to main's store → claudebot footer shows main's metrics

The fallback defeats the entire purpose of per-agent session isolation.

Why #422's approach is cleaner

#422 extracts agentId directly from the session key via regex, no fallback, no fallbackKey, no candidateKeys:

const agentId = key.match(/^agent:([^:]+):/)?.[1];
// ...
const storePath = sessionApi.resolveStorePath(sessionStorePath, { agentId });
// ...
const entry = store[key];  // direct lookup, no fallback

This is better because:

  1. No fallback = no cross-agent data leakage — if the correct agent's store has no data, we simply return undefined instead of reading from main's store
  2. Simpler code — no candidateKeys loop, no resolveDefaultAgentId call
  3. Single source of truth — the agentId comes from the session key itself, not from deps injection

Reference

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.

Footer metrics (tokens/cache/context/model) always missing for non-default agents

1 participant