@firstlovecenter/ai-chat 0.5.0 → 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 +32 -0
- package/dist/drizzle/index.cjs +24 -0
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +35 -1
- package/dist/drizzle/index.d.ts +35 -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 +7 -1
- package/dist/prisma/index.d.ts +7 -1
- package/dist/prisma/index.js +7 -0
- package/dist/prisma/index.js.map +1 -1
- package/dist/server/index.cjs +47 -12
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +12 -3
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.js +47 -12
- package/dist/server/index.js.map +1 -1
- package/dist/{types-CDKxdzQc.d.cts → types-CQntnyDJ.d.cts} +15 -2
- package/dist/{types-CDKxdzQc.d.ts → types-CQntnyDJ.d.ts} +15 -2
- package/dist/ui/index.cjs +74 -3
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +74 -3
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
- package/prisma/chat-models.prisma +7 -0
package/dist/server/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-CQntnyDJ.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-CQntnyDJ.cjs';
|
|
3
3
|
import { GoogleAuth } from 'google-auth-library';
|
|
4
4
|
export { GoogleAuth } from 'google-auth-library';
|
|
5
5
|
import 'zod';
|
|
@@ -398,7 +398,7 @@ declare function createChatSessionsRoutes<S>(ctx: ChatSessionsRouteCtx<S>): {
|
|
|
398
398
|
/**
|
|
399
399
|
* `/api/admin/ai-settings` route factory — global AI configuration (super_admin only).
|
|
400
400
|
*
|
|
401
|
-
*
|
|
401
|
+
* Five patchable fields on the singleton settings row:
|
|
402
402
|
* - `tool_provider` — vendor that drives the agent tool loop. Validated
|
|
403
403
|
* against the registered `toolProviders` registry passed in via ctx.
|
|
404
404
|
* - `gcp_location` — the Vertex region every provider call hits. Stays
|
|
@@ -408,6 +408,15 @@ declare function createChatSessionsRoutes<S>(ctx: ChatSessionsRouteCtx<S>): {
|
|
|
408
408
|
* against the `chatInterfaces` registry passed in via ctx (the actual
|
|
409
409
|
* registry lives in `@firstlovecenter/ai-chat/ui` so the host wires it through;
|
|
410
410
|
* the route stays free of UI imports).
|
|
411
|
+
* - `max_output_tokens` — caps the agent loop's per-turn output AND each
|
|
412
|
+
* narrator's prose pass. Bounded `[256, 64000]` — anything below 256 can't
|
|
413
|
+
* fit a useful response, anything above 64000 exceeds the headroom of any
|
|
414
|
+
* model currently routed through Vertex.
|
|
415
|
+
* - `role_prompt` — admin-editable persona string. Empty string and the
|
|
416
|
+
* explicit JSON `null` both clear the override back to the host's static
|
|
417
|
+
* `configureAiChat({ rolePrompt })` fallback; we canonicalise an empty/
|
|
418
|
+
* whitespace-only string to `null` on write so the "no override" state has
|
|
419
|
+
* a single representation in storage.
|
|
411
420
|
*
|
|
412
421
|
* Wire format is snake_case to preserve byte-for-byte parity with the
|
|
413
422
|
* host route the package replaces — existing host UIs keep working
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-CQntnyDJ.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-CQntnyDJ.js';
|
|
3
3
|
import { GoogleAuth } from 'google-auth-library';
|
|
4
4
|
export { GoogleAuth } from 'google-auth-library';
|
|
5
5
|
import 'zod';
|
|
@@ -398,7 +398,7 @@ declare function createChatSessionsRoutes<S>(ctx: ChatSessionsRouteCtx<S>): {
|
|
|
398
398
|
/**
|
|
399
399
|
* `/api/admin/ai-settings` route factory — global AI configuration (super_admin only).
|
|
400
400
|
*
|
|
401
|
-
*
|
|
401
|
+
* Five patchable fields on the singleton settings row:
|
|
402
402
|
* - `tool_provider` — vendor that drives the agent tool loop. Validated
|
|
403
403
|
* against the registered `toolProviders` registry passed in via ctx.
|
|
404
404
|
* - `gcp_location` — the Vertex region every provider call hits. Stays
|
|
@@ -408,6 +408,15 @@ declare function createChatSessionsRoutes<S>(ctx: ChatSessionsRouteCtx<S>): {
|
|
|
408
408
|
* against the `chatInterfaces` registry passed in via ctx (the actual
|
|
409
409
|
* registry lives in `@firstlovecenter/ai-chat/ui` so the host wires it through;
|
|
410
410
|
* the route stays free of UI imports).
|
|
411
|
+
* - `max_output_tokens` — caps the agent loop's per-turn output AND each
|
|
412
|
+
* narrator's prose pass. Bounded `[256, 64000]` — anything below 256 can't
|
|
413
|
+
* fit a useful response, anything above 64000 exceeds the headroom of any
|
|
414
|
+
* model currently routed through Vertex.
|
|
415
|
+
* - `role_prompt` — admin-editable persona string. Empty string and the
|
|
416
|
+
* explicit JSON `null` both clear the override back to the host's static
|
|
417
|
+
* `configureAiChat({ rolePrompt })` fallback; we canonicalise an empty/
|
|
418
|
+
* whitespace-only string to `null` on write so the "no override" state has
|
|
419
|
+
* a single representation in storage.
|
|
411
420
|
*
|
|
412
421
|
* Wire format is snake_case to preserve byte-for-byte parity with the
|
|
413
422
|
* host route the package replaces — existing host UIs keep working
|
package/dist/server/index.js
CHANGED
|
@@ -650,7 +650,7 @@ async function* streamClaudeNarration(opts) {
|
|
|
650
650
|
});
|
|
651
651
|
const stream = await client.messages.stream({
|
|
652
652
|
model: opts.modelId,
|
|
653
|
-
max_tokens:
|
|
653
|
+
max_tokens: opts.maxTokens,
|
|
654
654
|
system: NARRATIVE_SYSTEM,
|
|
655
655
|
messages: [{ role: "user", content: buildNarrativeUserMessage(opts.input) }]
|
|
656
656
|
});
|
|
@@ -710,7 +710,7 @@ async function* streamGeminiNarration(opts) {
|
|
|
710
710
|
parts: [{ text: buildNarrativeUserMessage(opts.input) }]
|
|
711
711
|
}
|
|
712
712
|
],
|
|
713
|
-
generationConfig: { maxOutputTokens:
|
|
713
|
+
generationConfig: { maxOutputTokens: opts.maxTokens, temperature: 0 }
|
|
714
714
|
})
|
|
715
715
|
});
|
|
716
716
|
if (!res.ok || !res.body) {
|
|
@@ -786,7 +786,7 @@ async function* streamGrokNarration(opts) {
|
|
|
786
786
|
},
|
|
787
787
|
body: JSON.stringify({
|
|
788
788
|
model: opts.modelId,
|
|
789
|
-
max_tokens:
|
|
789
|
+
max_tokens: opts.maxTokens,
|
|
790
790
|
stream: true,
|
|
791
791
|
messages: [
|
|
792
792
|
{ role: "system", content: NARRATIVE_SYSTEM3 },
|
|
@@ -1009,7 +1009,8 @@ data: ${JSON.stringify(data)}
|
|
|
1009
1009
|
ctx: toolContext,
|
|
1010
1010
|
tools: tools.tools,
|
|
1011
1011
|
systemBlocks,
|
|
1012
|
-
provider
|
|
1012
|
+
provider,
|
|
1013
|
+
maxOutputTokens: aiSettings.maxOutputTokens
|
|
1013
1014
|
});
|
|
1014
1015
|
if (!agentResult.ok) {
|
|
1015
1016
|
persistedError = agentResult.error;
|
|
@@ -1035,6 +1036,7 @@ data: ${JSON.stringify(data)}
|
|
|
1035
1036
|
projectId: vertex.projectId,
|
|
1036
1037
|
location: aiSettings.gcpLocation,
|
|
1037
1038
|
modelId: narratorModelId,
|
|
1039
|
+
maxTokens: aiSettings.maxOutputTokens,
|
|
1038
1040
|
input: {
|
|
1039
1041
|
question,
|
|
1040
1042
|
structured,
|
|
@@ -1320,7 +1322,7 @@ function createAgentVercelRoutes(ctx) {
|
|
|
1320
1322
|
messages: [{ role: "user", content: question }],
|
|
1321
1323
|
tools: vercelTools,
|
|
1322
1324
|
maxSteps: 12,
|
|
1323
|
-
maxTokens:
|
|
1325
|
+
maxTokens: aiSettings.maxOutputTokens,
|
|
1324
1326
|
onFinish: async ({ text }) => {
|
|
1325
1327
|
try {
|
|
1326
1328
|
let blocks = presentPayload?.blocks ?? [];
|
|
@@ -1609,6 +1611,8 @@ function createChatSessionsRoutes(ctx) {
|
|
|
1609
1611
|
|
|
1610
1612
|
// src/server/routes/admin-settings.ts
|
|
1611
1613
|
var VALID_LOCATIONS = ["us-east5", "global"];
|
|
1614
|
+
var MIN_MAX_OUTPUT_TOKENS = 256;
|
|
1615
|
+
var MAX_MAX_OUTPUT_TOKENS = 64e3;
|
|
1612
1616
|
function isStringRecord(v) {
|
|
1613
1617
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1614
1618
|
}
|
|
@@ -1623,6 +1627,8 @@ function toWire(settings) {
|
|
|
1623
1627
|
tool_provider: settings.toolProvider,
|
|
1624
1628
|
gcp_location: settings.gcpLocation,
|
|
1625
1629
|
chat_interface: settings.chatInterface,
|
|
1630
|
+
max_output_tokens: settings.maxOutputTokens,
|
|
1631
|
+
role_prompt: settings.rolePrompt,
|
|
1626
1632
|
updated_at: settings.updatedAt ? settings.updatedAt.toISOString() : null,
|
|
1627
1633
|
updated_by_user_id: settings.updatedByUserId
|
|
1628
1634
|
};
|
|
@@ -1702,11 +1708,29 @@ function createAdminSettingsRoutes(ctx) {
|
|
|
1702
1708
|
}
|
|
1703
1709
|
patch.chatInterface = v;
|
|
1704
1710
|
}
|
|
1705
|
-
if (
|
|
1711
|
+
if ("max_output_tokens" in body) {
|
|
1712
|
+
const v = body.max_output_tokens;
|
|
1713
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_MAX_OUTPUT_TOKENS || v > MAX_MAX_OUTPUT_TOKENS) {
|
|
1714
|
+
return jsonResponse({ error: "invalid_max_output_tokens" }, 400);
|
|
1715
|
+
}
|
|
1716
|
+
patch.maxOutputTokens = v;
|
|
1717
|
+
}
|
|
1718
|
+
if ("role_prompt" in body) {
|
|
1719
|
+
const v = body.role_prompt;
|
|
1720
|
+
if (v === null) {
|
|
1721
|
+
patch.rolePrompt = null;
|
|
1722
|
+
} else if (typeof v === "string") {
|
|
1723
|
+
const trimmed = v.trim();
|
|
1724
|
+
patch.rolePrompt = trimmed === "" ? null : trimmed;
|
|
1725
|
+
} else {
|
|
1726
|
+
return jsonResponse({ error: "invalid_role_prompt" }, 400);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
if (patch.toolProvider === void 0 && patch.gcpLocation === void 0 && patch.chatInterface === void 0 && patch.maxOutputTokens === void 0 && !("rolePrompt" in patch)) {
|
|
1706
1730
|
return jsonResponse(
|
|
1707
1731
|
{
|
|
1708
1732
|
error: "empty_patch",
|
|
1709
|
-
message: "Body must set at least one of tool_provider, gcp_location, chat_interface."
|
|
1733
|
+
message: "Body must set at least one of tool_provider, gcp_location, chat_interface, max_output_tokens, role_prompt."
|
|
1710
1734
|
},
|
|
1711
1735
|
400
|
|
1712
1736
|
);
|
|
@@ -1731,16 +1755,27 @@ function configureAiChat(opts) {
|
|
|
1731
1755
|
];
|
|
1732
1756
|
const getProvider = (id) => toolProviders2.find((p) => p.id === id) ?? getToolProvider(id);
|
|
1733
1757
|
const chatInterfaces = opts.chatInterfaces ?? BUILTIN_CHAT_INTERFACE_IDS.map((id) => ({ id }));
|
|
1734
|
-
const
|
|
1758
|
+
const staticRolePrompt = opts.rolePrompt;
|
|
1759
|
+
const tools = {
|
|
1735
1760
|
tools: opts.tools.tools,
|
|
1736
1761
|
async buildSystemBlocks(ctx) {
|
|
1737
1762
|
const inner = await opts.tools.buildSystemBlocks(ctx);
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1763
|
+
let role = null;
|
|
1764
|
+
try {
|
|
1765
|
+
const settings = await opts.persistence.getAiSettings();
|
|
1766
|
+
if (settings.rolePrompt && settings.rolePrompt.trim()) {
|
|
1767
|
+
role = settings.rolePrompt;
|
|
1768
|
+
}
|
|
1769
|
+
} catch {
|
|
1770
|
+
}
|
|
1771
|
+
if (!role && staticRolePrompt) {
|
|
1772
|
+
const resolved = typeof staticRolePrompt === "function" ? await staticRolePrompt(ctx) : staticRolePrompt;
|
|
1773
|
+
if (resolved && resolved.trim()) role = resolved;
|
|
1774
|
+
}
|
|
1775
|
+
if (!role) return inner;
|
|
1741
1776
|
return [{ text: role, cached: true }, ...inner];
|
|
1742
1777
|
}
|
|
1743
|
-
}
|
|
1778
|
+
};
|
|
1744
1779
|
const runAgentBound = async ({
|
|
1745
1780
|
question,
|
|
1746
1781
|
ctx,
|