Skip to content

v3.24 - Excel cell styling, current-row formula refs, upload regressions fixed

Choose a tag to compare

@dvejsada dvejsada released this 11 Aug 12:18
· 7 commits to master since this release
c0badc6

⚠️ Breaking: B[n] in Excel formulas now means "the row I am on"

Previously B[n] and T1.B[n] resolved to the same cell — the first data row of the
table — which made the short form pointless and, worse, wrong: writing =B[0]*C[0] down
a column produced =B4*C4 in every data row, so running totals, per-row products and
growth rates came out silently identical.

B[n] is now relative to the row the formula sits on: B[0] is the current row, B[-1]
the row above, B[1] the row below. T1.B[n] remains the way to point at one fixed cell.

If you have prompts or saved markdown that relied on the old behaviour, replace B[n]
with T1.B[n].
The tool description already documented B[0] as a current-row
reference, so most callers were already writing what they meant.

🩹 Regressions from v3.23, fixed

Template-generated files get their UUID prefix back

Documents produced by the YAML template tools stopped receiving the 8-character UUID
filename prefix on every storage backend, so template output landed under bare,
collision-prone object keys. Files created by the static create_* tools were unaffected.

Both dynamic call sites read the flag as .get("add_unique_prefix", False). Since the
payload is built solely from a template's declared arguments, any template that did not
declare that argument produced an explicit False, which skipped the strategy-based
default resolution entirely. Templates now inherit the same default as every other tool,
and a template that declares add_unique_prefix still controls it outright.

Uploads no longer freeze the event loop

The five static tools used to hand both the document build and the upload to the
background thread pool. Splitting the build out for LibreChat left the upload running
inline on the asyncio event loop — for S3/GCS/Azure that is a network round-trip plus a
signed-URL call, during which no other request is served, health probes included.

Measured with a 500 ms upload: the loop stalled for 517 ms before, 24 ms after.
Anyone running on Kubernetes with RUN_BLOCKING_BY_ASYNCIO_THREAD_ENABLED=true was
exposed to probe timeouts and the pod restarts that follow.

httpx no longer imported on every start

The LibreChat backend was imported at module scope, so every deployment pulled in httpx
regardless of UPLOAD_STRATEGY — and it was not declared in requirements.txt, resolving
only because fastmcp happens to depend on it. It is now imported lazily, like every other
optional backend, and declared explicitly.

✨ New: Excel cell styling

Colour a cell, or apply a named style defined in your own template, with a directive above
the table:

<!-- styles: A[-1]:D[-1]=bg:darkblue;color:white;bold, D[3]=bg:yellow -->

Comma-separated <target>=<attributes> entries, attributes separated by ;. Targets can
be an absolute cell (B2), a table-relative cell (B[0] is the first data row, B[-1]
the header), or a rectangular range of either form. Attributes are bg:, color:, bold,
italic, underline and style:; colours are 6-digit hex or one of 18 names.

Styling runs as a final pass over the finished table, so an explicit instruction beats the
built-in header fill, the formula fill and inline **bold**. It only ever sets colours and
font flags — values, formulas and number formats are left alone.

📈 Excel correctness & robustness

  • Number formats follow the source value instead of flattening it. 50.5% now displays as
    50.5%, not 51%; 1500.75 keeps its decimals instead of showing 1,501. Grouping
    applies to negatives too, and formats are still only imposed from 1000 up so small values
    keep full visible precision.
  • Cross-sheet ranges emit the sheet prefix on the first endpoint only.
  • Generated table-header names are de-duplicated.
  • Workbooks that could not be opened are handled rather than producing a corrupt file, and
    the build path is unified so both entry points share one save routine.
  • Circular-reference detection and typed-column handling corrected.

📄 Documentation

  • The health-probe section documented GET /health and GET /readiness, neither of which
    exists. The real routes are /healthz (startup), /readyz (readiness) and /livez
    (liveness), and it is now recorded that they deliberately bypass the API-key middleware
    so orchestrators can poll them without credentials.
  • add_unique_prefix is documented as what it actually is: unset follows the backend —
    true for LOCAL/S3/GCS/AZURE/MINIO, false for LibreChat.

LibreChat: still not usable

Unchanged from v3.23 — UPLOAD_STRATEGY=LIBRECHAT still depends on a /api/service/files
endpoint that LibreChat has not shipped. Additionally, note that the YAML template tools
fail outright under LIBRECHAT
: they call the synchronous upload path, which rejects that
strategy. That will be addressed alongside the rest of the integration. Keep using
LOCAL / S3 / GCS / AZURE / MINIO.