Class OpenAiCompatibleModelMessage
java.lang.Object
uno.anahata.asi.agi.event.BasicPropertyChangeSource
uno.anahata.asi.agi.message.AbstractMessage
uno.anahata.asi.agi.message.AbstractModelMessage<OpenAiCompatibleResponse>
uno.anahata.asi.openai.compatible.OpenAiCompatibleModelMessage
- All Implemented Interfaces:
PropertyChangeSource, Rebindable
Concrete model message implementation for OpenAI-compatible Chat Completion
APIs. Handles content accumulation, finish reason mapping, and tool call
streaming buffers.
- Author:
- anahata
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate Map<Integer, StringBuilder> Buffers for accumulating streaming tool call arguments, keyed by their index in the 'tool_calls' array.Maps tool call indices to their stable API-provided unique IDs.Maps tool call indices to the requested function name.private booleanState flag indicating if the parser is currently inside a reasoning tag.Fields inherited from class BasicPropertyChangeSource
propertyChangeSupportModifier and TypeFieldDescriptionprotected PropertyChangeSupportSupport for firing property change events. -
Constructor Summary
ConstructorsConstructorDescriptionOpenAiCompatibleModelMessage(Agi agi, String modelId) Constructs a new, empty compatible message for streaming.OpenAiCompatibleModelMessage(Agi agi, String modelId, com.fasterxml.jackson.databind.JsonNode choiceNode, OpenAiCompatibleResponse response, OpenAiCompatibleReasoningStyle reasoningStyle, String reasoningFieldName, List<String> reasoningTags) Constructs a message from a final (non-streaming) choice node. -
Method Summary
Modifier and TypeMethodDescriptionvoidappendContent(String text) Appends text to the main content part or creates a new one.voidappendTaggedContent(String text, String startTag, String endTag) Appends text while detecting and extracting reasoning content wrapped in tags.voidappendThoughts(String text) Appends text to the reasoning/thought part or creates a new one.voidFlushes any buffered tool calls (used during streaming).booleanCalculates the EFFECTIVE pruned state of this message.private FinishReasonmapFinishReason(String reason) Maps a standard OpenAI finish reason string to the Anahata enum.voidSets the finish reason from a raw OpenAI string.voidupdateFromNode(com.fasterxml.jackson.databind.JsonNode choice, OpenAiCompatibleReasoningStyle reasoningStyle, String reasoningFieldName, List<String> reasoningTags) Updates the message content and state from a JSON node (choice, item, or event).voidupdateToolCall(com.fasterxml.jackson.databind.JsonNode callNode) Updates a single tool call from a JSON node.Methods inherited from class AbstractModelMessage
addBlobPart, addBlobPart, addBlobPart, addTextPart, addTextPart, appendMetadata, appendRawJson, declineAllPending, executeAllPending, getDevice, getFrom, getPendingToolCalls, getRemainingToolCallsCount, getRole, getToolCalls, getToolResponses, hasPendingTools, isAutoRunnable, isToolPromptMessage, onPartPruningStateChanged, remove, removePart, setBilledCompletionTokens, setBilledPromptTokens, setFinishReason, setGroundingMetadata, setRawJson, stopRunningAllPendingModifier and TypeMethodDescriptionfinal BlobPartaddBlobPart(String mimeType, byte[] data) Creates and adds a new binary data part to this message.final ModelBlobPartaddBlobPart(String mimeType, byte[] data, byte[] thoughtSignature) Creates and adds a new model blob part with thought process metadata.final ModelBlobPartaddBlobPart(Path path) Creates and adds a new binary data part from a local file path.final TextPartaddTextPart(String text) Creates and adds a new text part to this message.final ModelTextPartaddTextPart(String text, byte[] thoughtSignature, boolean thought) Creates and adds a new model text part with thought process metadata.protected voidHook for subclasses to inject specialized metadata into the message header.voidappendRawJson(String chunk) Appends a raw JSON chunk to the existing content.voidSets all tool calls in this message that are currently in a PENDING state to DECLINED and collapses them.booleanExecutes all tool calls in this message that are currently in a PENDING state, sequentially checking runningAllPending before starting each tool call.Gets the ID of the device where this message was created or processed.getFrom()Gets the identity of the sender of this message.List<AbstractToolCall<?, ?>> Filters and returns all tool calls belonging to this model message that are currently awaiting execution inToolExecutionStatus.PENDINGstate.intCalculates the number of tool calls in this message that are currently active in the execution queue (either actively EXECUTING or still PENDING).getRole()Gets the role of the entity that created this message.List<AbstractToolCall<?, ?>> Filters and returns only the tool call parts from this message.Returns all tool responses associated with the tool calls in this message.booleanChecks if there are any tool calls with responses in a PENDING state.booleanDetermines if this entire batch of tool calls can be executed automatically without user intervention.booleanChecks if this model message is the current tool prompt message for the agi.protected voidonPartPruningStateChanged(AbstractPart part, PruningState oldState, PruningState newState) Lifecycle callback invoked whenever a child part's pruning state changes.voidremove()Removes this message from the agi history.voidremovePart(AbstractPart part) Removes a part from this message and severs the bidirectional link.voidsetBilledCompletionTokens(int billedCompletionTokens) Sets the billed completion token count and fires a property change event.voidsetBilledPromptTokens(int billedPromptTokens) Sets the billed prompt token count and fires a property change event.voidsetFinishReason(FinishReason finishReason) Sets the finish reason and fires a property change event.voidsetGroundingMetadata(GroundingMetadata groundingMetadata) Sets the grounding metadata and fires a property change event.voidsetRawJson(String rawJson) Sets the raw JSON representation of the model's response and fires a property change event.voidSignals the sequential tool execution on this message to halt after the currently executing tool finishes, leaving any subsequent unstarted tools in PENDING state.Methods inherited from class AbstractMessage
addPart, asText, createMetadataHeader, getDepth, getEffectiveTokenCount, getIdentityLabel, getParts, getParts, getRemainingDepth, getTokenCount, isAllPinned, isAllPruned, isAnyPinned, isEmpty, isGarbageCollectable, isPrunnableOrRemovable, pinAllParts, pruneAllParts, resetTokenCounts, setAutoAllParts, shouldCreateMetadataModifier and TypeMethodDescriptionvoidaddPart(@NonNull AbstractPart part) Safely adds a single part to this message, establishing the bidirectional relationship and ensuring the part is fully initialized before firing property change events.asText(boolean includePruned) Convenience method to get the message content as a single string, concatenating the text representation of all its parts.Creates a standardized text header containing metadata for this message.intgetDepth()Calculates the "depth" of this message, defined as its distance from the most recent message in the agi history.intCalculates the total effective tokens consumed by this message, including the in-band metadata header and all of its parts.protected StringReturns the identity label for the metadata header (e.g., "Message ID: 12").getParts()Gets an unmodifiable list of all parts in this message.getParts(boolean includePruned) The definitive, encapsulated method for retrieving the parts of a message that should be sent to the model, respecting the pruning policy.intCalculates the remaining depth of the message as the maximum remaining depth of all its parts.intgetTokenCount(boolean includePruned) Calculates the total number of tokens in this message, summing the token counts of its visible parts.booleanChecks if all parts in this message are explicitly pinned.booleanChecks if all parts in this message are explicitly pruned.booleanChecks if any part in this message is explicitly pinned.booleanisEmpty()Checks if the message is empty.booleanDetermines if this message is eligible for "hard pruning" (permanent removal from history).booleanChecks if this message is eligible for pruning or removal.voidPins all parts in this message.voidExplicitly prunes all parts in this message.voidResets the cached token counts on all parts contained within this message, forcing a lazy recalculation under the new selected model's tokenizer.voidSets all parts in this message to AUTO.booleanHook for subclasses to declare if they should generate in-band metadata headers.Methods inherited from class BasicPropertyChangeSource
addPropertyChangeListener, addPropertyChangeListener, rebind, removePropertyChangeListener, removePropertyChangeListenerModifier and TypeMethodDescriptionvoidAdds a property change listener.voidaddPropertyChangeListener(String propertyName, PropertyChangeListener listener) Adds a property change listener for a specific property.voidrebind()Re-initializes the transientPropertyChangeSupportafter deserialization.voidRemoves a property change listener.voidremovePropertyChangeListener(String propertyName, PropertyChangeListener listener) Removes a property change listener for a specific property.Methods inherited from class Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods inherited from interface PropertyChangeSource
getPropertyChangeSupportModifier and TypeMethodDescriptionGets the PropertyChangeSupport instance for this object.
-
Field Details
-
insideReasoningTags
private boolean insideReasoningTagsState flag indicating if the parser is currently inside a reasoning tag. -
callArgsBuffers
Buffers for accumulating streaming tool call arguments, keyed by their index in the 'tool_calls' array. -
callIds
-
callNames
-
-
Constructor Details
-
OpenAiCompatibleModelMessage
-
OpenAiCompatibleModelMessage
public OpenAiCompatibleModelMessage(Agi agi, String modelId, com.fasterxml.jackson.databind.JsonNode choiceNode, OpenAiCompatibleResponse response, OpenAiCompatibleReasoningStyle reasoningStyle, String reasoningFieldName, List<String> reasoningTags) Constructs a message from a final (non-streaming) choice node.- Parameters:
agi- The parent session.modelId- The model ID.choiceNode- The 'choice' node from the chat completion response.response- The parent response object.reasoningStyle- The strategy for thought extraction.reasoningFieldName- The field for thoughts (if using FIELD style).reasoningTags- The tags for thoughts (if using TAGS style).
-
-
Method Details
-
updateFromNode
public void updateFromNode(com.fasterxml.jackson.databind.JsonNode choice, OpenAiCompatibleReasoningStyle reasoningStyle, String reasoningFieldName, List<String> reasoningTags) Updates the message content and state from a JSON node (choice, item, or event). Handles both streaming deltas and final message objects from the Chat Completions API.- Parameters:
choice- The JSON node to parse.reasoningStyle- The strategy for extracting thoughts.reasoningFieldName- The field name for reasoning content (if using FIELD style).reasoningTags- The tags for reasoning content (if using TAGS style).
-
updateToolCall
public void updateToolCall(com.fasterxml.jackson.databind.JsonNode callNode) Updates a single tool call from a JSON node.- Parameters:
callNode- The JSON node containing the tool call (or delta).
-
flushToolCalls
public void flushToolCalls()Flushes any buffered tool calls (used during streaming). This ensures that partial tool call arguments are fully assembled and registered in the tool manager. -
setFinishReasonFromOpenAi
Sets the finish reason from a raw OpenAI string.- Parameters:
fr- The raw finish reason string (e.g., "stop", "length").
-
mapFinishReason
Maps a standard OpenAI finish reason string to the Anahata enum.- Parameters:
reason- The raw string from the API.- Returns:
- The corresponding FinishReason.
-
isEffectivelyPruned
public boolean isEffectivelyPruned()Calculates the EFFECTIVE pruned state of this message. A message is effectively pruned ONLY if it contains no visible (un-pruned) parts. A model message is never effectively pruned while it is streaming.An actively streaming model message is never considered pruned, even if its parts list is temporarily empty while the first chunk is being parsed.
- Overrides:
isEffectivelyPrunedin classAbstractModelMessage<OpenAiCompatibleResponse>- Returns:
trueif the message is effectively pruned.
-
appendContent
Appends text to the main content part or creates a new one.- Parameters:
text- The text to append.
-
appendThoughts
Appends text to the reasoning/thought part or creates a new one.- Parameters:
text- The thought text to append.
-
appendTaggedContent
-

