@firstlovecenter/ai-chat 0.2.3 → 0.6.0
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/CHANGELOG.md +57 -0
- package/dist/drizzle/index.cjs +24 -0
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +36 -1
- package/dist/drizzle/index.d.ts +36 -1
- package/dist/drizzle/index.js +25 -1
- package/dist/drizzle/index.js.map +1 -1
- package/dist/prisma/index.cjs +7 -0
- package/dist/prisma/index.cjs.map +1 -1
- package/dist/prisma/index.d.cts +8 -1
- package/dist/prisma/index.d.ts +8 -1
- package/dist/prisma/index.js +7 -0
- package/dist/prisma/index.js.map +1 -1
- package/dist/server/index.cjs +353 -15
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +50 -4
- package/dist/server/index.d.ts +50 -4
- package/dist/server/index.js +353 -15
- package/dist/server/index.js.map +1 -1
- package/dist/{types-DNwFvL-C.d.cts → types-CQntnyDJ.d.cts} +24 -2
- package/dist/{types-DNwFvL-C.d.ts → types-CQntnyDJ.d.ts} +24 -2
- package/dist/ui/index.cjs +1024 -87
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +24 -12
- package/dist/ui/index.d.ts +24 -12
- package/dist/ui/index.js +1022 -88
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
- package/prisma/chat-models.prisma +7 -0
package/dist/server/index.cjs
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var vertexSdk = require('@anthropic-ai/vertex-sdk');
|
|
4
4
|
var crypto = require('crypto');
|
|
5
|
+
var ai = require('ai');
|
|
6
|
+
var googleVertex = require('@ai-sdk/google-vertex');
|
|
7
|
+
var anthropic = require('@ai-sdk/google-vertex/anthropic');
|
|
5
8
|
var googleAuthLibrary = require('google-auth-library');
|
|
6
9
|
|
|
7
10
|
// src/server/tools/types.ts
|
|
@@ -72,8 +75,8 @@ async function runAgent(input) {
|
|
|
72
75
|
const toolResults = [];
|
|
73
76
|
for (const tc of response.toolCalls) {
|
|
74
77
|
transcript.push({ kind: "tool_use", name: tc.name, input: tc.input });
|
|
75
|
-
const
|
|
76
|
-
if (!
|
|
78
|
+
const tool2 = input.tools[tc.name];
|
|
79
|
+
if (!tool2) {
|
|
77
80
|
const errResult = {
|
|
78
81
|
ok: false,
|
|
79
82
|
error: { code: "UNKNOWN_TOOL", message: `Unknown tool: ${tc.name}` }
|
|
@@ -87,7 +90,7 @@ async function runAgent(input) {
|
|
|
87
90
|
});
|
|
88
91
|
continue;
|
|
89
92
|
}
|
|
90
|
-
const result = await
|
|
93
|
+
const result = await tool2.execute(tc.input, {
|
|
91
94
|
...input.ctx,
|
|
92
95
|
toolCallCount
|
|
93
96
|
});
|
|
@@ -649,7 +652,7 @@ async function* streamClaudeNarration(opts) {
|
|
|
649
652
|
});
|
|
650
653
|
const stream = await client.messages.stream({
|
|
651
654
|
model: opts.modelId,
|
|
652
|
-
max_tokens:
|
|
655
|
+
max_tokens: opts.maxTokens,
|
|
653
656
|
system: NARRATIVE_SYSTEM,
|
|
654
657
|
messages: [{ role: "user", content: buildNarrativeUserMessage(opts.input) }]
|
|
655
658
|
});
|
|
@@ -709,7 +712,7 @@ async function* streamGeminiNarration(opts) {
|
|
|
709
712
|
parts: [{ text: buildNarrativeUserMessage(opts.input) }]
|
|
710
713
|
}
|
|
711
714
|
],
|
|
712
|
-
generationConfig: { maxOutputTokens:
|
|
715
|
+
generationConfig: { maxOutputTokens: opts.maxTokens, temperature: 0 }
|
|
713
716
|
})
|
|
714
717
|
});
|
|
715
718
|
if (!res.ok || !res.body) {
|
|
@@ -785,7 +788,7 @@ async function* streamGrokNarration(opts) {
|
|
|
785
788
|
},
|
|
786
789
|
body: JSON.stringify({
|
|
787
790
|
model: opts.modelId,
|
|
788
|
-
max_tokens:
|
|
791
|
+
max_tokens: opts.maxTokens,
|
|
789
792
|
stream: true,
|
|
790
793
|
messages: [
|
|
791
794
|
{ role: "system", content: NARRATIVE_SYSTEM3 },
|
|
@@ -1008,7 +1011,8 @@ data: ${JSON.stringify(data)}
|
|
|
1008
1011
|
ctx: toolContext,
|
|
1009
1012
|
tools: tools.tools,
|
|
1010
1013
|
systemBlocks,
|
|
1011
|
-
provider
|
|
1014
|
+
provider,
|
|
1015
|
+
maxOutputTokens: aiSettings.maxOutputTokens
|
|
1012
1016
|
});
|
|
1013
1017
|
if (!agentResult.ok) {
|
|
1014
1018
|
persistedError = agentResult.error;
|
|
@@ -1034,6 +1038,7 @@ data: ${JSON.stringify(data)}
|
|
|
1034
1038
|
projectId: vertex.projectId,
|
|
1035
1039
|
location: aiSettings.gcpLocation,
|
|
1036
1040
|
modelId: narratorModelId,
|
|
1041
|
+
maxTokens: aiSettings.maxOutputTokens,
|
|
1037
1042
|
input: {
|
|
1038
1043
|
question,
|
|
1039
1044
|
structured,
|
|
@@ -1137,6 +1142,297 @@ data: {}
|
|
|
1137
1142
|
}
|
|
1138
1143
|
};
|
|
1139
1144
|
}
|
|
1145
|
+
function buildVercelTools(tools, ctx, data, onPresent) {
|
|
1146
|
+
const result = {};
|
|
1147
|
+
let toolCallCount = 0;
|
|
1148
|
+
for (const [name, def] of Object.entries(tools)) {
|
|
1149
|
+
if (!def.zodSchema) {
|
|
1150
|
+
throw new Error(
|
|
1151
|
+
`Tool '${name}' has no zodSchema; required for the Vercel AI SDK chat. Add a Zod schema to the tool definition (or remove it from the registry if the host only uses the custom SSE chat).`
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
if (name === TERMINAL_TOOL_NAME) {
|
|
1155
|
+
result[name] = ai.tool({
|
|
1156
|
+
description: def.schema.description,
|
|
1157
|
+
// The Zod schema doubles as the runtime parameter validator the SDK
|
|
1158
|
+
// hands the model. We accept whatever Zod shape the host registered;
|
|
1159
|
+
// the SDK uses it to validate the tool-call arguments before dispatch.
|
|
1160
|
+
parameters: def.zodSchema,
|
|
1161
|
+
execute: async (input) => {
|
|
1162
|
+
if (toolCallCount < 2) {
|
|
1163
|
+
return {
|
|
1164
|
+
error: {
|
|
1165
|
+
code: "SELF_VERIFY_REQUIRED",
|
|
1166
|
+
message: "Per FR-8.3 you must run at least one CROSS-CHECK tool call (a different metric, a different period, or a run_sql sanity-check) before present. Make that extra call now, then call present again."
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
const payload = input;
|
|
1171
|
+
for (let i = 0; i < payload.blocks.length; i++) {
|
|
1172
|
+
data.append({
|
|
1173
|
+
type: "block",
|
|
1174
|
+
value: { index: i, ...payload.blocks[i] }
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
onPresent(payload);
|
|
1178
|
+
return { ok: true };
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
result[name] = ai.tool({
|
|
1184
|
+
description: def.schema.description,
|
|
1185
|
+
parameters: def.zodSchema,
|
|
1186
|
+
execute: async (input) => {
|
|
1187
|
+
const res = await def.execute(input, { ...ctx, toolCallCount });
|
|
1188
|
+
toolCallCount += 1;
|
|
1189
|
+
if (res.ok) return res.data;
|
|
1190
|
+
return { error: res.error };
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
return result;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// src/server/routes/agent-vercel.ts
|
|
1198
|
+
var VALID_MODELS = /* @__PURE__ */ new Set(["claude", "gemini"]);
|
|
1199
|
+
function jsonError2(status, code, message) {
|
|
1200
|
+
return new Response(JSON.stringify({ error: { code, message } }), {
|
|
1201
|
+
status,
|
|
1202
|
+
headers: { "Content-Type": "application/json" }
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
function defaultGenerateSessionId2() {
|
|
1206
|
+
return crypto.randomUUID().replace(/-/g, "").slice(0, 16);
|
|
1207
|
+
}
|
|
1208
|
+
function createAgentVercelRoutes(ctx) {
|
|
1209
|
+
const { persistence, auth, scope, tools, vertex, logger, hooks } = ctx;
|
|
1210
|
+
return {
|
|
1211
|
+
/** Next.js-compatible POST handler. */
|
|
1212
|
+
POST: async (req) => {
|
|
1213
|
+
if (hooks?.onRequest) {
|
|
1214
|
+
const short = await hooks.onRequest(req);
|
|
1215
|
+
if (short) return short;
|
|
1216
|
+
}
|
|
1217
|
+
const authResult = await auth.requireAuth(req);
|
|
1218
|
+
if (!authResult.ok) return authResult.response;
|
|
1219
|
+
const { scope: callerScope, userId } = authResult;
|
|
1220
|
+
if (hooks?.onAuthenticated) {
|
|
1221
|
+
const short = await hooks.onAuthenticated({
|
|
1222
|
+
req,
|
|
1223
|
+
scope: callerScope,
|
|
1224
|
+
userId
|
|
1225
|
+
});
|
|
1226
|
+
if (short) return short;
|
|
1227
|
+
}
|
|
1228
|
+
const body = await req.json().catch(() => null);
|
|
1229
|
+
const question = typeof body?.question === "string" ? body.question.trim() : "";
|
|
1230
|
+
if (!question) {
|
|
1231
|
+
return jsonError2(
|
|
1232
|
+
400,
|
|
1233
|
+
"VALIDATION_FAILED",
|
|
1234
|
+
"question must be a non-empty string."
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
const rawChatSessionId = body?.chatSessionId;
|
|
1238
|
+
const incomingChatSessionId = typeof rawChatSessionId === "number" && Number.isInteger(rawChatSessionId) ? rawChatSessionId : null;
|
|
1239
|
+
const rawModel = body?.model;
|
|
1240
|
+
const requestedModel = typeof rawModel === "string" && VALID_MODELS.has(rawModel) ? rawModel : null;
|
|
1241
|
+
const aiSettings = await persistence.getAiSettings();
|
|
1242
|
+
let chatSessionId;
|
|
1243
|
+
if (incomingChatSessionId !== null) {
|
|
1244
|
+
const owned = await persistence.getSession(
|
|
1245
|
+
incomingChatSessionId,
|
|
1246
|
+
userId
|
|
1247
|
+
);
|
|
1248
|
+
if (!owned) {
|
|
1249
|
+
return jsonError2(404, "NOT_FOUND", "Chat session not found.");
|
|
1250
|
+
}
|
|
1251
|
+
chatSessionId = owned.id;
|
|
1252
|
+
} else {
|
|
1253
|
+
const created = await persistence.createSession({
|
|
1254
|
+
userId,
|
|
1255
|
+
title: question.slice(0, 200)
|
|
1256
|
+
});
|
|
1257
|
+
chatSessionId = created.id;
|
|
1258
|
+
}
|
|
1259
|
+
await persistence.appendMessage({
|
|
1260
|
+
sessionId: chatSessionId,
|
|
1261
|
+
role: "user",
|
|
1262
|
+
question
|
|
1263
|
+
});
|
|
1264
|
+
const sessionId = hooks?.generateSessionId ? await hooks.generateSessionId({
|
|
1265
|
+
scope: callerScope,
|
|
1266
|
+
userId,
|
|
1267
|
+
chatSessionId: incomingChatSessionId
|
|
1268
|
+
}) : defaultGenerateSessionId2();
|
|
1269
|
+
const scopeSummary = await scope.buildScopeSummary(callerScope);
|
|
1270
|
+
const scopeLabel = await scope.resolveScopeLabel(callerScope);
|
|
1271
|
+
const toolContext = {
|
|
1272
|
+
scope: callerScope,
|
|
1273
|
+
sessionId,
|
|
1274
|
+
scopeSummary,
|
|
1275
|
+
toolCallCount: 0
|
|
1276
|
+
};
|
|
1277
|
+
const systemBlocks = await tools.buildSystemBlocks(toolContext);
|
|
1278
|
+
const provider = requestedModel ?? aiSettings.toolProvider;
|
|
1279
|
+
if (!VALID_MODELS.has(provider)) {
|
|
1280
|
+
return jsonError2(
|
|
1281
|
+
400,
|
|
1282
|
+
"INVALID_PROVIDER",
|
|
1283
|
+
`Vercel chat only supports 'claude' or 'gemini'; got '${provider}'.`
|
|
1284
|
+
);
|
|
1285
|
+
}
|
|
1286
|
+
const data = new ai.StreamData();
|
|
1287
|
+
let presentPayload = null;
|
|
1288
|
+
let persistedError = null;
|
|
1289
|
+
let sessionStarted = false;
|
|
1290
|
+
try {
|
|
1291
|
+
if (hooks?.onSessionStart) {
|
|
1292
|
+
await hooks.onSessionStart({
|
|
1293
|
+
scope: callerScope,
|
|
1294
|
+
sessionId,
|
|
1295
|
+
userId
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
sessionStarted = true;
|
|
1299
|
+
const vercelTools = buildVercelTools(
|
|
1300
|
+
tools.tools,
|
|
1301
|
+
toolContext,
|
|
1302
|
+
data,
|
|
1303
|
+
(p) => {
|
|
1304
|
+
presentPayload = p;
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
data.append({
|
|
1308
|
+
type: "meta",
|
|
1309
|
+
value: { chatSessionId, scopeLabel }
|
|
1310
|
+
});
|
|
1311
|
+
const system = systemBlocks.map((b) => b.text).join("\n\n");
|
|
1312
|
+
const model = provider === "claude" ? anthropic.createVertexAnthropic({
|
|
1313
|
+
project: vertex.projectId,
|
|
1314
|
+
location: vertex.defaultLocation,
|
|
1315
|
+
googleAuthOptions: {}
|
|
1316
|
+
})(vertex.modelIds.claude) : googleVertex.createVertex({
|
|
1317
|
+
project: vertex.projectId,
|
|
1318
|
+
location: aiSettings.gcpLocation,
|
|
1319
|
+
googleAuthOptions: {}
|
|
1320
|
+
})(vertex.modelIds.gemini);
|
|
1321
|
+
const result = ai.streamText({
|
|
1322
|
+
model,
|
|
1323
|
+
system,
|
|
1324
|
+
messages: [{ role: "user", content: question }],
|
|
1325
|
+
tools: vercelTools,
|
|
1326
|
+
maxSteps: 12,
|
|
1327
|
+
maxTokens: aiSettings.maxOutputTokens,
|
|
1328
|
+
onFinish: async ({ text }) => {
|
|
1329
|
+
try {
|
|
1330
|
+
let blocks = presentPayload?.blocks ?? [];
|
|
1331
|
+
const prose = {};
|
|
1332
|
+
const trimmed = (text ?? "").trim();
|
|
1333
|
+
if (presentPayload === null && trimmed) {
|
|
1334
|
+
const topic = question.length > 80 ? question.slice(0, 77) + "..." : question;
|
|
1335
|
+
const synthetic = {
|
|
1336
|
+
kind: "paragraph_brief",
|
|
1337
|
+
topic,
|
|
1338
|
+
key_facts: [trimmed]
|
|
1339
|
+
};
|
|
1340
|
+
blocks = [synthetic];
|
|
1341
|
+
prose[0] = trimmed;
|
|
1342
|
+
data.append({
|
|
1343
|
+
type: "block",
|
|
1344
|
+
value: { index: 0, ...synthetic }
|
|
1345
|
+
});
|
|
1346
|
+
} else if (text) {
|
|
1347
|
+
const firstPbIdx = blocks.findIndex(
|
|
1348
|
+
(b) => b.kind === "paragraph_brief"
|
|
1349
|
+
);
|
|
1350
|
+
if (firstPbIdx >= 0) prose[firstPbIdx] = text;
|
|
1351
|
+
}
|
|
1352
|
+
await persistence.appendMessage({
|
|
1353
|
+
sessionId: chatSessionId,
|
|
1354
|
+
role: "assistant",
|
|
1355
|
+
blocks: blocks.length ? blocks : null,
|
|
1356
|
+
prose: Object.keys(prose).length ? prose : null,
|
|
1357
|
+
errorJson: persistedError
|
|
1358
|
+
});
|
|
1359
|
+
} catch (err2) {
|
|
1360
|
+
logger?.warn?.(
|
|
1361
|
+
{
|
|
1362
|
+
chatSessionId,
|
|
1363
|
+
sessionId,
|
|
1364
|
+
err: err2.message
|
|
1365
|
+
},
|
|
1366
|
+
"[agent-vercel] failed to persist assistant turn"
|
|
1367
|
+
);
|
|
1368
|
+
} finally {
|
|
1369
|
+
try {
|
|
1370
|
+
await data.close();
|
|
1371
|
+
} catch {
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
return result.toDataStreamResponse({ data });
|
|
1377
|
+
} catch (e) {
|
|
1378
|
+
const message = e.message ?? "Internal error";
|
|
1379
|
+
persistedError = { code: "INTERNAL", message };
|
|
1380
|
+
logger?.error?.(
|
|
1381
|
+
{ chatSessionId, sessionId, err: message },
|
|
1382
|
+
"[agent-vercel] route errored"
|
|
1383
|
+
);
|
|
1384
|
+
try {
|
|
1385
|
+
data.append({
|
|
1386
|
+
type: "error",
|
|
1387
|
+
value: { code: "INTERNAL", message }
|
|
1388
|
+
});
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
try {
|
|
1392
|
+
await data.close();
|
|
1393
|
+
} catch {
|
|
1394
|
+
}
|
|
1395
|
+
try {
|
|
1396
|
+
await persistence.appendMessage({
|
|
1397
|
+
sessionId: chatSessionId,
|
|
1398
|
+
role: "assistant",
|
|
1399
|
+
blocks: null,
|
|
1400
|
+
prose: null,
|
|
1401
|
+
errorJson: persistedError
|
|
1402
|
+
});
|
|
1403
|
+
} catch (err2) {
|
|
1404
|
+
logger?.warn?.(
|
|
1405
|
+
{ chatSessionId, sessionId, err: err2.message },
|
|
1406
|
+
"[agent-vercel] failed to persist error turn"
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
return jsonError2(500, "INTERNAL", message);
|
|
1410
|
+
} finally {
|
|
1411
|
+
if (hooks?.onSessionEnd) {
|
|
1412
|
+
const cause = req.signal.aborted ? "abort" : persistedError ? "error" : "complete";
|
|
1413
|
+
try {
|
|
1414
|
+
await hooks.onSessionEnd({
|
|
1415
|
+
scope: callerScope,
|
|
1416
|
+
sessionId,
|
|
1417
|
+
userId,
|
|
1418
|
+
cause
|
|
1419
|
+
});
|
|
1420
|
+
} catch (err2) {
|
|
1421
|
+
logger?.warn?.(
|
|
1422
|
+
{
|
|
1423
|
+
chatSessionId,
|
|
1424
|
+
sessionId,
|
|
1425
|
+
sessionStarted,
|
|
1426
|
+
err: err2.message
|
|
1427
|
+
},
|
|
1428
|
+
"[agent-vercel] onSessionEnd hook failed"
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1140
1436
|
|
|
1141
1437
|
// src/server/routes/chat-sessions.ts
|
|
1142
1438
|
var DEFAULT_TITLE = "New chat";
|
|
@@ -1317,6 +1613,8 @@ function createChatSessionsRoutes(ctx) {
|
|
|
1317
1613
|
|
|
1318
1614
|
// src/server/routes/admin-settings.ts
|
|
1319
1615
|
var VALID_LOCATIONS = ["us-east5", "global"];
|
|
1616
|
+
var MIN_MAX_OUTPUT_TOKENS = 256;
|
|
1617
|
+
var MAX_MAX_OUTPUT_TOKENS = 64e3;
|
|
1320
1618
|
function isStringRecord(v) {
|
|
1321
1619
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1322
1620
|
}
|
|
@@ -1331,6 +1629,8 @@ function toWire(settings) {
|
|
|
1331
1629
|
tool_provider: settings.toolProvider,
|
|
1332
1630
|
gcp_location: settings.gcpLocation,
|
|
1333
1631
|
chat_interface: settings.chatInterface,
|
|
1632
|
+
max_output_tokens: settings.maxOutputTokens,
|
|
1633
|
+
role_prompt: settings.rolePrompt,
|
|
1334
1634
|
updated_at: settings.updatedAt ? settings.updatedAt.toISOString() : null,
|
|
1335
1635
|
updated_by_user_id: settings.updatedByUserId
|
|
1336
1636
|
};
|
|
@@ -1410,11 +1710,29 @@ function createAdminSettingsRoutes(ctx) {
|
|
|
1410
1710
|
}
|
|
1411
1711
|
patch.chatInterface = v;
|
|
1412
1712
|
}
|
|
1413
|
-
if (
|
|
1713
|
+
if ("max_output_tokens" in body) {
|
|
1714
|
+
const v = body.max_output_tokens;
|
|
1715
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_MAX_OUTPUT_TOKENS || v > MAX_MAX_OUTPUT_TOKENS) {
|
|
1716
|
+
return jsonResponse({ error: "invalid_max_output_tokens" }, 400);
|
|
1717
|
+
}
|
|
1718
|
+
patch.maxOutputTokens = v;
|
|
1719
|
+
}
|
|
1720
|
+
if ("role_prompt" in body) {
|
|
1721
|
+
const v = body.role_prompt;
|
|
1722
|
+
if (v === null) {
|
|
1723
|
+
patch.rolePrompt = null;
|
|
1724
|
+
} else if (typeof v === "string") {
|
|
1725
|
+
const trimmed = v.trim();
|
|
1726
|
+
patch.rolePrompt = trimmed === "" ? null : trimmed;
|
|
1727
|
+
} else {
|
|
1728
|
+
return jsonResponse({ error: "invalid_role_prompt" }, 400);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
if (patch.toolProvider === void 0 && patch.gcpLocation === void 0 && patch.chatInterface === void 0 && patch.maxOutputTokens === void 0 && !("rolePrompt" in patch)) {
|
|
1414
1732
|
return jsonResponse(
|
|
1415
1733
|
{
|
|
1416
1734
|
error: "empty_patch",
|
|
1417
|
-
message: "Body must set at least one of tool_provider, gcp_location, chat_interface."
|
|
1735
|
+
message: "Body must set at least one of tool_provider, gcp_location, chat_interface, max_output_tokens, role_prompt."
|
|
1418
1736
|
},
|
|
1419
1737
|
400
|
|
1420
1738
|
);
|
|
@@ -1439,16 +1757,27 @@ function configureAiChat(opts) {
|
|
|
1439
1757
|
];
|
|
1440
1758
|
const getProvider = (id) => toolProviders2.find((p) => p.id === id) ?? getToolProvider(id);
|
|
1441
1759
|
const chatInterfaces = opts.chatInterfaces ?? BUILTIN_CHAT_INTERFACE_IDS.map((id) => ({ id }));
|
|
1442
|
-
const
|
|
1760
|
+
const staticRolePrompt = opts.rolePrompt;
|
|
1761
|
+
const tools = {
|
|
1443
1762
|
tools: opts.tools.tools,
|
|
1444
1763
|
async buildSystemBlocks(ctx) {
|
|
1445
1764
|
const inner = await opts.tools.buildSystemBlocks(ctx);
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1765
|
+
let role = null;
|
|
1766
|
+
try {
|
|
1767
|
+
const settings = await opts.persistence.getAiSettings();
|
|
1768
|
+
if (settings.rolePrompt && settings.rolePrompt.trim()) {
|
|
1769
|
+
role = settings.rolePrompt;
|
|
1770
|
+
}
|
|
1771
|
+
} catch {
|
|
1772
|
+
}
|
|
1773
|
+
if (!role && staticRolePrompt) {
|
|
1774
|
+
const resolved = typeof staticRolePrompt === "function" ? await staticRolePrompt(ctx) : staticRolePrompt;
|
|
1775
|
+
if (resolved && resolved.trim()) role = resolved;
|
|
1776
|
+
}
|
|
1777
|
+
if (!role) return inner;
|
|
1449
1778
|
return [{ text: role, cached: true }, ...inner];
|
|
1450
1779
|
}
|
|
1451
|
-
}
|
|
1780
|
+
};
|
|
1452
1781
|
const runAgentBound = async ({
|
|
1453
1782
|
question,
|
|
1454
1783
|
ctx,
|
|
@@ -1497,6 +1826,15 @@ function configureAiChat(opts) {
|
|
|
1497
1826
|
resolveNarratorId: opts.resolveNarratorId,
|
|
1498
1827
|
hooks: opts.hooks
|
|
1499
1828
|
});
|
|
1829
|
+
const agentVercel = createAgentVercelRoutes({
|
|
1830
|
+
persistence: opts.persistence,
|
|
1831
|
+
auth: opts.auth,
|
|
1832
|
+
scope: opts.scope,
|
|
1833
|
+
tools,
|
|
1834
|
+
vertex: opts.vertex,
|
|
1835
|
+
logger: opts.logger,
|
|
1836
|
+
hooks: opts.hooks
|
|
1837
|
+
});
|
|
1500
1838
|
const chatSessions = createChatSessionsRoutes({
|
|
1501
1839
|
persistence: opts.persistence,
|
|
1502
1840
|
auth: opts.auth,
|
|
@@ -1513,7 +1851,7 @@ function configureAiChat(opts) {
|
|
|
1513
1851
|
});
|
|
1514
1852
|
return {
|
|
1515
1853
|
runAgent: runAgentBound,
|
|
1516
|
-
routes: { agentCustom, chatSessions, adminSettings },
|
|
1854
|
+
routes: { agentCustom, agentVercel, chatSessions, adminSettings },
|
|
1517
1855
|
registries: { toolProviders: toolProviders2, chatInterfaces }
|
|
1518
1856
|
};
|
|
1519
1857
|
}
|