Shared composition of the budget service and prompt compiler.
Native platform composers and the compatibility cutover both use this binding.
The facade compiler may import capability values and declared service ports;
neither the capability nor the service imports the other. Keeping this owner
outside cutover also avoids a forbidden facade-compiler import of platform.
With no declared window, bind only the service package's counter. With a
window, bind BudgetService.as_token_estimator(); grant a PromptBudget
only when the service derived a PROMPT line from an explicit share. No window
or no share therefore introduces no ceiling. A share without a window is
refused because there is no declared number to divide.
prompt_compile_options
prompt_compile_options(*, context_window: int | None = None, prompt_share: float | None = None, chars_per_token: int | None = None) -> dict[str, Any]
The compile options that bind this deployment's budgeting.
Returned as options for PromptingCapability rather than applied here:
the capability owns the compile, and a composition root that pre-compiled
for it would be a second compiler.
Source code in src/symfonic/agent/prompt_budget.py
| def prompt_compile_options(
*,
context_window: int | None = None,
prompt_share: float | None = None,
chars_per_token: int | None = None,
) -> dict[str, Any]:
"""The compile options that bind this deployment's budgeting.
Returned as options for ``PromptingCapability`` rather than applied here:
the capability owns the compile, and a composition root that pre-compiled
for it would be a second compiler.
"""
if context_window is None:
if prompt_share is not None:
raise ValueError(
"prompt_compile_options(prompt_share=...) needs a context_window: "
"a share is a fraction of a window, and a fraction of an unknown "
"number is not a ceiling. Declare the model's window, or drop the "
"share and compile unbounded."
)
counter = (
HeuristicTokenCounter(chars_per_token=chars_per_token)
if chars_per_token is not None
else HeuristicTokenCounter()
)
return {"estimator": counter}
service = BudgetService.offline(
context_window=context_window,
prompt=prompt_share,
chars_per_token=chars_per_token,
)
options: dict[str, Any] = {"estimator": service.as_token_estimator()}
limit = service.limit_for(BudgetKind.PROMPT)
if limit is not None:
# ``None`` when no share was declared, and that is not a ceiling of
# zero: an undeclared line is unbudgeted, so the compile stays
# unbounded and the counter's numbers are a report rather than a gate.
options["budget"] = PromptBudget(max_total_tokens=limit)
return options
|