Skip to content

Releases: columenlabs/lumen

v0.1.137

Choose a tag to compare

@github-actions github-actions released this 27 Oct 23:48
546a9ac

Key takeaways

  • [Fix] Bound web link Test now shows its result: In Assistant.status() from @columenlabs/lumen-ai, an app that reaches its web-fetch service over a service binding now gets the test field on the web link's status, so the Settings ▸ Assistant ▸ Web badge shows the last result instead of staying on "Not tested".
  • [Improvement] Bound link tests are saved: POST /web/test on a bound link now stores its result in its own app-scope doc, so a Test you run is still there after you reload Settings.
  • [Improvement] Read the stored bound-link result from state: The state object has a new reader for the bound link's saved doc, so custom code can read the last test without calling Assistant.status().

Shell

  • The Web section of Settings ▸ Assistant shows the saved test result for a bound link. The badge no longer stays on "Not tested" after a successful Test.
  • There is no UI change. The block already draws the test state from wayTest(state), and it now receives data in the bound case.

AI

  • POST /web/test on a bound link saves its result in a dedicated app-scope doc. A bound link has no token doc to keep the result beside.
  • Assistant.status() reads that doc and returns the test field for the bound case. Before, it returned only { set: true, bound: true }.
  • The state object gains a reader for the bound link doc.
  • The token path is unchanged.
  • There is no new key or table. An older build ignores the new doc, so there is nothing to migrate and no change to make in your app.

Pull requests (1)

Full changelog: v0.1.136...v0.1.137

v0.1.136

Choose a tag to compare

@github-actions github-actions released this 27 Oct 22:37
5c691b3

Key takeaways

  • [Feature] The assistant now knows the current time and when the chat last spoke: In @columenlabs/lumen-ai/assistant, createAssistant now puts a "Bearings" block (the server's current time in the user's zone and in UTC, plus how long ago the last message in the chat was) at the top of every user message, so the model no longer guesses the date.
  • [Feature] Add your own app lines to the bearings: createAssistant accepts a new app name and a bearings: (b, caller) => lines option, and any lines your hook returns appear under the app name; a hook that takes longer than 300 ms or throws is skipped so a turn is never held up.
  • [Feature] Build bearings yourself: @columenlabs/lumen-ai/assistant now exports bearings(), bearingTime, bearingSpan and knownZone for formatting the current time, elapsed spans and validating IANA zone names in your own code.
  • [Improvement] The browser's time zone travels with each message: useAssistantChat from @columenlabs/lumen-ui now sends the browser's IANA zone with every message, using the new optional time_zone field on AssistantMessage from @columenlabs/lumen-ui-types/assistant, which is backward compatible.
  • [Improvement] The system prompt no longer carries a UTC date: The assistant's system rule now tells the model to take today and now from the bearings, and because the bearings sit in the user message rather than the system prompt, the prompt cache still holds.

Layout and widgets

  • useAssistantChat in @columenlabs/lumen-ui now includes the browser's IANA time zone in each message it sends, with no change needed in your app.

Types

  • AssistantMessage in @columenlabs/lumen-ui-types/assistant gains an optional time_zone field. Existing code keeps working.

AI

  • Every user message now starts with a "Bearings" block: the server's clock as now (local time with zone, plus UTC), how long ago the last message in the chat was, the app name, and any lines your app adds.
  • The block is built from the server's clock, and the model is told to use it for today, now and how long ago, never to guess the date.
  • createAssistant takes two new options: app (the name shown in the block) and bearings (a hook that receives the bearings and the caller and returns extra lines).
  • Each app hook has 300 ms to answer. If it is late or throws, only its lines are left out and the turn goes ahead.
  • The block sits at the top of the user message instead of the system prompt, so the cached system prompt stays stable. The old UTC "Today is" date is gone from the system rule.
  • New exports from @columenlabs/lumen-ai/assistant: bearings(), bearingTime, bearingSpan and knownZone.

There are no breaking changes in this release.

Pull requests (1)

Full changelog: v0.1.135...v0.1.136

v0.1.135

Choose a tag to compare

@github-actions github-actions released this 27 Oct 22:06
a8074dc

Key takeaways

  • [Feature] Reach scrapeql web tools over a service binding: In createAssistant from @columenlabs/lumen-ai, the web.scrapeql option now takes an optional fetch (the fetch of a service binding), so the assistant calls the /mcp endpoint through the binding and needs no service token.
  • [Improvement] Assistant settings show a bound link: In the @columenlabs/lumen-ui assistant settings, a bound scrapeql now appears as a LumenConnection with one read-only "App link" way and a Test button for admins, in place of the token form.
  • [Improvement] Status says when the link is bound: In @columenlabs/lumen-ui-types, AssistantStatus.web.scrapeql gains an optional bound boolean, so a client can tell a binding from a stored token.

AI

  • createAssistant's web.scrapeql accepts an optional fetch. When it is set, the assistant reaches the /mcp endpoint through that binding.
  • With scrapeql.fetch set, the scrapeql tools always join the assistant. No stored token is read.
  • scrapeqlTools(url, token | null, fetch) sends token headers only when a token is given.
  • The engine's testScrapeql now tests the link, and a new boundScrapeql getter tells you whether the link is bound.
  • The assistant status reports web.scrapeql = { set: true, bound: true } for a bound link.
  • Routes:
    • PUT /web/scrapeql answers 409 bound, since no token is needed.
    • POST /web/test tests the link.
    • DELETE /web/scrapeql still removes an old stored token.
  • An app that does not pass fetch behaves exactly as before. This is not a breaking change.

Layout and widgets

  • In the assistant settings, a bound scrapeql is shown as a LumenConnection with one read-only "App link" way. Admins get a Test action, and the token form is hidden.

Types

  • AssistantStatus.web.scrapeql in @columenlabs/lumen-ui-types gains bound?: boolean.

Docs

  • The @columenlabs/lumen-ai README documents the new fetch option on web.scrapeql.

Pull requests (1)

Full changelog: v0.1.134...v0.1.135

v0.1.134

Choose a tag to compare

@github-actions github-actions released this 27 Oct 21:43
31ed63f

Key takeaways

  • [Fix] Long Settings section lists now scroll: In LumenSettings from @columenlabs/lumen-ui, the desktop dialog's left section list scrolls on its own when an app has more sections than fit the dialog height, so every section can be reached.
  • [Fix] Search stays pinned above the list: In LumenSettings, the nav search no longer scrolls away, because only the groups live in the new scroll area (data-slot="settings-nav-list") that you can target for styling.
  • [Improvement] Deep-linked sections scroll into view: When LumenSettings opens on a section far down the list, for example through the assistant's settings move or a ?settings=<id> link, that row is now scrolled into view.

Shell

  • LumenSettings on desktop: the section list is now its own scroll area, with the search field pinned above it.
  • The scroll area contains its scrolling (overscroll-contain), so reaching the end of the list does not scroll the page behind the dialog.
  • The selected section is scrolled into view when Settings opens on it.
  • Phone is unchanged: it still uses the LumenSelector picker.
  • Not breaking. No prop changes, and existing apps get the fix without edits.

Docs

  • New story App shell/LumenShell ▸ Long Settings with 7 groups of 4 sections each, for checking how Settings behaves when the section list is taller than the dialog.

Pull requests (1)

Full changelog: v0.1.133...v0.1.134

v0.1.133

Choose a tag to compare

@github-actions github-actions released this 27 Oct 21:18
f64e762

Key takeaways

  • [Fix] savedAnswers no longer crashes on import when the browser blocks storage: In @columenlabs/lumen-ui, savedAnswers now reads indexedDB inside a try, so a browser that throws a SecurityError on window.indexedDB no longer stops your app from drawing.
  • [Improvement] Missing storage falls back to the server: When indexedDB is unavailable, savedAnswers switches to its no-op persister, so every load asks the server and your app still gets its data.
  • [Fix] A throwing open is retried later: If indexedDB.open throws synchronously, savedAnswers now rejects the promise instead of throwing, so the store is tried again on a later call.

Pickers and forms

  • savedAnswers no longer throws when the browser refuses storage, including when merely reading indexedDB raises an error. This used to fail at module load and leave the app blank.
  • With no usable storage, savedAnswers uses the no-op persister. Nothing is cached locally, and each load goes to the server.
  • A synchronous throw from open now becomes a rejected promise. A stuck or missing store falls back to the server, and the next attempt can open it normally.
  • In an app that uses savedAnswers, the "no storage" case used to render no data. It now draws in about 0.6 s, and the other returning-user cases still pass.

Pull requests (1)

Full changelog: v0.1.132...v0.1.133

v0.1.132

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:58
c5862af

Key takeaways

  • [Breaking] StatusMessages no longer takes max: In @columenlabs/lumen-ui, delete the max prop from every <StatusMessages> you render, because the component now always shows a single line and TypeScript will flag any call that still passes it.
  • [Improvement] The status bar shows only the latest message: StatusMessages in @columenlabs/lumen-ui renders the first entry of messages (newest first). A new message replaces the one on screen, so two different errors no longer appear as two chips side by side.
  • [Improvement] Earlier messages sit behind the +N chip: In StatusMessages, every message except the newest is listed behind the +N chip in the order it was posted. Errors are no longer sorted ahead of other messages, so the newest message always wins.
  • [Improvement] A wider status line: The --status-message-max CSS variable is now min(40rem, 45vw) from 768px and 55vw below that, so the single line has more room. Override the variable if your layout needs a different width.

Shell

  • StatusMessages shows one line: the newest message.
  • Older messages are reachable through the +N chip instead of being drawn next to the latest one.
  • Repeated errors still collapse into one line with a count (for example ×3), followed by +N for the other distinct messages.
  • On phones the line is one row, and a tap shows the full text.
  • The max prop is removed. This is a breaking change for any caller that passes it. In an app that uses it, delete the prop.

Theme

  • --status-message-max is wider: min(40rem, 45vw) from 768px and 55vw below. The status line no longer shares its row with a second message.

Docs

  • The contributor guidance for the status bar now says "latest message only".

Tooling

  • Lint, type-check and the package build all pass on this change.

Pull requests (1)

Full changelog: v0.1.131...v0.1.132

v0.1.131

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:38
66a5f86

Key takeaways

  • [Fix] Whole-number axes on stacked columns: In @columenlabs/lumen-ui, StackedColumns now labels its value axis in whole steps of 1, 2 or 5 × 10ⁿ (never below 1) when every plotted value is a whole number, so a day with 2 API calls reads 0, 1, 2 instead of 0, 0.5, 1, 1.5, 2.
  • [Fix] Whole-number axes on the line chart: The line chart in @columenlabs/lumen-ui now uses the same niceTicks rule, so count data such as small usage totals no longer shows fractional ticks, while charts with fractional values are unchanged.
  • [Fix] One main landmark per page: In @columenlabs/lumen-ui, PageBody now renders a div instead of a <main>, so pages inside the shell no longer nest <main> in the shell's SidebarInset (which is already the page's <main>) and screen readers hear a single main landmark.

Charts

  • niceTicks, which sets the axis steps for StackedColumns and the line chart, now picks whole steps of 1, 2 or 5 × 10ⁿ, never below 1, when all plotted values are whole numbers.
  • Charts with any fractional value keep their existing tick steps.

Layout and widgets

  • PageBody renders a div rather than a <main>, which removes invalid nested <main> elements and the doubled landmark.
  • This is not a breaking change. If an app styled or queried PageBody as a main element, target the PageBody element another way.

Pull requests (1)

Full changelog: v0.1.130...v0.1.131

v0.1.130

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:34
207ee52

Key takeaways

  • [Feature] fetchWithin puts a deadline on any request: From @columenlabs/lumen-ui, call fetchWithin(url, init, ms) to make a raw fetch reject with a TimeoutError after ms milliseconds. A signal you pass in init still aborts it, and the new FETCH_MS constant (15 s) is the default to pass.
  • [Fix] Built-in requests no longer wait forever: In @columenlabs/lumen-ui, the app switcher, What's new, notifications (reads and writes), tasks and market data now give up after FETCH_MS. The new-build check gives up after 5 s. A stalled network can no longer leave these hanging. The assistant's chat stream deliberately keeps the caller's signal, since a stream can legitimately run for a long time.
  • [Improvement] Prod safety rules are now concrete: The repo's contributor guide now says where timeouts belong (savedAnswers, API_TIMEOUT_MS, fetchWithin, and AbortSignal.timeout in worker code). It also says that fixing up old data on read should go through waitUntil, and that a changed JSON shape gets a new key version. The review checklist now blocks any pull request that breaks one of these rules.

Nothing here is breaking, and there is no visual change.

Shell

  • The app switcher, What's new, notifications, tasks and market data requests now use fetchWithin with the 15 s FETCH_MS bound.
  • The new-build check uses a shorter 5 s bound, because it runs in the background and should fail fast.
  • A caller's own signal still cancels these requests as before.
  • The assistant's chat stream is intentionally left unbounded by the timeout and keeps the caller's signal.

Docs

  • The Prod safety section of the contributor guide now spells out the rule "every wait has a timeout".
    • It lists where the bounds live: savedAnswers, API_TIMEOUT_MS, fetchWithin, and AbortSignal.timeout in worker code.
    • It says that fix-ups of old data on read go to waitUntil.
    • It says that a new JSON shape gets a new key version.

Tooling

  • The review checklist now treats a break of any Prod safety rule as a reason to block a pull request.

Pull requests (1)

Full changelog: v0.1.129...v0.1.130

v0.1.129

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:30
4806f73

Key takeaways

  • [Improvement] Clearer Admins tile caption: In LumenPeople from @columenlabs/lumen-ui, the Admins tile caption now reads "Can’t remove the last admin" instead of "at least 1 always kept", so your users see the rule in plain words with no prop or config change.

Layout and widgets

  • The Admins tile in LumenPeople now says "Can’t remove the last admin" where it used to say "at least 1 always kept".
  • This is a copy change only. The layout and props are unchanged, so there is nothing to update in your app. If you match on the old caption text in tests or snapshots, update it.

Pull requests (1)

Full changelog: v0.1.128...v0.1.129

v0.1.128

Choose a tag to compare

@github-actions github-actions released this 27 Oct 20:24
bbf8387

Key takeaways

  • [Fix] Requests no longer hang forever: apiJson from @columenlabs/lumen-ui now gives up after 15 s for reads and 60 s for writes, so a request the network never answers no longer leaves a page loading indefinitely.
  • [Feature] Set a timeout per call: pass timeoutMs in the init argument of apiJson to override the limit for one request, or import the exported API_TIMEOUT_MS constant to see the defaults.
  • [Improvement] Timeouts land in your existing error states: when apiJson times out it throws an ApiError with status 0 ("The server didn't answer in time …"), which is reported and counted like a network failure, so the error and empty states you already handle take over without code changes.

Shell

  • apiJson now has a timeout. Reads wait up to 15 s and writes up to 60 s, because writes may be doing slow work the person asked for.
  • API_TIMEOUT_MS is now exported and holds the default limits.
  • A timeout throws ApiError with status 0, so code that already handles network failures needs no change.
  • init.timeoutMs sets a different limit for a single call.
  • A signal you pass in still aborts the request. That abort is still rethrown as an AbortError for you to handle, and it is not treated as a timeout.
  • This is not a breaking change. The signature only gains an optional field.

Pull requests (1)

Full changelog: v0.1.127...v0.1.128