feat: enable catalog writes, with the conversation history they require
The gateway already authorised writes for a product_manager — ai-mcp-proxy filters tool discovery by consumer group, so create-product is simply absent from a read-only user's turn. Only the system prompt was holding the agent back, and it now describes how to write instead: restate the record, ask for confirmation, never invent a missing field, report the identifier, and stop on a refusal rather than working around it. That flow cannot terminate without history. Each turn built a fresh Agent with no message_history, so the user's "yes" arrived at an agent that had no idea what it was agreeing to. History is now kept per A2A contextId in a bounded in-memory map — enough for confirm-then-act, deliberately not durable, and documented as needing sticky routing beyond one replica. Verified end to end: pm-user creates S99_TEST1 across two turns and the row appears in MySQL; ro-user asking for the same thing is told no write tool exists, because for that token none does. Both test rows removed afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,10 +58,31 @@ quietly.
|
||||
| | |
|
||||
|---|---|
|
||||
| Reads | catalog (products, product lines), sales (read-only, to judge whether a product sells) |
|
||||
| Writes | **none yet** — the agent says so when asked |
|
||||
| Writes | catalog: `create-product`, and only after the user confirms the exact record |
|
||||
| Calls | nothing yet. `Approvisionnement.check_availability` comes with discontinuation decisions |
|
||||
| Exposes | `describe_catalog` |
|
||||
|
||||
Who may write is decided by Kong, not by this agent. `ai-mcp-proxy` carries a
|
||||
per-tool ACL — `create-product` allows the `admin` and `product_manager`
|
||||
consumer groups — and the group comes from `realm_access.roles` in the end
|
||||
user's own token. The filtering happens at **discovery**, not just at call time:
|
||||
|
||||
```
|
||||
pm-user catalog ['create-product', 'get-product', 'list-products']
|
||||
ro-user catalog ['get-product', 'list-products']
|
||||
```
|
||||
|
||||
So a read-only user's turn has no write tool in it at all, and no prompt
|
||||
injection can conjure one. The agent holds no standing write access of its own;
|
||||
the system prompt's confirm-before-writing rule is a courtesy on top of that,
|
||||
not the control.
|
||||
|
||||
Writing needs conversation history — the agent restates the record, the user
|
||||
says yes, and "yes" only means something if the previous turn is still there.
|
||||
History is kept in memory, keyed by A2A `contextId`, bounded, and never
|
||||
persisted. More than one replica therefore needs sticky routing on `contextId`
|
||||
or a shared store.
|
||||
|
||||
Skills are decision-shaped on purpose. An agent exposing a generic `query` has
|
||||
become a data proxy and defeats the per-domain scoping the estate is built on,
|
||||
so skills get added when another agent has a specific question — not in advance.
|
||||
|
||||
Reference in New Issue
Block a user