104 messages: list[dict],
107 tool_catalog: list[dict] |
None =
None,
108 allowed_tools: list[str] |
None =
None,
109 reasoning_mode: str =
"off",
110 output_max_tokens: int |
None =
None,
111) -> ProviderRequestPlan:
112 """Decompose a chat ``messages`` list into a :class:`ProviderRequestPlan`.
114 ``messages[0]`` is split at the ``## Tools`` boundary into ``policy_prompt`` +
115 ``tool_reference`` (pure slicing → concatenation reproduces it byte-for-byte).
116 ``variable_context`` is the sentinel-marked message's content (informational,
117 for renderers that rebuild); ``conversation`` is every message after
118 ``messages[0]`` in order, so the default chat renderer reproduces the list
119 exactly. Never mutates *messages*.
123 model=model, policy_prompt=
"", tool_reference=
"", variable_context=
"",
124 conversation=[], tool_catalog=list(tool_catalog
or []),
125 allowed_tools=allowed_tools, reasoning_mode=reasoning_mode,
126 output_max_tokens=output_max_tokens,
132 if messages[0].get(
"role") ==
"system":
133 s0 = messages[0].get(
"content")
or ""
134 idx = s0.find(_TOOL_SECTION_MARKER)
136 policy_prompt, tool_reference = s0,
""
138 policy_prompt, tool_reference = s0[:idx], s0[idx:]
139 conversation = list(messages[1:])
141 policy_prompt, tool_reference =
"",
""
142 conversation = list(messages)
144 variable_context =
""
146 for m
in conversation:
147 if (m.get(
"content")
or "").startswith(VARIABLE_CONTEXT_SENTINEL):
148 variable_context = m[
"content"]
153 policy_prompt=policy_prompt,
154 tool_reference=tool_reference,
155 variable_context=variable_context,
156 conversation=conversation,
157 tool_catalog=list(tool_catalog
or []),
158 allowed_tools=allowed_tools,
159 reasoning_mode=reasoning_mode,
160 output_max_tokens=output_max_tokens,
ProviderRequestPlan build_request_plan(list[dict] messages, str model, *, list[dict]|None tool_catalog=None, list[str]|None allowed_tools=None, str reasoning_mode="off", int|None output_max_tokens=None)