nemo_automodel.components.models.kimi_k3.encoding

View as Markdown

Kimi K3 XTML encoding helpers.

This module keeps chat rendering in Python. Callers that need token IDs should consume EncodeSegment objects directly: structural markers may be encoded as tiktoken special tokens, while user/tool text and attribute values are encoded as ordinary text.

Module Contents

Classes

Functions

Data

CLOSE_TOKEN

END_OF_MSG_TOKEN

IMAGE_PLACEHOLDER

OPEN_TOKEN

SEP_TOKEN

_VALID_THINKING_EFFORTS

API

class nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment(
text: str,
allow_special: bool = False,
is_assistant: bool = False
)
Dataclass
allow_special
bool = False
is_assistant
bool = False
text
str
class nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState(
image_prompts: typing.Optional[list[str]] = None
)
index
= 0
nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState.assert_consumed() -> None
nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState.next_prompt() -> str
nemo_automodel.components.models.kimi_k3.encoding._append_text(
segments: list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment],
text: typing.Any,
image_state: nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState
) -> None
nemo_automodel.components.models.kimi_k3.encoding._attr(
key: str,
value: typing.Any
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._close_tag(
tag: str
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._control(
text: str
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._end_of_msg() -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._escape_attr_value(
value: typing.Any
) -> str
nemo_automodel.components.models.kimi_k3.encoding._get_value(
obj: typing.Any,
key: str,
default: typing.Any = None
) -> typing.Any
nemo_automodel.components.models.kimi_k3.encoding._internal_system_message(
message_type: str,
body: str
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._is_mapping(
value: typing.Any
) -> bool
nemo_automodel.components.models.kimi_k3.encoding._json_compact(
value: typing.Any
) -> str
nemo_automodel.components.models.kimi_k3.encoding._mark_assistant(
segments: list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._open_tag(
tag: str,
attrs: typing.Iterable[tuple[str, typing.Any]] = ()
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._render_assistant_segments(
message: dict[str, typing.Any],
image_state: nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState,
thinking: bool = True
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._render_content_segments(
content: typing.Any,
image_state: nemo_automodel.components.models.kimi_k3.encoding._ImagePromptState
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._render_tool_declare(
tools: typing.Any,
dynamic: bool = False
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._segment(
text: typing.Any,
allow_special: bool = False
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._text(
text: typing.Any
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding._tool_call_id_index(
tool_calls: typing.Any
) -> dict

Map assistant tool_calls[].id to (1-based position, function name).

The position mirrors the chat template’s enumeration over tool_calls (every entry advances the position, even an id-less one). Duplicate ids keep their first occurrence.

nemo_automodel.components.models.kimi_k3.encoding._xtml_type(
value: typing.Any
) -> str
nemo_automodel.components.models.kimi_k3.encoding._xtml_value(
value: typing.Any
) -> str
nemo_automodel.components.models.kimi_k3.encoding.build_chat_segments(
messages: list[typing.Any],
tools: typing.Optional[list[dict]] = None,
add_generation_prompt: bool = True,
thinking: bool = True,
image_prompts: typing.Optional[list[str]] = None,
kwargs: typing.Any = {}
) -> list[nemo_automodel.components.models.kimi_k3.encoding.EncodeSegment]
nemo_automodel.components.models.kimi_k3.encoding.deep_sort_dict(
obj: typing.Any
) -> typing.Any
nemo_automodel.components.models.kimi_k3.encoding.extract_response_schema(
response_format: typing.Any
) -> typing.Any
nemo_automodel.components.models.kimi_k3.encoding.is_batched_conversation(
conversation: typing.Any
) -> bool
nemo_automodel.components.models.kimi_k3.encoding.normalize_conversation(
conversation: typing.Any
) -> typing.Any
nemo_automodel.components.models.kimi_k3.encoding.normalize_message(
message: typing.Any
) -> typing.Any
nemo_automodel.components.models.kimi_k3.encoding.normalize_tool_arguments(
arguments: typing.Any
) -> tuple[dict[str, typing.Any], typing.Optional[str]]
nemo_automodel.components.models.kimi_k3.encoding.normalize_xtml_tool_result_messages(
messages: list[typing.Any]
) -> list[typing.Any]

Re-sort K3 XTML tool results into assistant tool_calls order.

Serving frameworks generally deliver tool results already in call order. A direct Transformers caller, however, may pass OpenAI-style tool messages in any order, so each run of consecutive tool messages is matched against the most recent preceding assistant tool_calls by opaque tool_call_id == tool_calls[].id (K3 drops the func:index format requirement) and sorted by the matched 1-based position. The matched call is authoritative, so each matched message’s tool is set to that call’s function name — this keeps an explicit (and possibly stale) tool/name from drifting out of sync with the reordered position. index is still derived from the rendered position by the chat template. A run that cannot be fully matched is left untouched. Re-running is idempotent.

This function is side-effect free: matched tool messages are shallow-copied before their tool/name is rewritten, and every other message is appended to the output as-is. The input list and its message objects are never mutated.

nemo_automodel.components.models.kimi_k3.encoding.CLOSE_TOKEN = '<|close|>'
nemo_automodel.components.models.kimi_k3.encoding.END_OF_MSG_TOKEN = '<|end_of_msg|>'
nemo_automodel.components.models.kimi_k3.encoding.IMAGE_PLACEHOLDER = '<|kimi_image_placeholder|>'
nemo_automodel.components.models.kimi_k3.encoding.OPEN_TOKEN = '<|open|>'
nemo_automodel.components.models.kimi_k3.encoding.SEP_TOKEN = '<|sep|>'
nemo_automodel.components.models.kimi_k3.encoding._VALID_THINKING_EFFORTS = {'low', 'medium', 'high', 'max'}