feat: scope analytics and config by agentId - #7
Conversation
Adds per-agent isolation to analytics recording and config management: - analytics/db.ts: adds agent_id column to write_events, search_events, graph_events, memory_graph_links (nullable, backward compat); all recording methods accept optional agentId; getStats() filters by agent_id when provided - pipeline/write.ts: threads agentId from req.agent through the write pipeline to analytics recording - routes/memories.ts: passes agentId to search and write analytics - routes/stats.ts: filters stats/write-events by agent_id on agent-scoped routes - routes/config.ts: agent-scoped requests read/write config via registry.getAgentConfig()/setAgentConfig() with fallback to global; legacy requests unchanged Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9443b54388
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| registry.deleteAgentConfig(agentId, "custom_prompt"); | ||
| } | ||
| console.log(`[config] agent ${agentId} custom prompt updated: ${newPrompt ? `${newPrompt.slice(0, 80)}...` : "reset to global"}`); | ||
| return v2Ok(res, { prompt: newPrompt, source: newPrompt ? "agent" : "global", persisted: true }); |
There was a problem hiding this comment.
Reload agent memory after agent-scoped config writes
This agent-scoped PUT /config/prompt path persists the override and returns immediately, which skips the runtime reload path used by global config updates. In the current code, agent requests execute against req.agentMemory from the pool, and that memory constructor does not consume registry config, so the API reports an agent override as saved while subsequent agent writes continue using prior/global behavior. The same early-return pattern is repeated for other agent-scoped config setters, so per-agent config changes are not actually applied at runtime.
Useful? React with 👍 / 👎.
| if (ev === "ADD" || ev === "UPDATE") { | ||
| const memId = r?.id ?? r?.memory_id; | ||
| if (memId) analyticsDb.insertGraphLinks(memId, nodeIds, edgeIds, userId); | ||
| if (memId) analyticsDb.insertGraphLinks(memId, nodeIds, edgeIds, userId, agentId); |
There was a problem hiding this comment.
Pass agent ID when capturing graph links
This call now writes agent_id into memory_graph_links, but v2Write still invokes captureGraphLinks with only (result, userId), so agentId is always undefined and new rows get NULL for agent_id. That means the agent-scoping column added in this commit is never populated for graph links, which breaks per-agent attribution/filtering for this dataset.
Useful? React with 👍 / 👎.
Summary
agent_id TEXTcolumn towrite_events,search_events,graph_events,memory_graph_links(nullable, backward compat via ALTER TABLE ADD COLUMN with try/catch)recordWriteResults,recordSearch,recordGraphWrite,insertGraphLinks) accept optionalagentIdgetStats(days, agentId?)filters all queries byagent_idwhen providedreq.agent?.idthrough to analytics recording/v2/agents/:agentId/config/*) read/write viaregistry.getAgentConfig()/setAgentConfig()with fallback to global config; legacy routes unchangedDepends on #6 (registry + agent routing).
Test plan
yarn buildpasses cleanlyGET /v2/agents/:agentId/stats/memoriesreturns only that agent's data🤖 Generated with Claude Code