@columenlabs/lumen-ai 0.1.225 → 0.1.226

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.
@@ -12,7 +12,7 @@
12
12
  * An `Assistant` gives both: `assistant.agentTurn(caller, input)` returns a plan and its settle.
13
13
  */
14
14
  import { type ChatResponseResult, type PrepareStepContext, type Session, type StepConfig, type StepContext, Think, type ThinkModel, type TurnConfig, type TurnContext } from '@cloudflare/think';
15
- import { type AssistantChat, type AssistantEffort, type AssistantEvent, type AssistantImage, type AssistantRefNote, type AssistantScreenMap, type AssistantScreenOutcome, type ChatUsage, type UsagePart } from '@columenlabs/lumen-ui-types/assistant';
15
+ import { type AssistantChat, type AssistantEffort, type AssistantEvent, type AssistantImage, type AssistantQuote, type AssistantRefNote, type AssistantScreenMap, type AssistantScreenOutcome, type ChatUsage, type UsagePart } from '@columenlabs/lumen-ui-types/assistant';
16
16
  import { type ModelMessage, type ToolSet } from 'ai';
17
17
  import type { ModelDef } from '../assistant/models.js';
18
18
  import { type AgentConnector, type ConnectorAt } from './connectors.js';
@@ -134,6 +134,8 @@ export interface AskInput {
134
134
  note?: unknown;
135
135
  };
136
136
  refs?: AssistantRefNote[];
137
+ /** The piece of the chat this message replies to (Reply on selected text). */
138
+ quote?: AssistantQuote;
137
139
  tier?: string;
138
140
  time_zone?: string;
139
141
  /** What the browser can show (Screen on): the `screen` tool and its rules join the turn. */
@@ -141,6 +143,14 @@ export interface AskInput {
141
143
  /** How earlier screen calls ended in the browser. */
142
144
  outcomes?: AssistantScreenOutcome[];
143
145
  }
146
+ /** A quote as sent, checked: its text cut to `ASSISTANT_QUOTE_MAX`, and whose message it came from. */
147
+ export declare function quoteOf(q: unknown): AssistantQuote | undefined;
148
+ /**
149
+ * The words the model reads before a message that replies to a quote: which message it came from
150
+ * and the quote itself. It is the message's first text part; the panel shows the quote from the
151
+ * message's metadata instead, so `itemsOf` leaves this part out.
152
+ */
153
+ export declare function quoteLead(q: AssistantQuote): string;
144
154
  /**
145
155
  * The images a message may carry, as file parts: allowed types only, at most `ASSISTANT_IMAGES_MAX`,
146
156
  * and no more than `ASSISTANT_IMAGE_CHARS` of base64 together; the rest are left out.
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { anthropic } from '@ai-sdk/anthropic';
15
15
  import { Think, } from '@cloudflare/think';
16
- import { ASSISTANT_IMAGES_MAX, ASSISTANT_IMAGE_CHARS, ASSISTANT_IMAGE_TYPES, } from '@columenlabs/lumen-ui-types/assistant';
16
+ import { ASSISTANT_IMAGES_MAX, ASSISTANT_IMAGE_CHARS, ASSISTANT_IMAGE_TYPES, ASSISTANT_QUOTE_MAX, } from '@columenlabs/lumen-ui-types/assistant';
17
17
  import { createCompactFunction } from 'agents/sessions';
18
18
  import { generateText } from 'ai';
19
19
  import { CONNECTOR_GROUP, checkConnectorUrl, connectorGroup, connectorId, connectorSource, } from './connectors.js';
@@ -73,6 +73,27 @@ export function withLead(messages, lead) {
73
73
  : [{ type: 'text', text: lead }, ...m.content];
74
74
  return [...messages.slice(0, i), { ...m, content }, ...messages.slice(i + 1)];
75
75
  }
76
+ /** A quote as sent, checked: its text cut to `ASSISTANT_QUOTE_MAX`, and whose message it came from. */
77
+ export function quoteOf(q) {
78
+ const o = q;
79
+ const text = typeof o?.text === 'string' ? o.text.trim().slice(0, ASSISTANT_QUOTE_MAX) : '';
80
+ if (!text)
81
+ return undefined;
82
+ return { text, from: o?.from === 'user' ? 'user' : 'assistant' };
83
+ }
84
+ /**
85
+ * The words the model reads before a message that replies to a quote: which message it came from
86
+ * and the quote itself. It is the message's first text part; the panel shows the quote from the
87
+ * message's metadata instead, so `itemsOf` leaves this part out.
88
+ */
89
+ export function quoteLead(q) {
90
+ const whose = q.from === 'user' ? 'their own earlier message' : 'your earlier answer';
91
+ const lines = q.text
92
+ .split('\n')
93
+ .map((l) => `> ${l}`)
94
+ .join('\n');
95
+ return `The person replies to this part of ${whose}:\n${lines}\n\n`;
96
+ }
76
97
  /**
77
98
  * The images a message may carry, as file parts: allowed types only, at most `ASSISTANT_IMAGES_MAX`,
78
99
  * and no more than `ASSISTANT_IMAGE_CHARS` of base64 together; the rest are left out.
@@ -209,10 +230,12 @@ export class LumenAgent extends Think {
209
230
  this.#put('at', at);
210
231
  await sink.event({ event: 'chat', data: { id: this.name, title } });
211
232
  this.#outcomes(screenOutcomesOf(input.outcomes));
233
+ const quote = quoteOf(input.quote);
212
234
  const meta = {
213
235
  at,
214
236
  ...(input.context ? { context: { label: input.context.label } } : {}),
215
237
  ...(input.refs?.length ? { refs: input.refs } : {}),
238
+ ...(quote ? { quote } : {}),
216
239
  ...(input.tier ? { tier: input.tier } : {}),
217
240
  };
218
241
  const toEvents = chunkEvents({
@@ -237,7 +260,11 @@ export class LumenAgent extends Think {
237
260
  await this.chat({
238
261
  id: userId,
239
262
  role: 'user',
240
- parts: [{ type: 'text', text: input.message }, ...imageParts(input.images)],
263
+ parts: [
264
+ ...(quote ? [{ type: 'text', text: quoteLead(quote) }] : []),
265
+ { type: 'text', text: input.message },
266
+ ...imageParts(input.images),
267
+ ],
241
268
  metadata: meta,
242
269
  }, {
243
270
  onStart: () => undefined,
@@ -3,7 +3,7 @@
3
3
  * panel's `AssistantEvent`s, and a stored chat's messages and cards as its `ChatItem`s. The panel
4
4
  * (`@columenlabs/lumen-ui`'s `LumenAssistant`) reads a Think chat the same way as before.
5
5
  */
6
- import type { AssistantEvent, AssistantRefNote, ChatItem } from '@columenlabs/lumen-ui-types/assistant';
6
+ import type { AssistantEvent, AssistantQuote, AssistantRefNote, ChatItem } from '@columenlabs/lumen-ui-types/assistant';
7
7
  import type { AgentCard } from './agent.js';
8
8
  import type { ScreenCall } from './screen.js';
9
9
  /** A tool's name as a line's title: `notes__find_notes` → `find notes`. */
@@ -40,6 +40,8 @@ export interface AskMeta {
40
40
  label: string;
41
41
  };
42
42
  refs?: AssistantRefNote[];
43
+ /** The piece of the chat the message replies to; its words to the model are the first text part. */
44
+ quote?: AssistantQuote;
43
45
  tier?: string;
44
46
  }
45
47
  /** A stored chat as the panel's items: the messages in order, each tool call as it ended. */
@@ -137,11 +137,12 @@ export function itemsOf(messages, cards, screens = new Map(), steers = {}) {
137
137
  for (const m of messages) {
138
138
  if (m.role === 'user') {
139
139
  asked = m.id;
140
+ const meta = (obj(m.metadata) ?? {});
140
141
  const text = m.parts
141
142
  .filter((p) => p.type === 'text')
143
+ .slice(meta.quote ? 1 : 0)
142
144
  .map((p) => String(p.text ?? ''))
143
145
  .join('');
144
- const meta = (obj(m.metadata) ?? {});
145
146
  const images = m.parts
146
147
  .filter((p) => p.type === 'file' && typeof p.url === 'string' && p.url.startsWith('data:image/'))
147
148
  .map((p) => p.url);
@@ -152,6 +153,7 @@ export function itemsOf(messages, cards, screens = new Map(), steers = {}) {
152
153
  ...(images.length ? { images } : {}),
153
154
  ...(meta.context?.label ? { context: meta.context.label } : {}),
154
155
  ...(meta.refs?.length ? { refs: meta.refs } : {}),
156
+ ...(meta.quote ? { quote: meta.quote } : {}),
155
157
  ...(meta.tier ? { tier: meta.tier } : {}),
156
158
  });
157
159
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-ai",
3
- "version": "0.1.225",
3
+ "version": "0.1.226",
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.225",
56
- "@columenlabs/lumen-ui-types": "0.1.225",
55
+ "@columenlabs/lumen-ops": "0.1.226",
56
+ "@columenlabs/lumen-ui-types": "0.1.226",
57
57
  "agents": "0.32.0",
58
58
  "ai": "7.0.162",
59
59
  "just-bash": "3.6.0",