@columenlabs/lumen-ai 0.1.246 → 0.1.247
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/agent/stream.js +9 -1
- package/dist/assistant/engine.js +11 -12
- package/dist/assistant/state.d.ts +20 -1
- package/dist/assistant/state.js +58 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ app.all('/api/assistant/*', (c) => routes(c.req.raw));
|
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
- **Providers.** A tier runs any model in `models` (Claude's and OpenAI's by default, `CLAUDE_MODELS`, `OPENAI_MODELS`): Claude through Anthropic's Messages API, OpenAI through the Responses API, with the same tools, drafts, Stop and caps. xAI's Grok models (`XAI_MODELS`) are opt in: an app that lists them gets an xAI row in Model providers (an API key, `xai-…`); they run on the same Responses client at `XAI_BASE_URL` (`https://api.x.ai/v1`). xAI has no public sign-in for other apps, so Grok takes a key only. A hand-off may cross providers. The advisor and prompt caching marks are Claude's only.
|
|
109
|
-
- **Keys.** Each provider has its own keys (`?provider=anthropic|openai|xai` on the key routes). An admin pastes the shared key everyone uses (`PUT /key`); it is tested with one free call before it is kept, then sealed, and no route returns it. A person may add their own (`PUT /my-key`), with one monthly cap on their own keys (`PUT /my-key/cap`).
|
|
109
|
+
- **Keys.** Each provider has its own keys (`?provider=anthropic|openai|xai` on the key routes). An admin pastes the shared key everyone uses (`PUT /key`); it is tested with one free call before it is kept, then sealed, and no route returns it. A person may add their own (`PUT /my-key`), with one monthly cap on their own keys (`PUT /my-key/cap`). The cap counts what their own API keys spent this month on providers they can still pay with; a plan sign-in (ChatGPT) costs them nothing per call, so its calls count $0 (each own spend row records its `way`). Status gives that count as `spend.own_used`.
|
|
110
110
|
- **ChatGPT sign-in.** In place of their own OpenAI key a person may sign in with their ChatGPT plan (`POST /my-signin`, then `POST /my-signin/finish {url}`): the sign-in opens in a new tab and ends on `http://127.0.0.1:1455/auth/callback`, a page that does not load, whose address the person pastes back. The tokens are sealed as their own key and refreshed before they run out; answers on the plan count tokens and no dollars.
|
|
111
111
|
- **Who pays.** The person's pick (the shared keys by default) while it has a key for the tier's provider and money left this month under its cap (an admin sets the shared keys' cap per person, `PUT /app`), else the other; with neither the panel says why.
|
|
112
112
|
- **Tools.** Each group is Off, Read, Read + draft or Read + write per person. A tool is a read when its MCP `readOnlyHint` is set. On Read + draft a write only drafts a card, and runs as the person when they press Save, after access is checked again. A group with `readOnly: true` (read tools only) is offered Off or Read alone. Read + write is offered only for a group with `writes: true`: its writes run at once, and with `undo` set each one's line in the chat has Undo, which calls `undo(caller, { tool, args, result })`; the model is told what was undone. Cards drafted one after another show as one stack with Save all. Use `mcpServerTools` (an SDK `McpServer`), `mcpFetchTools` (a server served as a fetch handler, any SDK), `remoteMcpTools` or `plainTools`.
|
|
@@ -253,6 +253,8 @@ Drafts and writes are cards in the chat's own storage (`lumen_cards` in the agen
|
|
|
253
253
|
|
|
254
254
|
**The panel.** `LumenAssistant` reads a Think chat with no change. `ask(input, sink)` runs one answer and sends the panel's own events (`AssistantEvent`: the chat, the text, each tool line, cards, hand-off sections, advice, the use) to `sink`. The app's `POST /chat` returns `askResponse((sink) => chat.ask(input, sink), { signal, stop: () => chat.stop() })`, the same server-sent events `assistantRoutes` sends. `view()` gives a stored chat as the panel's items, and `usage()` gives the chat's use so far. A card's id is its tool call's, so the panel's Save, Dismiss and Undo go to `saveCard`, `dismissCard` and `undoCard`. The app keeps the list of chats, and each chat is its own agent, such as a facet of the person's store. `chunkEvents` and `itemsOf` are the mapping, for an app that streams some other way.
|
|
255
255
|
|
|
256
|
+
**A write in progress.** A tool line starts (`step_start`) as soon as the model starts the call, while it is still writing the arguments. For a Read + write tool it carries `write: true`, and `useAssistantChat` marks that running step `writing` until its result lands or the answer ends, so an app can show what the tool changes as being changed now (a pending edit is not ready to accept while the model rewrites it).
|
|
257
|
+
|
|
256
258
|
**Steps.** One answer makes at most `plan.maxSteps` model calls (`MAX_STEPS`, 8). The last one runs with no tools and `LAST_STEP_NOTE`, so an answer always ends in words: what it found, and what is left when the task did not fit.
|
|
257
259
|
|
|
258
260
|
**Steer and queue.** While an answer runs, the panel's box stays open: Enter steers the message into the answer (`steer(message)` on the agent; the app routes `POST /chats/:id/steer` `{ message }` to it and answers `{ steered }`), Alt+Enter queues it for after. A steer joins at the answer's next step, after the tool it is on, with `STEER_NOTE` before it for the model; the panel shows it there marked Steered (event `steered`), and `view()` keeps it in place (`SteerNote`, under the message the answer is to). A steer the answer ends before reading comes back as `unsteered` and goes first in the queue. `plan.steer: false` turns it off for a model; an app without the route (404) shows Queue only. Queued messages each go as their own message when the answer before them ends; each has Steer now, Edit and Remove.
|
package/dist/agent/stream.js
CHANGED
|
@@ -108,7 +108,15 @@ export function chunkEvents(o = {}) {
|
|
|
108
108
|
}
|
|
109
109
|
if (name === 'escalate' || name === 'screen' || o.kindOf?.(name) === 'draft')
|
|
110
110
|
return [];
|
|
111
|
-
|
|
111
|
+
// A tool that makes a change at once says so as it starts, so an app can show that what it
|
|
112
|
+
// changes is being changed now, before the model has finished writing the call.
|
|
113
|
+
const write = o.kindOf?.(name) === 'write';
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
event: 'step_start',
|
|
117
|
+
data: { id, tool: name, title: stepTitle(name), ...(write ? { write } : {}) },
|
|
118
|
+
},
|
|
119
|
+
];
|
|
112
120
|
}
|
|
113
121
|
case 'tool-input-available': {
|
|
114
122
|
const c = calls.get(id) ?? { name: String(chunk.toolName ?? ''), t0: Date.now() };
|
package/dist/assistant/engine.js
CHANGED
|
@@ -15,7 +15,7 @@ import { aiModel, turnSettings } from '../agent/models.js';
|
|
|
15
15
|
import { bearings } from './bearings.js';
|
|
16
16
|
import { CHATGPT_REDIRECT, SigninError, finishChatgpt, startChatgpt, testChatgpt, } from './chatgpt.js';
|
|
17
17
|
import { ALL_MODELS, DEFAULT_OUT, Meter, PROVIDERS, XAI_BASE_URL, effortParams, } from './models.js';
|
|
18
|
-
import { DEFAULT_CAP, State, keyDocName, keyState, planDocName, waitText, } from './state.js';
|
|
18
|
+
import { DEFAULT_CAP, State, keyDocName, keyState, ownKeyUsd, planDocName, waitText, withProvider, } from './state.js';
|
|
19
19
|
import { Docs } from './store.js';
|
|
20
20
|
import { toolName, withDeadline } from './tools.js';
|
|
21
21
|
import { scrapeqlTools, webFetchTools } from './web.js';
|
|
@@ -388,7 +388,7 @@ export class Assistant {
|
|
|
388
388
|
const onShared = sharedLabel ? end.parts.filter((x) => x.label === sharedLabel) : [];
|
|
389
389
|
const onPayer = onShared.length ? end.parts.filter((x) => !onShared.includes(x)) : end.parts;
|
|
390
390
|
await this.state
|
|
391
|
-
.addSpend(caller.id, paying.payer, onPayer, { task: 'chat', ms: end.ms }, free)
|
|
391
|
+
.addSpend(caller.id, paying.payer, onPayer, { task: 'chat', ms: end.ms }, free, paying.plans)
|
|
392
392
|
.catch(() => undefined);
|
|
393
393
|
if (onShared.length)
|
|
394
394
|
await this.state
|
|
@@ -400,7 +400,7 @@ export class Assistant {
|
|
|
400
400
|
id: `chat:${input.chat}`,
|
|
401
401
|
kind: 'chat',
|
|
402
402
|
title: message.split('\n')[0] || 'Chat',
|
|
403
|
-
own_usd: paying
|
|
403
|
+
own_usd: ownKeyUsd(paying, onPayer),
|
|
404
404
|
}, end.parts)
|
|
405
405
|
.catch(() => undefined);
|
|
406
406
|
const total = end.parts.reduce((a, m) => ({
|
|
@@ -551,7 +551,7 @@ export class Assistant {
|
|
|
551
551
|
// The binding's last test has no token doc to sit in; it is read beside the rest.
|
|
552
552
|
const linkTest = this.o.web?.scrapeql?.fetch ? this.state.scrapeqlLink() : null;
|
|
553
553
|
const ownWays = await this.ownWaysOf(caller);
|
|
554
|
-
const [p, providers, scrapeql, spend, appCap, ownCap, { paying, wait }] = await Promise.all([
|
|
554
|
+
const [p, providers, scrapeql, spend, appCap, ownCap, { paying, wait }, ownUsed] = await Promise.all([
|
|
555
555
|
this.state.person(caller.id),
|
|
556
556
|
Promise.all(this.providers.map(async (id) => {
|
|
557
557
|
const [doc, key, own, plan, use] = await Promise.all([
|
|
@@ -584,6 +584,7 @@ export class Assistant {
|
|
|
584
584
|
this.state.appCap(),
|
|
585
585
|
this.state.ownCap(caller.id),
|
|
586
586
|
this.rulesFor(caller, main.id).then(({ rules }) => this.state.paying(caller.id, mainModel.provider, rules)),
|
|
587
|
+
this.state.ownUsed(caller.id, ownWays),
|
|
587
588
|
]);
|
|
588
589
|
const link = await linkTest;
|
|
589
590
|
const tiers = await Promise.all(this.tiers.map(async (t) => {
|
|
@@ -656,7 +657,8 @@ export class Assistant {
|
|
|
656
657
|
usd: spend.rows.reduce((a, r) => a + r.usd, 0),
|
|
657
658
|
cap: paying?.cap ?? null,
|
|
658
659
|
payer: paying?.payer ?? null,
|
|
659
|
-
rows: spend.rows,
|
|
660
|
+
rows: withProvider(spend.rows),
|
|
661
|
+
own_used: ownUsed,
|
|
660
662
|
},
|
|
661
663
|
...(this.o.allowance ? { allowance: await this.allowanceState(caller) } : {}),
|
|
662
664
|
};
|
|
@@ -1044,7 +1046,7 @@ export class Assistant {
|
|
|
1044
1046
|
}
|
|
1045
1047
|
finally {
|
|
1046
1048
|
const part = s.meter.part();
|
|
1047
|
-
await this.state.addSpend(caller.id, paying.payer, [part], { task: o.tag ?? o.task, ms: Date.now() - began }, free);
|
|
1049
|
+
await this.state.addSpend(caller.id, paying.payer, [part], { task: o.tag ?? o.task, ms: Date.now() - began }, free, paying.plans);
|
|
1048
1050
|
const task = this.tasks.find((t) => t.id === o.task);
|
|
1049
1051
|
await this.state
|
|
1050
1052
|
.addUsage(caller.id, {
|
|
@@ -1052,7 +1054,7 @@ export class Assistant {
|
|
|
1052
1054
|
kind: 'task',
|
|
1053
1055
|
task: o.task,
|
|
1054
1056
|
title: o.run?.title ?? task?.label ?? o.task,
|
|
1055
|
-
own_usd: paying
|
|
1057
|
+
own_usd: ownKeyUsd(paying, [part]),
|
|
1056
1058
|
}, [part])
|
|
1057
1059
|
.catch(() => undefined);
|
|
1058
1060
|
}
|
|
@@ -1132,10 +1134,7 @@ export class Assistant {
|
|
|
1132
1134
|
usd,
|
|
1133
1135
|
model: m.id,
|
|
1134
1136
|
};
|
|
1135
|
-
await this.state.addSpend(caller.id, paying.payer, [part], {
|
|
1136
|
-
task: o.task,
|
|
1137
|
-
ms: Date.now() - began,
|
|
1138
|
-
});
|
|
1137
|
+
await this.state.addSpend(caller.id, paying.payer, [part], { task: o.task, ms: Date.now() - began }, false, paying.plans);
|
|
1139
1138
|
const task = this.tasks.find((t) => t.id === o.task);
|
|
1140
1139
|
await this.state
|
|
1141
1140
|
.addUsage(caller.id, {
|
|
@@ -1143,7 +1142,7 @@ export class Assistant {
|
|
|
1143
1142
|
kind: 'task',
|
|
1144
1143
|
task: o.task,
|
|
1145
1144
|
title: o.run?.title ?? task?.label ?? o.task,
|
|
1146
|
-
own_usd: paying
|
|
1145
|
+
own_usd: ownKeyUsd(paying, [part]),
|
|
1147
1146
|
}, [part])
|
|
1148
1147
|
.catch(() => undefined);
|
|
1149
1148
|
}
|
|
@@ -99,7 +99,24 @@ export interface RequestsDoc {
|
|
|
99
99
|
export type SpendRow = UsagePart & {
|
|
100
100
|
payer: AssistantPayer;
|
|
101
101
|
free?: true;
|
|
102
|
+
/** Of an own row: paid by the person's API key or their plan sign-in (a plan costs them $0). */
|
|
103
|
+
way?: AssistantOwnWay;
|
|
102
104
|
};
|
|
105
|
+
/** The provider a part ran on: by its model id, else by the model's name at the end of its label. */
|
|
106
|
+
export declare function providerOfPart(p: UsagePart): AssistantProvider | undefined;
|
|
107
|
+
/** Spend rows with the provider each ran on, so a page can tell a removed key's spend apart. */
|
|
108
|
+
export declare function withProvider<R extends UsagePart>(rows: R[]): R[];
|
|
109
|
+
/** USD of `parts` the person's own API keys paid: a provider signed in with a plan costs $0. */
|
|
110
|
+
export declare function ownKeyUsd(paying: {
|
|
111
|
+
payer: AssistantPayer;
|
|
112
|
+
plans: Paying['plans'];
|
|
113
|
+
}, parts: UsagePart[]): number;
|
|
114
|
+
/**
|
|
115
|
+
* What counts toward the person's own cap: own rows paid by an API key (a plan sign-in costs
|
|
116
|
+
* nothing per call), on a provider they can still pay with. A row from before ways were recorded
|
|
117
|
+
* counts unless its provider has no own way left (an old key since removed).
|
|
118
|
+
*/
|
|
119
|
+
export declare function ownCapUsed(rows: SpendRow[], usable: Partial<Record<AssistantProvider, unknown>>): number;
|
|
103
120
|
/** The ways of their own a person may pay with, per provider; a provider left out has none. */
|
|
104
121
|
export type OwnWays = Partial<Record<AssistantProvider, AssistantOwnWay[]>>;
|
|
105
122
|
/** How `paying` may choose: the app's limits on a person's own keys, and one payer only. */
|
|
@@ -255,7 +272,7 @@ export declare class State {
|
|
|
255
272
|
addSpend(id: string, payer: AssistantPayer, parts: UsagePart[], at?: {
|
|
256
273
|
task: string;
|
|
257
274
|
ms?: number;
|
|
258
|
-
}, free?: boolean): Promise<void>;
|
|
275
|
+
}, free?: boolean, plans?: Partial<Record<AssistantProvider, boolean>>): Promise<void>;
|
|
259
276
|
/**
|
|
260
277
|
* Adds one answer's use to a chat or run in this month's history (`usage:YYYY-MM`): one entry a
|
|
261
278
|
* chat or run, its parts merged, the newest `USAGE_KEPT` kept. `title` names a new entry only;
|
|
@@ -275,6 +292,8 @@ export declare class State {
|
|
|
275
292
|
keys: Partial<Record<"anthropic" | "openai" | "xai", string>>;
|
|
276
293
|
plans: Partial<Record<"anthropic" | "openai" | "xai", boolean>>;
|
|
277
294
|
}>;
|
|
295
|
+
/** USD of this month's own spend that counts toward the person's own cap (`ownCapUsed`). */
|
|
296
|
+
ownUsed(id: string, ways?: OwnWays): Promise<number>;
|
|
278
297
|
/** Who pays the person's next answer on `provider`'s model, or why nobody can. */
|
|
279
298
|
paying(id: string, provider: AssistantProvider, rules?: PayingRules): Promise<{
|
|
280
299
|
paying: Paying | null;
|
package/dist/assistant/state.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { refreshChatgpt, staleChatgpt } from './chatgpt.js';
|
|
2
|
-
import { PROVIDERS, keyHint } from './models.js';
|
|
2
|
+
import { ALL_MODELS, PROVIDERS, XAI_MODELS, keyHint } from './models.js';
|
|
3
3
|
import { APP_SCOPE } from './store.js';
|
|
4
4
|
/** Where a provider's key is kept: `key` for Anthropic, `key:<provider>` for the rest. */
|
|
5
5
|
export const keyDocName = (provider) => provider === 'anthropic' ? 'key' : `key:${provider}`;
|
|
@@ -7,6 +7,45 @@ export const keyDocName = (provider) => provider === 'anthropic' ? 'key' : `key:
|
|
|
7
7
|
export const planDocName = (provider) => `plan:${provider}`;
|
|
8
8
|
/** Requests kept for approvers: the newest this many. */
|
|
9
9
|
const REQUESTS_KEPT = 300;
|
|
10
|
+
const KNOWN_MODELS = [...ALL_MODELS, ...XAI_MODELS];
|
|
11
|
+
/** The provider a part ran on: by its model id, else by the model's name at the end of its label. */
|
|
12
|
+
export function providerOfPart(p) {
|
|
13
|
+
const m = KNOWN_MODELS.find((x) => x.id === p.model) ??
|
|
14
|
+
KNOWN_MODELS.find((x) => p.label === x.label || p.label.endsWith(` · ${x.label}`));
|
|
15
|
+
return m?.provider;
|
|
16
|
+
}
|
|
17
|
+
/** Spend rows with the provider each ran on, so a page can tell a removed key's spend apart. */
|
|
18
|
+
export function withProvider(rows) {
|
|
19
|
+
return rows.map((r) => {
|
|
20
|
+
const provider = providerOfPart(r);
|
|
21
|
+
return provider ? { ...r, provider } : r;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** USD of `parts` the person's own API keys paid: a provider signed in with a plan costs $0. */
|
|
25
|
+
export function ownKeyUsd(paying, parts) {
|
|
26
|
+
if (paying.payer !== 'own')
|
|
27
|
+
return 0;
|
|
28
|
+
return parts
|
|
29
|
+
.filter((p) => {
|
|
30
|
+
const prov = providerOfPart(p);
|
|
31
|
+
return !(prov && paying.plans[prov]);
|
|
32
|
+
})
|
|
33
|
+
.reduce((a, p) => a + p.usd, 0);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What counts toward the person's own cap: own rows paid by an API key (a plan sign-in costs
|
|
37
|
+
* nothing per call), on a provider they can still pay with. A row from before ways were recorded
|
|
38
|
+
* counts unless its provider has no own way left (an old key since removed).
|
|
39
|
+
*/
|
|
40
|
+
export function ownCapUsed(rows, usable) {
|
|
41
|
+
return rows
|
|
42
|
+
.filter((r) => r.payer === 'own' && !r.free && r.way !== 'plan')
|
|
43
|
+
.filter((r) => {
|
|
44
|
+
const prov = providerOfPart(r);
|
|
45
|
+
return !prov || !!usable[prov];
|
|
46
|
+
})
|
|
47
|
+
.reduce((a, r) => a + r.usd, 0);
|
|
48
|
+
}
|
|
10
49
|
/** Chats and runs kept in one month's usage history: the newest this many. */
|
|
11
50
|
export const USAGE_KEPT = 300;
|
|
12
51
|
/** Months of usage history offered (`usage:YYYY-MM` documents are listed this far back). */
|
|
@@ -241,9 +280,16 @@ export class State {
|
|
|
241
280
|
* Adds an answer's use to this month's spend, by label and payer. `at` names the task the answer
|
|
242
281
|
* was for and how long it took, so the month also adds up per task and model (`tasks`).
|
|
243
282
|
*/
|
|
244
|
-
async addSpend(id, payer, parts, at, free = false) {
|
|
283
|
+
async addSpend(id, payer, parts, at, free = false, plans) {
|
|
245
284
|
if (!parts.some((p) => p.calls))
|
|
246
285
|
return;
|
|
286
|
+
// Which own way paid each part: a plan sign-in or a key, by the part's provider.
|
|
287
|
+
const wayOf = (p) => {
|
|
288
|
+
if (payer !== 'own' || !plans)
|
|
289
|
+
return undefined;
|
|
290
|
+
const prov = providerOfPart(p);
|
|
291
|
+
return prov && plans[prov] ? 'plan' : 'key';
|
|
292
|
+
};
|
|
247
293
|
await this.docs.update(id, `spend:${this.month()}`, (d) => {
|
|
248
294
|
const rows = [...(d?.rows ?? [])];
|
|
249
295
|
const tasks = [...(d?.tasks ?? [])];
|
|
@@ -277,7 +323,8 @@ export class State {
|
|
|
277
323
|
for (const p of parts) {
|
|
278
324
|
if (!p.calls)
|
|
279
325
|
continue;
|
|
280
|
-
const
|
|
326
|
+
const way = wayOf(p);
|
|
327
|
+
const i = rows.findIndex((r) => r.label === p.label && r.payer === payer && !!r.free === free && r.way === way);
|
|
281
328
|
const prev = i >= 0 ? rows[i] : undefined;
|
|
282
329
|
const row = prev
|
|
283
330
|
? {
|
|
@@ -288,7 +335,7 @@ export class State {
|
|
|
288
335
|
out: prev.out + p.out,
|
|
289
336
|
usd: prev.usd + p.usd,
|
|
290
337
|
}
|
|
291
|
-
: { ...p, payer, ...(free ? { free: true } : {}) };
|
|
338
|
+
: { ...p, payer, ...(free ? { free: true } : {}), ...(way ? { way } : {}) };
|
|
292
339
|
if (i >= 0)
|
|
293
340
|
rows[i] = row;
|
|
294
341
|
else
|
|
@@ -348,7 +395,7 @@ export class State {
|
|
|
348
395
|
month,
|
|
349
396
|
months,
|
|
350
397
|
usd: spend.rows.reduce((a, r) => a + r.usd, 0),
|
|
351
|
-
rows: spend.rows,
|
|
398
|
+
rows: withProvider(spend.rows),
|
|
352
399
|
entries: doc?.entries ?? [],
|
|
353
400
|
};
|
|
354
401
|
}
|
|
@@ -369,6 +416,11 @@ export class State {
|
|
|
369
416
|
});
|
|
370
417
|
return { keys, plans };
|
|
371
418
|
}
|
|
419
|
+
/** USD of this month's own spend that counts toward the person's own cap (`ownCapUsed`). */
|
|
420
|
+
async ownUsed(id, ways) {
|
|
421
|
+
const [{ keys }, spend] = await Promise.all([this.keysOf(id, 'own', ways), this.spend(id)]);
|
|
422
|
+
return ownCapUsed(spend.rows, keys);
|
|
423
|
+
}
|
|
372
424
|
/** Who pays the person's next answer on `provider`'s model, or why nobody can. */
|
|
373
425
|
async paying(id, provider, rules = {}) {
|
|
374
426
|
const [person, appKeys, ownKeys, spend, ownCap] = await Promise.all([
|
|
@@ -399,7 +451,7 @@ export class State {
|
|
|
399
451
|
apiKey: own,
|
|
400
452
|
...ownKeys,
|
|
401
453
|
cap: ownCap,
|
|
402
|
-
left: ownCap -
|
|
454
|
+
left: ownCap - ownCapUsed(spend.rows, ownKeys.keys),
|
|
403
455
|
}
|
|
404
456
|
: null,
|
|
405
457
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.247",
|
|
4
4
|
"description": "Lumen's assistant and agent parts: a chat assistant's server (Claude tiers, tools over MCP, the web, hand off, spend caps), serving an MCP server from a Worker, read-only tool sets and metered tool calls.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"@ai-sdk/openai": "4.0.108",
|
|
53
53
|
"@anthropic-ai/sdk": "0.133.0",
|
|
54
54
|
"@cloudflare/think": "0.23.0",
|
|
55
|
-
"@columenlabs/lumen-ops": "0.1.
|
|
56
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
55
|
+
"@columenlabs/lumen-ops": "0.1.247",
|
|
56
|
+
"@columenlabs/lumen-ui-types": "0.1.247",
|
|
57
57
|
"agents": "0.32.0",
|
|
58
58
|
"ai": "7.0.162",
|
|
59
59
|
"just-bash": "3.6.0",
|