@columenlabs/lumen-ai 0.1.95 → 0.1.97
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/dist/assistant/engine.js +44 -7
- package/package.json +3 -3
package/dist/assistant/engine.js
CHANGED
|
@@ -1108,6 +1108,10 @@ export class Assistant {
|
|
|
1108
1108
|
// the SDK does not know and its accumulator throws on them. The final response rides on the
|
|
1109
1109
|
// completed, incomplete or failed event; every other event but text deltas is skipped.
|
|
1110
1110
|
let partial = '';
|
|
1111
|
+
// Event types seen and the items finished one by one: a plan sign-in's final event may carry
|
|
1112
|
+
// an empty `output`, its items having come only as `response.output_item.done`.
|
|
1113
|
+
const seen = {};
|
|
1114
|
+
const items = [];
|
|
1111
1115
|
const res = await (async () => {
|
|
1112
1116
|
const stream = await client.responses.create({
|
|
1113
1117
|
model: session.model.id,
|
|
@@ -1122,6 +1126,9 @@ export class Assistant {
|
|
|
1122
1126
|
}, signal ? { signal } : {});
|
|
1123
1127
|
let done;
|
|
1124
1128
|
for await (const e of stream) {
|
|
1129
|
+
seen[e.type] = (seen[e.type] ?? 0) + 1;
|
|
1130
|
+
if (e.type === 'response.output_item.done' && e.item)
|
|
1131
|
+
items.push(e.item);
|
|
1125
1132
|
if (e.type === 'response.output_text.delta' && typeof e.delta === 'string') {
|
|
1126
1133
|
partial += e.delta;
|
|
1127
1134
|
emit('text', { delta: e.delta });
|
|
@@ -1147,6 +1154,14 @@ export class Assistant {
|
|
|
1147
1154
|
if (partial)
|
|
1148
1155
|
sink.push({ kind: 'text', text: partial });
|
|
1149
1156
|
const code = res.error?.code ?? '';
|
|
1157
|
+
console.error(JSON.stringify({
|
|
1158
|
+
event: 'assistant_openai_failed',
|
|
1159
|
+
model: session.model.id,
|
|
1160
|
+
plan,
|
|
1161
|
+
code,
|
|
1162
|
+
message: res.error?.message?.slice(0, 300) ?? null,
|
|
1163
|
+
events: seen,
|
|
1164
|
+
}));
|
|
1150
1165
|
throw new AssistantError(/usage_limit/.test(code)
|
|
1151
1166
|
? 'Your ChatGPT plan reached its usage limit for now: try again later, or pick another model.'
|
|
1152
1167
|
: 'OpenAI could not finish the answer.', 'upstream');
|
|
@@ -1164,14 +1179,36 @@ export class Assistant {
|
|
|
1164
1179
|
o.context?.(u.input_tokens + u.output_tokens);
|
|
1165
1180
|
}
|
|
1166
1181
|
o.called();
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
emit('text', { delta: cut });
|
|
1182
|
+
const output = (res.output?.length ? res.output : items);
|
|
1183
|
+
res.output = output;
|
|
1170
1184
|
// Raw events carry no `output_text`: the words are the output messages' text parts.
|
|
1171
|
-
const words =
|
|
1185
|
+
const words = output
|
|
1172
1186
|
.flatMap((b) => (b.type === 'message' ? b.content : []))
|
|
1173
1187
|
.map((c) => (c.type === 'output_text' ? c.text : ''))
|
|
1174
|
-
.join('');
|
|
1188
|
+
.join('') || partial;
|
|
1189
|
+
const hasCall = output.some((b) => b.type === 'function_call');
|
|
1190
|
+
if (!words && !hasCall) {
|
|
1191
|
+
// Nothing to show: say why instead of an empty or bare "cut" answer, and log the shape.
|
|
1192
|
+
console.error(JSON.stringify({
|
|
1193
|
+
event: 'assistant_openai_empty',
|
|
1194
|
+
model: session.model.id,
|
|
1195
|
+
plan,
|
|
1196
|
+
status: res.status,
|
|
1197
|
+
incomplete: res.incomplete_details ?? null,
|
|
1198
|
+
usage: res.usage ?? null,
|
|
1199
|
+
events: seen,
|
|
1200
|
+
output: output.map((b) => b.type),
|
|
1201
|
+
}));
|
|
1202
|
+
if (!answer)
|
|
1203
|
+
throw new AssistantError(res.incomplete_details?.reason
|
|
1204
|
+
? `OpenAI stopped before answering (${res.incomplete_details.reason}).`
|
|
1205
|
+
: 'OpenAI sent no answer.', 'upstream');
|
|
1206
|
+
}
|
|
1207
|
+
const cut = res.incomplete_details?.reason === 'max_output_tokens' && (words || hasCall)
|
|
1208
|
+
? ' …(cut)'
|
|
1209
|
+
: '';
|
|
1210
|
+
if (cut)
|
|
1211
|
+
emit('text', { delta: cut });
|
|
1175
1212
|
const text = words + cut;
|
|
1176
1213
|
if (text) {
|
|
1177
1214
|
answer += (answer ? '\n\n' : '') + text;
|
|
@@ -1179,8 +1216,8 @@ export class Assistant {
|
|
|
1179
1216
|
emit('text_end', {});
|
|
1180
1217
|
}
|
|
1181
1218
|
// Reasoning, words and calls go back as they came, so the model keeps its own thread.
|
|
1182
|
-
input.push(...
|
|
1183
|
-
const calls =
|
|
1219
|
+
input.push(...output);
|
|
1220
|
+
const calls = output.filter((b) => b.type === 'function_call');
|
|
1184
1221
|
if (calls.length === 0)
|
|
1185
1222
|
break;
|
|
1186
1223
|
const results = await Promise.all(calls.map((c) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@columenlabs/lumen-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.97",
|
|
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.
|
|
45
|
-
"@columenlabs/lumen-ui-types": "0.1.
|
|
44
|
+
"@columenlabs/lumen-ops": "0.1.97",
|
|
45
|
+
"@columenlabs/lumen-ui-types": "0.1.97",
|
|
46
46
|
"openai": "7.32.0",
|
|
47
47
|
"zod": "^4.3.6"
|
|
48
48
|
},
|