Repository navigation
Releases: columenlabs/lumen
Releases · columenlabs/lumen
Release list
v0.1.151
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 usesassistant_docs. - [Feature] Move one person's rows at a time: In lumen-person,
exportRows(sql, table, after, { where })androwStats(sql, tables, where)now take aRowFilter({ 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
tableoption ofsqlAssistantStoremust be a plain identifier, and the values in aRowFilter'sargsare bound as parameters, so only the filter'ssqlcondition 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
exportRowsaccepts a fourth argument,{ where }, androwStatsaccepts a third argument,where. Both take aRowFilterof 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
Key takeaways
- [Feature] Read images with a prompt: In
@columenlabs/lumen-ai,Assistant.completenow takes an optionalimagesarray ofCompleteImage({ mediaType, data }, with base64data), 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
imagesoption onAssistant.completeworks 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, andinput_imageparts follow aninput_textpart for the other. - [Improvement] Existing calls are untouched: Calls to
Assistant.completethat omitimagesbehave exactly as before, so this release needs no change in your app.
AI
Assistant.completeaccepts an optionalimages: CompleteImage[], sent together with the prompt.- Each
CompleteImageis amediaTypeplus base64data. - 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_imageparts after aninput_textpart, 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-aiREADME now documentsimages.
Pull requests (1)
Full changelog: v0.1.149...v0.1.150
v0.1.149
Key takeaways
- [Fix] One-shot assistant calls now work on a plan sign-in: In @columenlabs/lumen-ai,
assistant.completeandcompactnow send their prompt as a one-item user message list, so an app signed in with a subscription plan no longer gets a400 Input must be a listerror. API-key sign-ins accept the same shape, so they need no change.
AI
assistant.completeandcompactshare one internal one-shot request helper. It used to sendinputas 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
Key takeaways
- [Fix]
assistant.completenow answers on a plan sign-in: In @columenlabs/lumen-ai,assistant.completenow streams its call, so an app whose model access comes from a subscription plan sign-in gets an answer instead of a refusal. - [Fix]
/compactworks on a plan sign-in too: The/compactcommand 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.completeand/compactnow 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.completeand/compactused 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.completeor run/compact, you don't need to change anything.
Pull requests (1)
Full changelog: v0.1.147...v0.1.148
v0.1.147
Key takeaways
- [Fix] App switcher tile keeps its full size in the brand row: In
LumenAppSwitcherfrom @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 usessize-8!, so it keeps its size and its rounded-square shape in the brand row. - Menu rows inside
LumenAppSwitcherwere 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
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 totaskincreateAssistant'stasksoption, 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.completefollowsstate.payingto pick the payer (own key, or app key and allowance) and records spend throughaddSpend, so it appears in Settings spend and counts against the allowance and caps. - [Improvement] Clear errors when nobody can pay:
Assistant.completethrows anAssistantErrorwith codenot_connected,app_caporown_cap(402) when no payer is available, orupstream(502) when the model fails, so your job can wait on the first group and retry on the second.
AI
- Added
Assistant.completeto@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
AbortSignalassignalto cancel a call. - Failures are reported as
AssistantErrorwith the codesnot_connected,app_cap,own_cap(402) orupstream(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
Key takeaways
- [Feature] Full-size app tiles in the switcher: In
@columenlabs/lumen-ui, the new optionaltileboolean onLumenApp(and onSuiteApp, passed throughsuiteApps) makesLumenAppSwitcherdraw the app'siconoriconUrlat 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
LumenAppandSuiteAppaccept a new optionaltileboolean. Set it when an app'siconoriconUrlis already its whole coloured tile.- With
tileset,LumenAppSwitcherdraws the icon at the box's full size:size-8in the brand andsize-6in the menu. Before, it drew asize-4glyph inside the primary box, or asize-3.5glyph inside a bordered box, which left the glyph at about a third of the box. suiteAppspassestilethrough, so suite setups need no extra wiring.- Apps that don't set
tilelook the same as before. There are no breaking changes.
Pull requests (1)
Full changelog: v0.1.144...v0.1.145
v0.1.144
Key takeaways
- [Feature] One store per person, shared by every app: The new
@columenlabs/lumen-personpackage exportsPersonObject, 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,personCallandpersonModulecall 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 thewakeMsoption (default 30 s).
Tooling
- Added the
@columenlabs/lumen-personpackage. It providesPersonObject, 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
personCallandpersonModuleto 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
_wakestable records the module, the time and the failure count for each wake. Each wake has a deadline of 30 s, set withwakeMs, 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
Key takeaways
- [Fix] No more made-up match counts on a search by meaning: In @columenlabs/lumen-ai, a find that uses
likeno longer returnscount, 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
likefind now returnsnearest: trueand a note telling the assistant to pick from the rows and not say how many match. - [Improvement]
FindResult.countis now optional: In @columenlabs/lumen-ai, check thatcountis defined before you read it from aFindResult, because exact searches still return it andlikesearches leave it out.
AI
- A find that uses
likereturns the nearest rows, at most 50, not every row that fits. It no longer reports that pool size ascount. - In place of
count, the result carriesnearest: trueand 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
likesearch has no count, so the assistant is told this up front. runFindandFindResulthave no consumers outside the find module, so makingcountoptional breaks nothing in Lumen.
Docs
- The README entry on counts now covers the
likecase.
Pull requests (1)
Full changelog: v0.1.142...v0.1.143
v0.1.142
Key takeaways
- [Feature] Find by meaning: In
@columenlabs/lumen-ai, a find'slikeoption (for example "something light for a hot day") now searches by meaning when you setmeaning: { fields, changed }on the definition and callfindTool(def, sql, { meaning: vectorMeaning({ embed, index }) }). - [Feature] Background indexing with
meaningStep: From@columenlabs/lumen-ai,meaningStepis a budgeted background step you can run on a schedule to embed only rows whosechangedcolumn moved past a bookmark your app keeps, so the index stays current without re-embedding everything. - [Feature] Worked-out find fields: On
FindField, the newsqloption lets a number, date or tag field be your app's own SQL over the row, such asjson_array_length(t.steps)as a "quick" hint when no time is stored. - [Improvement] Reliable counts: Find results from
findToolnow carrycount,returnedandsame_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
meaningon the definition,likebehaves as before. - When
likeis used, the index returns the nearest 20 to 50 rows. The same SQL then trims them, so filters, words and the app'swherestill apply, in the index's order. vectorMeaningdoes 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-madeembedfunction for the platform's AI binding. It adds the query prefix the embedding model expects.meaningStepembeds 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,
likeis left out and the rest of the find still runs. The result says thatlikewas skipped. FindField.sqlworks for number, date and tag fields. Text fields still need a column.- Find results now include
count,returnedandsame_name.
Pull requests (1)
Full changelog: v0.1.141...v0.1.142