@firstlovecenter/ai-chat 0.2.3 → 0.5.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 +25 -0
- package/dist/drizzle/index.d.cts +2 -1
- package/dist/drizzle/index.d.ts +2 -1
- package/dist/prisma/index.d.cts +2 -1
- package/dist/prisma/index.d.ts +2 -1
- package/dist/server/index.cjs +307 -4
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +40 -3
- package/dist/server/index.d.ts +40 -3
- package/dist/server/index.js +307 -4
- package/dist/server/index.js.map +1 -1
- package/dist/{types-DNwFvL-C.d.cts → types-CDKxdzQc.d.cts} +9 -0
- package/dist/{types-DNwFvL-C.d.ts → types-CDKxdzQc.d.ts} +9 -0
- package/dist/ui/index.cjs +952 -86
- 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 +950 -87
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { S as SystemBlock, T as ToolSchema, a as ToolContext, b as ToolDefinition, P as PresentPayload, c as PersistencePort, A as AuthPort, d as ScopePort, e as ToolsPort, V as VertexPort, L as LoggerPort } from '../types-
|
|
2
|
-
export { f as AiSettings, g as AiSettingsPatch, h as AppendMessageInput, i as AuthFail, j as AuthOk, k as AuthResult, B as Block, C as ChartSpec, l as ChatMessage, m as ChatMessageRole, n as ChatSession, o as CreateSessionInput, p as ListSessionsOpts, q as TERMINAL_TOOL_NAME, r as ToolResult, s as err, t as ok } from '../types-
|
|
1
|
+
import { S as SystemBlock, T as ToolSchema, a as ToolContext, b as ToolDefinition, P as PresentPayload, c as PersistencePort, A as AuthPort, d as ScopePort, e as ToolsPort, V as VertexPort, L as LoggerPort } from '../types-CDKxdzQc.cjs';
|
|
2
|
+
export { f as AiSettings, g as AiSettingsPatch, h as AppendMessageInput, i as AuthFail, j as AuthOk, k as AuthResult, B as Block, C as ChartSpec, l as ChatMessage, m as ChatMessageRole, n as ChatSession, o as CreateSessionInput, p as ListSessionsOpts, q as TERMINAL_TOOL_NAME, r as ToolResult, s as err, t as ok } from '../types-CDKxdzQc.cjs';
|
|
3
3
|
import { GoogleAuth } from 'google-auth-library';
|
|
4
4
|
export { GoogleAuth } from 'google-auth-library';
|
|
5
|
+
import 'zod';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Provider-agnostic tool-calling abstraction.
|
|
@@ -302,6 +303,34 @@ declare function createAgentCustomRoutes<S>(ctx: AgentCustomRouteCtx<S>): {
|
|
|
302
303
|
POST: (req: Request) => Promise<Response>;
|
|
303
304
|
};
|
|
304
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Streaming-route hooks for the Vercel AI SDK chat.
|
|
308
|
+
*
|
|
309
|
+
* Identical to `AgentCustomHooks` — the lifecycle (pre-auth → auth →
|
|
310
|
+
* post-auth → resolve session → onSessionStart → stream → onSessionEnd)
|
|
311
|
+
* is the same. We re-alias rather than introducing a new type so consumers
|
|
312
|
+
* can plug a single hook bag into both routes.
|
|
313
|
+
*/
|
|
314
|
+
type AgentVercelHooks$1<S> = AgentCustomHooks$1<S>;
|
|
315
|
+
type AgentVercelRouteCtx<S> = {
|
|
316
|
+
persistence: PersistencePort;
|
|
317
|
+
auth: AuthPort<S>;
|
|
318
|
+
scope: ScopePort<S>;
|
|
319
|
+
tools: ToolsPort;
|
|
320
|
+
vertex: VertexPort;
|
|
321
|
+
logger?: LoggerPort;
|
|
322
|
+
/**
|
|
323
|
+
* Optional lifecycle hooks. See `AgentCustomHooks` for the available
|
|
324
|
+
* extension points (shutdown gating, rate limiting, per-request
|
|
325
|
+
* resource setup/teardown).
|
|
326
|
+
*/
|
|
327
|
+
hooks?: AgentVercelHooks$1<S>;
|
|
328
|
+
};
|
|
329
|
+
declare function createAgentVercelRoutes<S>(ctx: AgentVercelRouteCtx<S>): {
|
|
330
|
+
/** Next.js-compatible POST handler. */
|
|
331
|
+
POST: (req: Request) => Promise<Response>;
|
|
332
|
+
};
|
|
333
|
+
|
|
305
334
|
/**
|
|
306
335
|
* `chat-sessions` route factory — host-agnostic CRUD for chat sessions.
|
|
307
336
|
*
|
|
@@ -501,6 +530,7 @@ type AiChatRuntime<S = unknown> = {
|
|
|
501
530
|
}) => Promise<AgentResult>;
|
|
502
531
|
routes: {
|
|
503
532
|
agentCustom: ReturnType<typeof createAgentCustomRoutes<S>>;
|
|
533
|
+
agentVercel: ReturnType<typeof createAgentVercelRoutes<S>>;
|
|
504
534
|
chatSessions: ReturnType<typeof createChatSessionsRoutes<S>>;
|
|
505
535
|
adminSettings: ReturnType<typeof createAdminSettingsRoutes<S>>;
|
|
506
536
|
};
|
|
@@ -513,5 +543,12 @@ declare function configureAiChat<S = unknown>(opts: ConfigureAiChatOpts<S>): AiC
|
|
|
513
543
|
|
|
514
544
|
type RouteHooks<S> = RouteHooks$1<S>;
|
|
515
545
|
type AgentCustomHooks<S> = AgentCustomHooks$1<S>;
|
|
546
|
+
/**
|
|
547
|
+
* Alias of `AgentCustomHooks` — the Vercel AI SDK chat reuses the same
|
|
548
|
+
* lifecycle (pre-auth → auth → post-auth → resolve session → onSessionStart
|
|
549
|
+
* → stream → onSessionEnd). Re-exported for callers that prefer the more
|
|
550
|
+
* specific name.
|
|
551
|
+
*/
|
|
552
|
+
type AgentVercelHooks<S> = AgentVercelHooks$1<S>;
|
|
516
553
|
|
|
517
|
-
export { type AgentCustomHooks, type AgentInput, type AgentResult, type AiChatRuntime, AuthPort, BUILTIN_CHAT_INTERFACE_IDS, type ChatInterfaceRegistryEntry, type ConfigureAiChatOpts, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MAX_TOOL_TURNS, LoggerPort, PersistencePort, PresentPayload, type ProviderInitOpts, type RouteHooks, ScopePort, SystemBlock, ToolContext, ToolDefinition, type ToolProviderDef, ToolSchema, ToolsPort, type TranscriptEntry, VertexPort, configureAiChat, getToolProvider, runAgent, toolProviders };
|
|
554
|
+
export { type AgentCustomHooks, type AgentInput, type AgentResult, type AgentVercelHooks, type AiChatRuntime, AuthPort, BUILTIN_CHAT_INTERFACE_IDS, type ChatInterfaceRegistryEntry, type ConfigureAiChatOpts, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MAX_TOOL_TURNS, LoggerPort, PersistencePort, PresentPayload, type ProviderInitOpts, type RouteHooks, ScopePort, SystemBlock, ToolContext, ToolDefinition, type ToolProviderDef, ToolSchema, ToolsPort, type TranscriptEntry, VertexPort, configureAiChat, getToolProvider, runAgent, toolProviders };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { S as SystemBlock, T as ToolSchema, a as ToolContext, b as ToolDefinition, P as PresentPayload, c as PersistencePort, A as AuthPort, d as ScopePort, e as ToolsPort, V as VertexPort, L as LoggerPort } from '../types-
|
|
2
|
-
export { f as AiSettings, g as AiSettingsPatch, h as AppendMessageInput, i as AuthFail, j as AuthOk, k as AuthResult, B as Block, C as ChartSpec, l as ChatMessage, m as ChatMessageRole, n as ChatSession, o as CreateSessionInput, p as ListSessionsOpts, q as TERMINAL_TOOL_NAME, r as ToolResult, s as err, t as ok } from '../types-
|
|
1
|
+
import { S as SystemBlock, T as ToolSchema, a as ToolContext, b as ToolDefinition, P as PresentPayload, c as PersistencePort, A as AuthPort, d as ScopePort, e as ToolsPort, V as VertexPort, L as LoggerPort } from '../types-CDKxdzQc.js';
|
|
2
|
+
export { f as AiSettings, g as AiSettingsPatch, h as AppendMessageInput, i as AuthFail, j as AuthOk, k as AuthResult, B as Block, C as ChartSpec, l as ChatMessage, m as ChatMessageRole, n as ChatSession, o as CreateSessionInput, p as ListSessionsOpts, q as TERMINAL_TOOL_NAME, r as ToolResult, s as err, t as ok } from '../types-CDKxdzQc.js';
|
|
3
3
|
import { GoogleAuth } from 'google-auth-library';
|
|
4
4
|
export { GoogleAuth } from 'google-auth-library';
|
|
5
|
+
import 'zod';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Provider-agnostic tool-calling abstraction.
|
|
@@ -302,6 +303,34 @@ declare function createAgentCustomRoutes<S>(ctx: AgentCustomRouteCtx<S>): {
|
|
|
302
303
|
POST: (req: Request) => Promise<Response>;
|
|
303
304
|
};
|
|
304
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Streaming-route hooks for the Vercel AI SDK chat.
|
|
308
|
+
*
|
|
309
|
+
* Identical to `AgentCustomHooks` — the lifecycle (pre-auth → auth →
|
|
310
|
+
* post-auth → resolve session → onSessionStart → stream → onSessionEnd)
|
|
311
|
+
* is the same. We re-alias rather than introducing a new type so consumers
|
|
312
|
+
* can plug a single hook bag into both routes.
|
|
313
|
+
*/
|
|
314
|
+
type AgentVercelHooks$1<S> = AgentCustomHooks$1<S>;
|
|
315
|
+
type AgentVercelRouteCtx<S> = {
|
|
316
|
+
persistence: PersistencePort;
|
|
317
|
+
auth: AuthPort<S>;
|
|
318
|
+
scope: ScopePort<S>;
|
|
319
|
+
tools: ToolsPort;
|
|
320
|
+
vertex: VertexPort;
|
|
321
|
+
logger?: LoggerPort;
|
|
322
|
+
/**
|
|
323
|
+
* Optional lifecycle hooks. See `AgentCustomHooks` for the available
|
|
324
|
+
* extension points (shutdown gating, rate limiting, per-request
|
|
325
|
+
* resource setup/teardown).
|
|
326
|
+
*/
|
|
327
|
+
hooks?: AgentVercelHooks$1<S>;
|
|
328
|
+
};
|
|
329
|
+
declare function createAgentVercelRoutes<S>(ctx: AgentVercelRouteCtx<S>): {
|
|
330
|
+
/** Next.js-compatible POST handler. */
|
|
331
|
+
POST: (req: Request) => Promise<Response>;
|
|
332
|
+
};
|
|
333
|
+
|
|
305
334
|
/**
|
|
306
335
|
* `chat-sessions` route factory — host-agnostic CRUD for chat sessions.
|
|
307
336
|
*
|
|
@@ -501,6 +530,7 @@ type AiChatRuntime<S = unknown> = {
|
|
|
501
530
|
}) => Promise<AgentResult>;
|
|
502
531
|
routes: {
|
|
503
532
|
agentCustom: ReturnType<typeof createAgentCustomRoutes<S>>;
|
|
533
|
+
agentVercel: ReturnType<typeof createAgentVercelRoutes<S>>;
|
|
504
534
|
chatSessions: ReturnType<typeof createChatSessionsRoutes<S>>;
|
|
505
535
|
adminSettings: ReturnType<typeof createAdminSettingsRoutes<S>>;
|
|
506
536
|
};
|
|
@@ -513,5 +543,12 @@ declare function configureAiChat<S = unknown>(opts: ConfigureAiChatOpts<S>): AiC
|
|
|
513
543
|
|
|
514
544
|
type RouteHooks<S> = RouteHooks$1<S>;
|
|
515
545
|
type AgentCustomHooks<S> = AgentCustomHooks$1<S>;
|
|
546
|
+
/**
|
|
547
|
+
* Alias of `AgentCustomHooks` — the Vercel AI SDK chat reuses the same
|
|
548
|
+
* lifecycle (pre-auth → auth → post-auth → resolve session → onSessionStart
|
|
549
|
+
* → stream → onSessionEnd). Re-exported for callers that prefer the more
|
|
550
|
+
* specific name.
|
|
551
|
+
*/
|
|
552
|
+
type AgentVercelHooks<S> = AgentVercelHooks$1<S>;
|
|
516
553
|
|
|
517
|
-
export { type AgentCustomHooks, type AgentInput, type AgentResult, type AiChatRuntime, AuthPort, BUILTIN_CHAT_INTERFACE_IDS, type ChatInterfaceRegistryEntry, type ConfigureAiChatOpts, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MAX_TOOL_TURNS, LoggerPort, PersistencePort, PresentPayload, type ProviderInitOpts, type RouteHooks, ScopePort, SystemBlock, ToolContext, ToolDefinition, type ToolProviderDef, ToolSchema, ToolsPort, type TranscriptEntry, VertexPort, configureAiChat, getToolProvider, runAgent, toolProviders };
|
|
554
|
+
export { type AgentCustomHooks, type AgentInput, type AgentResult, type AgentVercelHooks, type AiChatRuntime, AuthPort, BUILTIN_CHAT_INTERFACE_IDS, type ChatInterfaceRegistryEntry, type ConfigureAiChatOpts, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MAX_TOOL_TURNS, LoggerPort, PersistencePort, PresentPayload, type ProviderInitOpts, type RouteHooks, ScopePort, SystemBlock, ToolContext, ToolDefinition, type ToolProviderDef, ToolSchema, ToolsPort, type TranscriptEntry, VertexPort, configureAiChat, getToolProvider, runAgent, toolProviders };
|
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { AnthropicVertex } from '@anthropic-ai/vertex-sdk';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
|
+
import { StreamData, streamText, tool } from 'ai';
|
|
4
|
+
import { createVertex } from '@ai-sdk/google-vertex';
|
|
5
|
+
import { createVertexAnthropic } from '@ai-sdk/google-vertex/anthropic';
|
|
3
6
|
export { GoogleAuth } from 'google-auth-library';
|
|
4
7
|
|
|
5
8
|
// src/server/tools/types.ts
|
|
@@ -70,8 +73,8 @@ async function runAgent(input) {
|
|
|
70
73
|
const toolResults = [];
|
|
71
74
|
for (const tc of response.toolCalls) {
|
|
72
75
|
transcript.push({ kind: "tool_use", name: tc.name, input: tc.input });
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
76
|
+
const tool2 = input.tools[tc.name];
|
|
77
|
+
if (!tool2) {
|
|
75
78
|
const errResult = {
|
|
76
79
|
ok: false,
|
|
77
80
|
error: { code: "UNKNOWN_TOOL", message: `Unknown tool: ${tc.name}` }
|
|
@@ -85,7 +88,7 @@ async function runAgent(input) {
|
|
|
85
88
|
});
|
|
86
89
|
continue;
|
|
87
90
|
}
|
|
88
|
-
const result = await
|
|
91
|
+
const result = await tool2.execute(tc.input, {
|
|
89
92
|
...input.ctx,
|
|
90
93
|
toolCallCount
|
|
91
94
|
});
|
|
@@ -1135,6 +1138,297 @@ data: {}
|
|
|
1135
1138
|
}
|
|
1136
1139
|
};
|
|
1137
1140
|
}
|
|
1141
|
+
function buildVercelTools(tools, ctx, data, onPresent) {
|
|
1142
|
+
const result = {};
|
|
1143
|
+
let toolCallCount = 0;
|
|
1144
|
+
for (const [name, def] of Object.entries(tools)) {
|
|
1145
|
+
if (!def.zodSchema) {
|
|
1146
|
+
throw new Error(
|
|
1147
|
+
`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).`
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
if (name === TERMINAL_TOOL_NAME) {
|
|
1151
|
+
result[name] = tool({
|
|
1152
|
+
description: def.schema.description,
|
|
1153
|
+
// The Zod schema doubles as the runtime parameter validator the SDK
|
|
1154
|
+
// hands the model. We accept whatever Zod shape the host registered;
|
|
1155
|
+
// the SDK uses it to validate the tool-call arguments before dispatch.
|
|
1156
|
+
parameters: def.zodSchema,
|
|
1157
|
+
execute: async (input) => {
|
|
1158
|
+
if (toolCallCount < 2) {
|
|
1159
|
+
return {
|
|
1160
|
+
error: {
|
|
1161
|
+
code: "SELF_VERIFY_REQUIRED",
|
|
1162
|
+
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."
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
const payload = input;
|
|
1167
|
+
for (let i = 0; i < payload.blocks.length; i++) {
|
|
1168
|
+
data.append({
|
|
1169
|
+
type: "block",
|
|
1170
|
+
value: { index: i, ...payload.blocks[i] }
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
onPresent(payload);
|
|
1174
|
+
return { ok: true };
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
result[name] = tool({
|
|
1180
|
+
description: def.schema.description,
|
|
1181
|
+
parameters: def.zodSchema,
|
|
1182
|
+
execute: async (input) => {
|
|
1183
|
+
const res = await def.execute(input, { ...ctx, toolCallCount });
|
|
1184
|
+
toolCallCount += 1;
|
|
1185
|
+
if (res.ok) return res.data;
|
|
1186
|
+
return { error: res.error };
|
|
1187
|
+
}
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
return result;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/server/routes/agent-vercel.ts
|
|
1194
|
+
var VALID_MODELS = /* @__PURE__ */ new Set(["claude", "gemini"]);
|
|
1195
|
+
function jsonError2(status, code, message) {
|
|
1196
|
+
return new Response(JSON.stringify({ error: { code, message } }), {
|
|
1197
|
+
status,
|
|
1198
|
+
headers: { "Content-Type": "application/json" }
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
function defaultGenerateSessionId2() {
|
|
1202
|
+
return randomUUID().replace(/-/g, "").slice(0, 16);
|
|
1203
|
+
}
|
|
1204
|
+
function createAgentVercelRoutes(ctx) {
|
|
1205
|
+
const { persistence, auth, scope, tools, vertex, logger, hooks } = ctx;
|
|
1206
|
+
return {
|
|
1207
|
+
/** Next.js-compatible POST handler. */
|
|
1208
|
+
POST: async (req) => {
|
|
1209
|
+
if (hooks?.onRequest) {
|
|
1210
|
+
const short = await hooks.onRequest(req);
|
|
1211
|
+
if (short) return short;
|
|
1212
|
+
}
|
|
1213
|
+
const authResult = await auth.requireAuth(req);
|
|
1214
|
+
if (!authResult.ok) return authResult.response;
|
|
1215
|
+
const { scope: callerScope, userId } = authResult;
|
|
1216
|
+
if (hooks?.onAuthenticated) {
|
|
1217
|
+
const short = await hooks.onAuthenticated({
|
|
1218
|
+
req,
|
|
1219
|
+
scope: callerScope,
|
|
1220
|
+
userId
|
|
1221
|
+
});
|
|
1222
|
+
if (short) return short;
|
|
1223
|
+
}
|
|
1224
|
+
const body = await req.json().catch(() => null);
|
|
1225
|
+
const question = typeof body?.question === "string" ? body.question.trim() : "";
|
|
1226
|
+
if (!question) {
|
|
1227
|
+
return jsonError2(
|
|
1228
|
+
400,
|
|
1229
|
+
"VALIDATION_FAILED",
|
|
1230
|
+
"question must be a non-empty string."
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
const rawChatSessionId = body?.chatSessionId;
|
|
1234
|
+
const incomingChatSessionId = typeof rawChatSessionId === "number" && Number.isInteger(rawChatSessionId) ? rawChatSessionId : null;
|
|
1235
|
+
const rawModel = body?.model;
|
|
1236
|
+
const requestedModel = typeof rawModel === "string" && VALID_MODELS.has(rawModel) ? rawModel : null;
|
|
1237
|
+
const aiSettings = await persistence.getAiSettings();
|
|
1238
|
+
let chatSessionId;
|
|
1239
|
+
if (incomingChatSessionId !== null) {
|
|
1240
|
+
const owned = await persistence.getSession(
|
|
1241
|
+
incomingChatSessionId,
|
|
1242
|
+
userId
|
|
1243
|
+
);
|
|
1244
|
+
if (!owned) {
|
|
1245
|
+
return jsonError2(404, "NOT_FOUND", "Chat session not found.");
|
|
1246
|
+
}
|
|
1247
|
+
chatSessionId = owned.id;
|
|
1248
|
+
} else {
|
|
1249
|
+
const created = await persistence.createSession({
|
|
1250
|
+
userId,
|
|
1251
|
+
title: question.slice(0, 200)
|
|
1252
|
+
});
|
|
1253
|
+
chatSessionId = created.id;
|
|
1254
|
+
}
|
|
1255
|
+
await persistence.appendMessage({
|
|
1256
|
+
sessionId: chatSessionId,
|
|
1257
|
+
role: "user",
|
|
1258
|
+
question
|
|
1259
|
+
});
|
|
1260
|
+
const sessionId = hooks?.generateSessionId ? await hooks.generateSessionId({
|
|
1261
|
+
scope: callerScope,
|
|
1262
|
+
userId,
|
|
1263
|
+
chatSessionId: incomingChatSessionId
|
|
1264
|
+
}) : defaultGenerateSessionId2();
|
|
1265
|
+
const scopeSummary = await scope.buildScopeSummary(callerScope);
|
|
1266
|
+
const scopeLabel = await scope.resolveScopeLabel(callerScope);
|
|
1267
|
+
const toolContext = {
|
|
1268
|
+
scope: callerScope,
|
|
1269
|
+
sessionId,
|
|
1270
|
+
scopeSummary,
|
|
1271
|
+
toolCallCount: 0
|
|
1272
|
+
};
|
|
1273
|
+
const systemBlocks = await tools.buildSystemBlocks(toolContext);
|
|
1274
|
+
const provider = requestedModel ?? aiSettings.toolProvider;
|
|
1275
|
+
if (!VALID_MODELS.has(provider)) {
|
|
1276
|
+
return jsonError2(
|
|
1277
|
+
400,
|
|
1278
|
+
"INVALID_PROVIDER",
|
|
1279
|
+
`Vercel chat only supports 'claude' or 'gemini'; got '${provider}'.`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
const data = new StreamData();
|
|
1283
|
+
let presentPayload = null;
|
|
1284
|
+
let persistedError = null;
|
|
1285
|
+
let sessionStarted = false;
|
|
1286
|
+
try {
|
|
1287
|
+
if (hooks?.onSessionStart) {
|
|
1288
|
+
await hooks.onSessionStart({
|
|
1289
|
+
scope: callerScope,
|
|
1290
|
+
sessionId,
|
|
1291
|
+
userId
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
sessionStarted = true;
|
|
1295
|
+
const vercelTools = buildVercelTools(
|
|
1296
|
+
tools.tools,
|
|
1297
|
+
toolContext,
|
|
1298
|
+
data,
|
|
1299
|
+
(p) => {
|
|
1300
|
+
presentPayload = p;
|
|
1301
|
+
}
|
|
1302
|
+
);
|
|
1303
|
+
data.append({
|
|
1304
|
+
type: "meta",
|
|
1305
|
+
value: { chatSessionId, scopeLabel }
|
|
1306
|
+
});
|
|
1307
|
+
const system = systemBlocks.map((b) => b.text).join("\n\n");
|
|
1308
|
+
const model = provider === "claude" ? createVertexAnthropic({
|
|
1309
|
+
project: vertex.projectId,
|
|
1310
|
+
location: vertex.defaultLocation,
|
|
1311
|
+
googleAuthOptions: {}
|
|
1312
|
+
})(vertex.modelIds.claude) : createVertex({
|
|
1313
|
+
project: vertex.projectId,
|
|
1314
|
+
location: aiSettings.gcpLocation,
|
|
1315
|
+
googleAuthOptions: {}
|
|
1316
|
+
})(vertex.modelIds.gemini);
|
|
1317
|
+
const result = streamText({
|
|
1318
|
+
model,
|
|
1319
|
+
system,
|
|
1320
|
+
messages: [{ role: "user", content: question }],
|
|
1321
|
+
tools: vercelTools,
|
|
1322
|
+
maxSteps: 12,
|
|
1323
|
+
maxTokens: 4096,
|
|
1324
|
+
onFinish: async ({ text }) => {
|
|
1325
|
+
try {
|
|
1326
|
+
let blocks = presentPayload?.blocks ?? [];
|
|
1327
|
+
const prose = {};
|
|
1328
|
+
const trimmed = (text ?? "").trim();
|
|
1329
|
+
if (presentPayload === null && trimmed) {
|
|
1330
|
+
const topic = question.length > 80 ? question.slice(0, 77) + "..." : question;
|
|
1331
|
+
const synthetic = {
|
|
1332
|
+
kind: "paragraph_brief",
|
|
1333
|
+
topic,
|
|
1334
|
+
key_facts: [trimmed]
|
|
1335
|
+
};
|
|
1336
|
+
blocks = [synthetic];
|
|
1337
|
+
prose[0] = trimmed;
|
|
1338
|
+
data.append({
|
|
1339
|
+
type: "block",
|
|
1340
|
+
value: { index: 0, ...synthetic }
|
|
1341
|
+
});
|
|
1342
|
+
} else if (text) {
|
|
1343
|
+
const firstPbIdx = blocks.findIndex(
|
|
1344
|
+
(b) => b.kind === "paragraph_brief"
|
|
1345
|
+
);
|
|
1346
|
+
if (firstPbIdx >= 0) prose[firstPbIdx] = text;
|
|
1347
|
+
}
|
|
1348
|
+
await persistence.appendMessage({
|
|
1349
|
+
sessionId: chatSessionId,
|
|
1350
|
+
role: "assistant",
|
|
1351
|
+
blocks: blocks.length ? blocks : null,
|
|
1352
|
+
prose: Object.keys(prose).length ? prose : null,
|
|
1353
|
+
errorJson: persistedError
|
|
1354
|
+
});
|
|
1355
|
+
} catch (err2) {
|
|
1356
|
+
logger?.warn?.(
|
|
1357
|
+
{
|
|
1358
|
+
chatSessionId,
|
|
1359
|
+
sessionId,
|
|
1360
|
+
err: err2.message
|
|
1361
|
+
},
|
|
1362
|
+
"[agent-vercel] failed to persist assistant turn"
|
|
1363
|
+
);
|
|
1364
|
+
} finally {
|
|
1365
|
+
try {
|
|
1366
|
+
await data.close();
|
|
1367
|
+
} catch {
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
return result.toDataStreamResponse({ data });
|
|
1373
|
+
} catch (e) {
|
|
1374
|
+
const message = e.message ?? "Internal error";
|
|
1375
|
+
persistedError = { code: "INTERNAL", message };
|
|
1376
|
+
logger?.error?.(
|
|
1377
|
+
{ chatSessionId, sessionId, err: message },
|
|
1378
|
+
"[agent-vercel] route errored"
|
|
1379
|
+
);
|
|
1380
|
+
try {
|
|
1381
|
+
data.append({
|
|
1382
|
+
type: "error",
|
|
1383
|
+
value: { code: "INTERNAL", message }
|
|
1384
|
+
});
|
|
1385
|
+
} catch {
|
|
1386
|
+
}
|
|
1387
|
+
try {
|
|
1388
|
+
await data.close();
|
|
1389
|
+
} catch {
|
|
1390
|
+
}
|
|
1391
|
+
try {
|
|
1392
|
+
await persistence.appendMessage({
|
|
1393
|
+
sessionId: chatSessionId,
|
|
1394
|
+
role: "assistant",
|
|
1395
|
+
blocks: null,
|
|
1396
|
+
prose: null,
|
|
1397
|
+
errorJson: persistedError
|
|
1398
|
+
});
|
|
1399
|
+
} catch (err2) {
|
|
1400
|
+
logger?.warn?.(
|
|
1401
|
+
{ chatSessionId, sessionId, err: err2.message },
|
|
1402
|
+
"[agent-vercel] failed to persist error turn"
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
return jsonError2(500, "INTERNAL", message);
|
|
1406
|
+
} finally {
|
|
1407
|
+
if (hooks?.onSessionEnd) {
|
|
1408
|
+
const cause = req.signal.aborted ? "abort" : persistedError ? "error" : "complete";
|
|
1409
|
+
try {
|
|
1410
|
+
await hooks.onSessionEnd({
|
|
1411
|
+
scope: callerScope,
|
|
1412
|
+
sessionId,
|
|
1413
|
+
userId,
|
|
1414
|
+
cause
|
|
1415
|
+
});
|
|
1416
|
+
} catch (err2) {
|
|
1417
|
+
logger?.warn?.(
|
|
1418
|
+
{
|
|
1419
|
+
chatSessionId,
|
|
1420
|
+
sessionId,
|
|
1421
|
+
sessionStarted,
|
|
1422
|
+
err: err2.message
|
|
1423
|
+
},
|
|
1424
|
+
"[agent-vercel] onSessionEnd hook failed"
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1138
1432
|
|
|
1139
1433
|
// src/server/routes/chat-sessions.ts
|
|
1140
1434
|
var DEFAULT_TITLE = "New chat";
|
|
@@ -1495,6 +1789,15 @@ function configureAiChat(opts) {
|
|
|
1495
1789
|
resolveNarratorId: opts.resolveNarratorId,
|
|
1496
1790
|
hooks: opts.hooks
|
|
1497
1791
|
});
|
|
1792
|
+
const agentVercel = createAgentVercelRoutes({
|
|
1793
|
+
persistence: opts.persistence,
|
|
1794
|
+
auth: opts.auth,
|
|
1795
|
+
scope: opts.scope,
|
|
1796
|
+
tools,
|
|
1797
|
+
vertex: opts.vertex,
|
|
1798
|
+
logger: opts.logger,
|
|
1799
|
+
hooks: opts.hooks
|
|
1800
|
+
});
|
|
1498
1801
|
const chatSessions = createChatSessionsRoutes({
|
|
1499
1802
|
persistence: opts.persistence,
|
|
1500
1803
|
auth: opts.auth,
|
|
@@ -1511,7 +1814,7 @@ function configureAiChat(opts) {
|
|
|
1511
1814
|
});
|
|
1512
1815
|
return {
|
|
1513
1816
|
runAgent: runAgentBound,
|
|
1514
|
-
routes: { agentCustom, chatSessions, adminSettings },
|
|
1817
|
+
routes: { agentCustom, agentVercel, chatSessions, adminSettings },
|
|
1515
1818
|
registries: { toolProviders: toolProviders2, chatInterfaces }
|
|
1516
1819
|
};
|
|
1517
1820
|
}
|