Skip to content

Releases: columenlabs/lumen

v0.1.151

Choose a tag to compare

@github-actions github-actions released this 28 Oct 08:22
4a630a8

Key takeaways

  • [Feature] Name the assistant's table: In @columenlabs/lumen-ai, sqlAssistantStore(sql, { table }) now keeps the assistant's documents in a table you name, so a module can use its own table name; without the option it still uses assistant_docs.
  • [Feature] Move one person's rows at a time: In lumen-person, exportRows(sql, table, after, { where }) and rowStats(sql, tables, where) now take a RowFilter ({ sql, args }), so you can export and check only the rows that belong to one person when an old store keeps many people's rows in one table.
  • [Security] Checked table names, bound filter values: The new table option of sqlAssistantStore must be a plain identifier, and the values in a RowFilter's args are bound as parameters, so only the filter's sql condition is code you write yourself.

AI

  • sqlAssistantStore(sql, { table }) takes an optional table name for the assistant's documents.
  • A person-store module can name the table after itself (for example <module>_docs) instead of using the shared default.
  • The default table is still assistant_docs, so existing apps need no change.
  • A table name that is not a plain identifier is rejected.

Tooling

  • exportRows accepts a fourth argument, { where }, and rowStats accepts a third argument, where. Both take a RowFilter of the form { sql, args }, for example { sql: "scope = ?", args: [personId] }.
  • This lets you move a single person's part of a shared table into that person's own store. You no longer need to copy or rewrite the kit's SQL.
  • Both changes are additive, so existing callers behave as before.

Pull requests (1)

Full changelog: v0.1.150...v0.1.151

v0.1.150

Choose a tag to compare

@github-actions github-actions released this 28 Oct 08:01
aff5fc2

Key takeaways

  • [Feature] Read images with a prompt: In @columenlabs/lumen-ai, Assistant.complete now takes an optional images array of CompleteImage ({ mediaType, data }, with base64 data), so background work can read photos, screenshots or scanned pages through the assistant's own models.
  • [Improvement] Images work with both sign-in routes: The images option on Assistant.complete works with an API key or a plan sign-in, and Lumen formats the images for each provider: image blocks go before the text for one, and input_image parts follow an input_text part for the other.
  • [Improvement] Existing calls are untouched: Calls to Assistant.complete that omit images behave exactly as before, so this release needs no change in your app.

AI

  • Assistant.complete accepts an optional images: CompleteImage[], sent together with the prompt.
  • Each CompleteImage is a mediaType plus base64 data.
  • On the first provider, images are sent as image blocks placed before the text.
  • On the second provider, with either an API key or a plan sign-in, images are sent as input_image parts after an input_text part, inside the list input that the assistant already uses.
  • Background jobs that read images, such as photo or handwritten-card imports, can now go through the assistant's models and payer.
  • Calls without images are unchanged.

Docs

  • The "Background work" line in the @columenlabs/lumen-ai README now documents images.

Pull requests (1)

Full changelog: v0.1.149...v0.1.150

v0.1.149

Choose a tag to compare

@github-actions github-actions released this 28 Oct 07:37
3e1b9b3

Key takeaways

  • [Fix] One-shot assistant calls now work on a plan sign-in: In @columenlabs/lumen-ai, assistant.complete and compact now send their prompt as a one-item user message list, so an app signed in with a subscription plan no longer gets a 400 Input must be a list error. API-key sign-ins accept the same shape, so they need no change.

AI

  • assistant.complete and compact share one internal one-shot request helper. It used to send input as bare text, which plan sign-ins reject, so every one-shot call on a plan failed.
  • The helper now sends a single user message, [{ role: 'user', content }].
  • API-key sign-ins behave as before. No code changes are needed in an app.

Pull requests (1)

Full changelog: v0.1.148...v0.1.149

v0.1.148

Choose a tag to compare

@github-actions github-actions released this 28 Oct 07:06
41ee922

Key takeaways

  • [Fix] assistant.complete now answers on a plan sign-in: In @columenlabs/lumen-ai, assistant.complete now streams its call, so an app whose model access comes from a subscription plan sign-in gets an answer instead of a refusal.
  • [Fix] /compact works on a plan sign-in too: The /compact command in @columenlabs/lumen-ai now streams its call the same way, so you can compact a conversation under a plan sign-in.
  • [Improvement] Output cap is sent only with an API key: assistant.complete and /compact now send the output token cap only when you authenticate with an API key, so the same code runs under both sign-in types without errors from the unsupported cap.

AI

  • assistant.complete and /compact used to make a plain, non-streamed call that included an output token cap. A plan sign-in accepts neither, so both now stream, like the chat loop.
  • Both read the raw stream events the way the chat loop does: text deltas first, then the completed, incomplete or failed event. Error events become the same plain-sentence messages you already see in chat.
  • The output token cap is now sent only when you sign in with an API key.
  • Token use on a plan sign-in is metered as free, so ops meters no longer count it as paid usage.
  • There are no changes to the public API and no UI changes. If you call assistant.complete or run /compact, you don't need to change anything.

Pull requests (1)

Full changelog: v0.1.147...v0.1.148

v0.1.147

Choose a tag to compare

@github-actions github-actions released this 28 Oct 07:03
85eb163

Key takeaways

  • [Fix] App switcher tile keeps its full size in the brand row: In LumenAppSwitcher from @columenlabs/lumen-ui, an app's own tile now draws at 32 px inside the sidebar menu button instead of shrinking to 16 px and turning into a circle, so you can drop any size overrides you added to work around it.

Shell

  • The sidebar menu button forces its icons to 16 px, and that rule outranked the tile's plain size-8. The tile now uses size-8!, so it keeps its size and its rounded-square shape in the brand row.
  • Menu rows inside LumenAppSwitcher were already correct and are unchanged.
  • The 32 px tile was checked in a real browser, in light and dark themes, across every app in a live app hub.

Pull requests (1)

Full changelog: v0.1.146...v0.1.147

v0.1.146

Choose a tag to compare

@github-actions github-actions released this 28 Oct 06:49
7e92448

Key takeaways

  • [Feature] One-shot answers for background work: From @columenlabs/lumen-ai/assistant, Assistant.complete(caller, { task, system, prompt, maxTokens?, signal? }) runs a single answer on the tier you mapped to task in createAssistant's tasks option, so jobs like scoring or summaries use the person's model, effort and payer instead of a separate model call.
  • [Feature] Background spend is counted like chat: Assistant.complete follows state.paying to pick the payer (own key, or app key and allowance) and records spend through addSpend, so it appears in Settings spend and counts against the allowance and caps.
  • [Improvement] Clear errors when nobody can pay: Assistant.complete throws an AssistantError with code not_connected, app_cap or own_cap (402) when no payer is available, or upstream (502) when the model fails, so your job can wait on the first group and retry on the second.

AI

  • Added Assistant.complete to @columenlabs/lumen-ai/assistant. It returns one answer with no chat history and no tools.
  • The answer uses the tier set for the task in createAssistant, with the person's chosen model and effort for that tier.
  • It works with Claude and OpenAI keys. A ChatGPT plan sign-in is counted as tokens with no dollar amount, the same as in chat.
  • Output is capped by maxTokens. The default is 1,000 and the most you can ask for is 8,000.
  • You can pass an AbortSignal as signal to cancel a call.
  • Failures are reported as AssistantError with the codes not_connected, app_cap, own_cap (402) or upstream (502).
  • This is not a breaking change. The method is new and nothing else changed.

Docs

  • The README section "A chat assistant" now documents Assistant.complete, including payment, errors and the output cap.

Pull requests (1)

Full changelog: v0.1.145...v0.1.146

v0.1.145

Choose a tag to compare

@github-actions github-actions released this 28 Oct 06:40
55576e3

Key takeaways

  • [Feature] Full-size app tiles in the switcher: In @columenlabs/lumen-ui, the new optional tile boolean on LumenApp (and on SuiteApp, passed through suiteApps) makes LumenAppSwitcher draw the app's icon or iconUrl at the full size of its box, so an app whose icon is already a coloured tile no longer shows a small glyph inside a second box.

Shell

  • LumenApp and SuiteApp accept a new optional tile boolean. Set it when an app's icon or iconUrl is already its whole coloured tile.
  • With tile set, LumenAppSwitcher draws the icon at the box's full size: size-8 in the brand and size-6 in the menu. Before, it drew a size-4 glyph inside the primary box, or a size-3.5 glyph inside a bordered box, which left the glyph at about a third of the box.
  • suiteApps passes tile through, so suite setups need no extra wiring.
  • Apps that don't set tile look the same as before. There are no breaking changes.

Pull requests (1)

Full changelog: v0.1.144...v0.1.145

v0.1.144

Choose a tag to compare

@github-actions github-actions released this 28 Oct 05:44
a15730f

Key takeaways

  • [Feature] One store per person, shared by every app: The new @columenlabs/lumen-person package exports PersonObject, a base class whose SQLite database holds the tables of every app for one person, so an app no longer needs its own per-person object.
  • [Feature] Call a person's store from the Worker: From @columenlabs/lumen-person, personCall and personModule call a person's store from the Worker, and a call made from inside that person's store to the same person runs in place.
  • [Improvement] A bad migration only breaks its own module: In PersonObject, each module now migrates on its first call or wake, with each step in one transaction, so a step that throws makes only that module answer 503 (retried after a minute) while other modules keep working.
  • [Improvement] One alarm shared by every module's wake: In PersonObject, each module's wake time now goes through a single multiplexed alarm, and each wake gets a deadline you can set with the wakeMs option (default 30 s).

Tooling

  • Added the @columenlabs/lumen-person package. It provides PersonObject, a base class for a per-person object whose SQLite database holds every app's tables for one person.
  • Each app is a module that owns its <module>_* tables, its migrations and its wake time. Apps keep their own data, even though the store is shared.
  • From the Worker, use personCall and personModule to reach a person's store. A call made from inside a person's store to that same person runs in place instead of making a second hop.
  • Migrations are isolated per module. Each module migrates on its first call or wake, and every step runs in one transaction. If a step throws, only that module answers 503 and is retried after a minute. Previously one bad migration blocked the whole object.
  • Wakes share one alarm. A _wakes table records the module, the time and the failure count for each wake. Each wake has a deadline of 30 s, set with wakeMs, and a wake that throws is retried.
  • The code moves over from a per-person object that an app already runs in production.
  • The package stands alone, so it does not wait on the vault's approval gate.

Docs

  • The vault README used to say a per-person object base would come later. It now points to @columenlabs/lumen-person.

Pull requests (1)

Full changelog: v0.1.143...v0.1.144

v0.1.143

Choose a tag to compare

@github-actions github-actions released this 28 Oct 05:41
24192b8

Key takeaways

  • [Fix] No more made-up match counts on a search by meaning: In @columenlabs/lumen-ai, a find that uses like no longer returns count, so an assistant stops quoting the pool of up to 50 nearest rows as a number of matches (for example "49 possible matches").
  • [Improvement] A search by meaning now says it is approximate: In @columenlabs/lumen-ai, a like find now returns nearest: true and a note telling the assistant to pick from the rows and not say how many match.
  • [Improvement] FindResult.count is now optional: In @columenlabs/lumen-ai, check that count is defined before you read it from a FindResult, because exact searches still return it and like searches leave it out.

AI

  • A find that uses like returns the nearest rows, at most 50, not every row that fits. It no longer reports that pool size as count.
  • In place of count, the result carries nearest: true and a short note that tells the assistant to pick from the rows and not say how many match.
  • Exact searches are unchanged and still return count.
  • The find tool description and the engine's find rule now state that a like search has no count, so the assistant is told this up front.
  • runFind and FindResult have no consumers outside the find module, so making count optional breaks nothing in Lumen.

Docs

  • The README entry on counts now covers the like case.

Pull requests (1)

Full changelog: v0.1.142...v0.1.143

v0.1.142

Choose a tag to compare

@github-actions github-actions released this 28 Oct 05:13
11cb1fc

Key takeaways

  • [Feature] Find by meaning: In @columenlabs/lumen-ai, a find's like option (for example "something light for a hot day") now searches by meaning when you set meaning: { fields, changed } on the definition and call findTool(def, sql, { meaning: vectorMeaning({ embed, index }) }).
  • [Feature] Background indexing with meaningStep: From @columenlabs/lumen-ai, meaningStep is a budgeted background step you can run on a schedule to embed only rows whose changed column moved past a bookmark your app keeps, so the index stays current without re-embedding everything.
  • [Feature] Worked-out find fields: On FindField, the new sql option lets a number, date or tag field be your app's own SQL over the row, such as json_array_length(t.steps) as a "quick" hint when no time is stored.
  • [Improvement] Reliable counts: Find results from findTool now carry count, returned and same_name, so a tool or model can report totals accurately and see when different rows share a name.

AI

  • Meaning search is opt in per app. Without meaning on the definition, like behaves as before.
  • When like is used, the index returns the nearest 20 to 50 rows. The same SQL then trims them, so filters, words and the app's where still apply, in the index's order.
  • vectorMeaning does one embedding and one index query per find. It accepts an optional namespace, so each person can have their own slice of the index.
  • workersEmbed(ai) is a ready-made embed function for the platform's AI binding. It adds the query prefix the embedding model expects.
  • meaningStep embeds up to 50 changed rows in one embedding call and one upsert. Rows the find hides are removed from the index. It resumes from your bookmark and is safe to run twice at once.
  • If the index does not answer within 3 seconds, like is left out and the rest of the find still runs. The result says that like was skipped.
  • FindField.sql works for number, date and tag fields. Text fields still need a column.
  • Find results now include count, returned and same_name.

Pull requests (1)

Full changelog: v0.1.141...v0.1.142