Class SubjectPlugin
- All Implemented Interfaces:
ChatPlugin
/subject command (set(com.axelor.ai.db.AiChat, java.lang.Object), clear(com.axelor.ai.db.AiChat)) changes it afterwards. Users
still open popups and switch tabs freely; that only changes the focused view the prompt reports
for the turn.
The pin fires on first engagement, not first sight: a tool call has to name the record the user has in front of them, the exchange has to be about it, or the user has to ask from one of its fields, which also records that field. Starting a conversation on a project task and then asking about product sales therefore pins nothing, where pinning on sight would have labelled that conversation with a record it never discusses — and, since the subject outranks the focused view, would have misdirected a later "this record".
The pinned subject, the active tab and the focused field are stamped into the request context,
where AgentResolverPlugin renders them; a consulted agent's request carries them on with
the rest of its caller's context. Every key it writes is server-owned and cleared on entry, so
nothing a client sends reaches the prompt unvalidated.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classPinned fields resolved once per model and path for one reader: a chat listing shows many chats pinned on the same few fields, and each resolve reads permissions and metadata. -
Method Summary
Modifier and TypeMethodDescriptionstatic voidClears the pin; the next engagement re-arms the automatic one (pin() checks for null).decorateToolExecutor(ChatRequest request, ToolExecutor executor) Watches tool calls for the first one that names the record on screen, and pins it.voidonComplete(ChatRequest request) The fallback for a turn no tool call named: asks whether the words themselves were about the record on screen, rather than assuming either way.onRequest(ChatRequest request) Called before the loop starts.static StringpinnedLabel(AiChat chat) How to name the pinned record to a reader, or null when there is no pin - or when the caller cannot read what was pinned.pinnedValue(AiChat chat, SubjectPlugin.PinnedFields fields) AspinnedValue(AiChat, Access), resolving fields through a listing's shared cache.pinnedValue(AiChat chat, Access access) The pinned subject as chatToMap serializes it, or null: the context value, plus the field the conversation started from while it still resolves foruser.intpriority()Execution priority.static StringExplicit re-pin for/subject set.static StringsimpleName(String model) e.g.Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface com.axelor.ai.chat.ChatPlugin
decorateProvider, decorateWriter, estimateInjectedTokens, onError, onMessage
-
Method Details
-
priority
public int priority()Description copied from interface:ChatPluginExecution priority. Lower values run first. Default is 100.- Specified by:
priorityin interfaceChatPlugin
-
onRequest
Description copied from interface:ChatPluginCalled before the loop starts. May inspect or transform the request (e.g. resolve agent config, check rate limits).- Specified by:
onRequestin interfaceChatPlugin
-
decorateToolExecutor
Watches tool calls for the first one that names the record on screen, and pins it. Runs for sub-agents too: they inherit the parent's active tab, and work they do counts as engagement.- Specified by:
decorateToolExecutorin interfaceChatPlugin
-
onComplete
The fallback for a turn no tool call named: asks whether the words themselves were about the record on screen, rather than assuming either way.touchesanswers "no" to plenty of genuine engagement - the active-form tools take no target of their own to declare, so a question the person is visibly asking about the record in front of them still names nothing mechanically. Silence there is not evidence either way, so this asks instead of assuming.Only reached while unpinned: a tool call may have already pinned earlier in the same turn, so the chat's own stored state is re-read rather than trusted from the request's snapshot of it at the top of the turn.
- Specified by:
onCompletein interfaceChatPlugin
-
simpleName
e.g. "com.axelor.sale.db.Order" -> "Order" -
pinnedValue
The pinned subject as chatToMap serializes it, or null: the context value, plus the field the conversation started from while it still resolves foruser. -
pinnedValue
AspinnedValue(AiChat, Access), resolving fields through a listing's shared cache. -
set
Explicit re-pin for/subject set. Unlike the engagement pin this arrives with no successful tool call behind it, so it re-establishes that gate itself: the record is resolved under the caller'sAccessto read it, and a record that does not exist and one the caller cannot read are rejected identically (null), so the command cannot probe existence. Unlikepin()it may overwrite — that is what makes it a re-pin. Call inside a transaction, after the resource's membership and canDrive checks.- Returns:
- the server-derived label of the pinned record (for the event chip), or null when rejected: bad shape, nonexistent, or unreadable
-
pinnedLabel
How to name the pinned record to a reader, or null when there is no pin - or when the caller cannot read what was pinned.That second case matters: a chat's pin is the owner's, and a member may not share their access to it. A caller who cannot read the record gets no label, which is what keeps the destination out of reach for someone who should not be publishing to it.
-
clear
Clears the pin; the next engagement re-arms the automatic one (pin() checks for null).
-