@columenlabs/lumen-ai 0.1.157 → 0.1.159

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 CHANGED
@@ -98,7 +98,7 @@ app.all('/api/assistant/*', (c) => routes(c.req.raw));
98
98
  - **Keys.** Each provider has its own keys (`?provider=anthropic|openai` 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`).
99
99
  - **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.
100
100
  - **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.
101
- - **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. 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 })` (`POST /chats/:id/writes/:step/undo`); 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`.
101
+ - **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 })` (`POST /chats/:id/writes/:step/undo`); 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`.
102
102
  - **Web.** `fetch` is a plain GET from the Worker (10 s, 2 MB, never the app's own hosts or private addresses). ScrapeQL's own tools join over its MCP API once an admin pastes a Cloudflare Access service token (`PUT /web/scrapeql`). A Worker on ScrapeQL's own Cloudflare account passes its service binding instead, `scrapeql: { url: 'https://scrapeql/mcp', fetch: env.SCRAPEQL.fetch.bind(env.SCRAPEQL) }`: no token is stored, the tools are always on and Settings shows the link with a Test.
103
103
  - **Hand off and advice.** The `escalate` tool hands one task to a higher tier (the person sets next, any or only when asked); Anthropic's advisor tool lets a higher tier send a plan, at most two an answer.
104
104
  - **Chats** stream as server-sent events (`POST /chat`); closing the request stops the answer and keeps what was said. Past 150k tokens, or on `/compact`, the history sent to the model becomes a summary. Run `assistant.purge()` once a day to drop chats 30 days after their last message.
@@ -75,6 +75,11 @@ export interface ToolGroup {
75
75
  * chat when `undo` is set. Off by default, so a group only drafts.
76
76
  */
77
77
  writes?: boolean;
78
+ /**
79
+ * Has read tools only: offered Off or Read, never Read + draft or Read + write, and a saved
80
+ * draft or write level reads as Read.
81
+ */
82
+ readOnly?: boolean;
78
83
  /** Takes back one change a write made at once (Undo on its line in the chat). */
79
84
  undo?: (caller: Caller, write: AssistantWrite) => Promise<void>;
80
85
  tools: (caller: Caller) => ToolSource | ToolSource[];
@@ -331,6 +331,8 @@ export class Assistant {
331
331
  }
332
332
  access(p, g) {
333
333
  const a = p.access?.[g.id] ?? g.access ?? 'read';
334
+ if (g.readOnly && (a === 'draft' || a === 'write'))
335
+ return 'read';
334
336
  return a === 'write' && !g.writes ? 'draft' : a;
335
337
  }
336
338
  groupById(id) {
@@ -417,8 +419,8 @@ export class Assistant {
417
419
  label: g.label,
418
420
  about: g.about,
419
421
  access: this.access(p, g),
420
- drafts: true,
421
- writes: !!g.writes,
422
+ drafts: !g.readOnly,
423
+ writes: !!g.writes && !g.readOnly,
422
424
  })),
423
425
  hand_off: p.hand_off ?? 'next',
424
426
  advice: p.advice && (p.advice === 'off' || this.tierById(p.advice)) ? p.advice : 'off',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-ai",
3
- "version": "0.1.157",
3
+ "version": "0.1.159",
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",
@@ -41,8 +41,8 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@anthropic-ai/sdk": "0.133.0",
44
- "@columenlabs/lumen-ops": "0.1.157",
45
- "@columenlabs/lumen-ui-types": "0.1.157",
44
+ "@columenlabs/lumen-ops": "0.1.159",
45
+ "@columenlabs/lumen-ui-types": "0.1.159",
46
46
  "openai": "7.32.0",
47
47
  "zod": "^4.3.6"
48
48
  },