@columenlabs/lumen-ai 0.1.194 → 0.1.196
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.
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* PUT /workspaces/:id/tabs/:tab {name?, config?}
|
|
14
14
|
* DELETE /workspaces/:id/tabs/:tab
|
|
15
15
|
* GET /frames every frame (for + Data)
|
|
16
|
+
* POST /frames {name, recipe} a frame from a recipe, for a card to link (reuses one
|
|
17
|
+
* that runs the same recipe)
|
|
16
18
|
* GET /frames/:id rows, meta and hand edits
|
|
17
19
|
* POST /frames/:id/refresh runs its recipe again
|
|
18
20
|
* GET|PUT /frames/:id/script its recipe
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* PUT /workspaces/:id/tabs/:tab {name?, config?}
|
|
14
14
|
* DELETE /workspaces/:id/tabs/:tab
|
|
15
15
|
* GET /frames every frame (for + Data)
|
|
16
|
+
* POST /frames {name, recipe} a frame from a recipe, for a card to link (reuses one
|
|
17
|
+
* that runs the same recipe)
|
|
16
18
|
* GET /frames/:id rows, meta and hand edits
|
|
17
19
|
* POST /frames/:id/refresh runs its recipe again
|
|
18
20
|
* GET|PUT /frames/:id/script its recipe
|
|
@@ -120,8 +122,17 @@ export function workspaceRoutes(opts) {
|
|
|
120
122
|
if (!id) {
|
|
121
123
|
if (m === 'GET')
|
|
122
124
|
return json(await s.frames(owner));
|
|
123
|
-
if (m === 'POST')
|
|
124
|
-
|
|
125
|
+
if (m === 'POST') {
|
|
126
|
+
const raw = await req
|
|
127
|
+
.clone()
|
|
128
|
+
.json()
|
|
129
|
+
.catch(() => null);
|
|
130
|
+
if (!raw || typeof raw !== 'object' || !('recipe' in raw))
|
|
131
|
+
return fail('Your own columns are not offered here yet.', 501);
|
|
132
|
+
const p = await body(addTabSchema);
|
|
133
|
+
await allowed(p.recipe);
|
|
134
|
+
return json(await s.makeFrame(owner, p));
|
|
135
|
+
}
|
|
125
136
|
}
|
|
126
137
|
else if (!sub && m === 'GET') {
|
|
127
138
|
return json(await s.frame(owner, id));
|
|
@@ -105,6 +105,14 @@ export declare function createWorkspaces(opts: WorkspacesOptions): {
|
|
|
105
105
|
frames(owner: string): Promise<{
|
|
106
106
|
frames: FrameChoice[];
|
|
107
107
|
}>;
|
|
108
|
+
/**
|
|
109
|
+
* A frame from a recipe the product offers (+ Data's app recipes), for a card to link. One that
|
|
110
|
+
* already runs the same recipe is reused, so picking it twice keeps one copy.
|
|
111
|
+
*/
|
|
112
|
+
makeFrame(owner: string, p: {
|
|
113
|
+
name: string;
|
|
114
|
+
recipe: FrameScript;
|
|
115
|
+
}): Promise<FrameChoice>;
|
|
108
116
|
frame(owner: string, id: string): Promise<FrameData>;
|
|
109
117
|
refresh: (owner: string, id: string, by?: 'you' | 'assistant') => Promise<FrameData>;
|
|
110
118
|
script(owner: string, id: string): Promise<{
|
package/dist/workspaces/store.js
CHANGED
|
@@ -189,9 +189,37 @@ export function createWorkspaces(opts) {
|
|
|
189
189
|
throw err instanceof FrameError ? err : new FrameError(error, 502);
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
+
/** A new frame from a recipe, run once (a failed run keeps the frame with its error). */
|
|
193
|
+
async function newFrame(owner, name, recipe, by) {
|
|
194
|
+
const [{ n } = { n: 0 }] = await db.all(`SELECT COUNT(*) AS n FROM (SELECT 1 FROM ${t.frames} WHERE owner = ? LIMIT ${MAX_FRAMES})`, owner);
|
|
195
|
+
if (Number(n) >= MAX_FRAMES)
|
|
196
|
+
throw new FrameError(`You keep ${MAX_FRAMES} tabs of data, the most: delete some first.`, 409);
|
|
197
|
+
const head = {
|
|
198
|
+
id: newId('fr'),
|
|
199
|
+
name,
|
|
200
|
+
columns: [],
|
|
201
|
+
rows: 0,
|
|
202
|
+
mode: 'live',
|
|
203
|
+
kind: 'snapshot',
|
|
204
|
+
at: now(),
|
|
205
|
+
origin: 'assistant',
|
|
206
|
+
script: recipe,
|
|
207
|
+
};
|
|
208
|
+
await runInto(owner, head, [], recipe, by, []);
|
|
209
|
+
return (await heads(owner, [head.id])).get(head.id) ?? head;
|
|
210
|
+
}
|
|
211
|
+
const choiceOf = (h) => ({
|
|
212
|
+
id: h.id,
|
|
213
|
+
name: h.name,
|
|
214
|
+
columns: h.columns,
|
|
215
|
+
at: h.at,
|
|
216
|
+
origin: h.origin ?? 'assistant',
|
|
217
|
+
});
|
|
218
|
+
/** A frame no tab shows but a card links (a recipe added from + Data) still counts as used. */
|
|
192
219
|
async function dropFrameIfUnused(owner, frame) {
|
|
193
220
|
const rows = await db.all(`SELECT tabs FROM ${t.spaces} WHERE owner = ? LIMIT ${MAX_WORKSPACES}`, owner);
|
|
194
|
-
const used = rows.some((r) => parse(r.tabs, []).some((x) => 'frame' in x.source && x.source.frame === frame)
|
|
221
|
+
const used = rows.some((r) => parse(r.tabs, []).some((x) => ('frame' in x.source && x.source.frame === frame) ||
|
|
222
|
+
JSON.stringify(x.config ?? null).includes(frame)));
|
|
195
223
|
if (!used)
|
|
196
224
|
await db.run(`DELETE FROM ${t.frames} WHERE owner = ? AND id = ?`, owner, frame);
|
|
197
225
|
}
|
|
@@ -257,21 +285,7 @@ export function createWorkspaces(opts) {
|
|
|
257
285
|
const w = await getSpace(owner, id);
|
|
258
286
|
if (w.tabs.length >= MAX_TABS)
|
|
259
287
|
throw new FrameError(`${w.name} has ${MAX_TABS} tabs, the most: delete one first.`, 409);
|
|
260
|
-
const
|
|
261
|
-
if (Number(n) >= MAX_FRAMES)
|
|
262
|
-
throw new FrameError(`You keep ${MAX_FRAMES} tabs of data, the most: delete some first.`, 409);
|
|
263
|
-
const head = {
|
|
264
|
-
id: newId('fr'),
|
|
265
|
-
name: p.name,
|
|
266
|
-
columns: [],
|
|
267
|
-
rows: 0,
|
|
268
|
-
mode: 'live',
|
|
269
|
-
kind: 'snapshot',
|
|
270
|
-
at: now(),
|
|
271
|
-
origin: 'assistant',
|
|
272
|
-
script: p.recipe,
|
|
273
|
-
};
|
|
274
|
-
await runInto(owner, head, [], p.recipe, p.by ?? 'you', []);
|
|
288
|
+
const head = await newFrame(owner, p.name, p.recipe, p.by ?? 'you');
|
|
275
289
|
const tab = {
|
|
276
290
|
id: newId('tb'),
|
|
277
291
|
name: p.name,
|
|
@@ -336,18 +350,21 @@ export function createWorkspaces(opts) {
|
|
|
336
350
|
async frames(owner) {
|
|
337
351
|
const rows = await db.all(`SELECT head FROM ${t.frames} WHERE owner = ? LIMIT ${MAX_FRAMES}`, owner);
|
|
338
352
|
return {
|
|
339
|
-
frames: rows.map((r) =>
|
|
340
|
-
const h = parse(r.head, null);
|
|
341
|
-
return {
|
|
342
|
-
id: h.id,
|
|
343
|
-
name: h.name,
|
|
344
|
-
columns: h.columns,
|
|
345
|
-
at: h.at,
|
|
346
|
-
origin: h.origin ?? 'assistant',
|
|
347
|
-
};
|
|
348
|
-
}),
|
|
353
|
+
frames: rows.map((r) => choiceOf(parse(r.head, null))),
|
|
349
354
|
};
|
|
350
355
|
},
|
|
356
|
+
/**
|
|
357
|
+
* A frame from a recipe the product offers (+ Data's app recipes), for a card to link. One that
|
|
358
|
+
* already runs the same recipe is reused, so picking it twice keeps one copy.
|
|
359
|
+
*/
|
|
360
|
+
async makeFrame(owner, p) {
|
|
361
|
+
const rows = await db.all(`SELECT head FROM ${t.frames} WHERE owner = ? LIMIT ${MAX_FRAMES}`, owner);
|
|
362
|
+
const want = recipeText(p.recipe);
|
|
363
|
+
const same = rows
|
|
364
|
+
.map((r) => parse(r.head, null))
|
|
365
|
+
.find((h) => h?.script && recipeText(h.script) === want);
|
|
366
|
+
return choiceOf(same ?? (await newFrame(owner, p.name, p.recipe, 'you')));
|
|
367
|
+
},
|
|
351
368
|
async frame(owner, id) {
|
|
352
369
|
return (await getFrame(owner, id)).data;
|
|
353
370
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.196",
|
|
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.196",
|
|
56
|
+
"@columenlabs/lumen-ui-types": "0.1.196",
|
|
57
57
|
"agents": "0.32.0",
|
|
58
58
|
"ai": "7.0.162",
|
|
59
59
|
"just-bash": "3.6.0",
|