@apart-tech/intelligence-core 1.18.0 → 1.20.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/dist/auth/ability.d.ts +1 -1
- package/dist/auth/ability.d.ts.map +1 -1
- package/dist/auth/ability.js +21 -3
- package/dist/auth/ability.js.map +1 -1
- package/dist/auth/ability.test.js +51 -10
- package/dist/auth/ability.test.js.map +1 -1
- package/dist/db/tenant.d.ts.map +1 -1
- package/dist/db/tenant.js +10 -0
- package/dist/db/tenant.js.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/services/chat-capture-service.d.ts +19 -0
- package/dist/services/chat-capture-service.d.ts.map +1 -0
- package/dist/services/chat-capture-service.js +74 -0
- package/dist/services/chat-capture-service.js.map +1 -0
- package/dist/services/chat-context-service.d.ts +33 -0
- package/dist/services/chat-context-service.d.ts.map +1 -0
- package/dist/services/chat-context-service.js +110 -0
- package/dist/services/chat-context-service.js.map +1 -0
- package/dist/services/chat-service.d.ts +83 -0
- package/dist/services/chat-service.d.ts.map +1 -0
- package/dist/services/chat-service.js +103 -0
- package/dist/services/chat-service.js.map +1 -0
- package/dist/services/chat-usage-service.d.ts +36 -0
- package/dist/services/chat-usage-service.d.ts.map +1 -0
- package/dist/services/chat-usage-service.js +89 -0
- package/dist/services/chat-usage-service.js.map +1 -0
- package/dist/services/content-policy-service.d.ts +71 -0
- package/dist/services/content-policy-service.d.ts.map +1 -0
- package/dist/services/content-policy-service.js +109 -0
- package/dist/services/content-policy-service.js.map +1 -0
- package/dist/services/llm-router-service.d.ts +29 -0
- package/dist/services/llm-router-service.d.ts.map +1 -0
- package/dist/services/llm-router-service.js +70 -0
- package/dist/services/llm-router-service.js.map +1 -0
- package/dist/services/org-llm-provider-service.d.ts +47 -0
- package/dist/services/org-llm-provider-service.d.ts.map +1 -0
- package/dist/services/org-llm-provider-service.js +126 -0
- package/dist/services/org-llm-provider-service.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +148 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export class ChatCaptureService {
|
|
2
|
+
chatService;
|
|
3
|
+
nodeService;
|
|
4
|
+
edgeService;
|
|
5
|
+
constructor(chatService, nodeService, edgeService) {
|
|
6
|
+
this.chatService = chatService;
|
|
7
|
+
this.nodeService = nodeService;
|
|
8
|
+
this.edgeService = edgeService;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Capture a chat session as a graph node with an LLM-generated summary.
|
|
12
|
+
* The caller provides the LLM summarizer function to keep this service
|
|
13
|
+
* decoupled from LLM routing.
|
|
14
|
+
*/
|
|
15
|
+
async captureSession(sessionId, userId, llmSummarizer) {
|
|
16
|
+
const session = await this.chatService.getSession(sessionId);
|
|
17
|
+
if (!session)
|
|
18
|
+
throw new Error("Session not found");
|
|
19
|
+
if (session.graphCaptured)
|
|
20
|
+
throw new Error("Session already captured");
|
|
21
|
+
const messages = await this.chatService.getMessages(sessionId);
|
|
22
|
+
if (messages.length === 0)
|
|
23
|
+
throw new Error("No messages to capture");
|
|
24
|
+
// Format conversation as a readable transcript using PII-stripped content
|
|
25
|
+
const transcript = messages
|
|
26
|
+
.map((m) => {
|
|
27
|
+
const role = m.role === "user" ? "User" : "Assistant";
|
|
28
|
+
const text = m.contentClean ?? m.content;
|
|
29
|
+
return `${role}: ${text}`;
|
|
30
|
+
})
|
|
31
|
+
.join("\n\n");
|
|
32
|
+
// Generate summary via caller-provided LLM function
|
|
33
|
+
const summary = await llmSummarizer(transcript);
|
|
34
|
+
// Create a graph node for the captured conversation
|
|
35
|
+
const title = session.title ?? "Untitled conversation";
|
|
36
|
+
const node = await this.nodeService.create({
|
|
37
|
+
type: "note",
|
|
38
|
+
title: `Chat: ${title}`,
|
|
39
|
+
content: summary,
|
|
40
|
+
metadata: {
|
|
41
|
+
capturedFromSession: sessionId,
|
|
42
|
+
capturedAt: new Date().toISOString(),
|
|
43
|
+
},
|
|
44
|
+
createdBy: userId,
|
|
45
|
+
});
|
|
46
|
+
// Collect unique context node IDs across all messages
|
|
47
|
+
const contextNodeIds = new Set();
|
|
48
|
+
for (const m of messages) {
|
|
49
|
+
if (m.contextNodeIds && Array.isArray(m.contextNodeIds)) {
|
|
50
|
+
for (const id of m.contextNodeIds) {
|
|
51
|
+
contextNodeIds.add(id);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Create relates-to edges from the capture node to each context node
|
|
56
|
+
for (const targetId of contextNodeIds) {
|
|
57
|
+
try {
|
|
58
|
+
await this.edgeService.create({
|
|
59
|
+
sourceNodeId: node.id,
|
|
60
|
+
targetNodeId: targetId,
|
|
61
|
+
relationshipType: "relates-to",
|
|
62
|
+
createdBy: userId,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Skip edges that fail (e.g. target node deleted)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Mark the session as captured
|
|
70
|
+
await this.chatService.updateSession(sessionId, { graphCaptured: true });
|
|
71
|
+
return { nodeId: node.id };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=chat-capture-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-capture-service.js","sourceRoot":"","sources":["../../src/services/chat-capture-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ContextService } from "./context-service.js";
|
|
2
|
+
import type { ChatService } from "./chat-service.js";
|
|
3
|
+
export interface ChatContextOptions {
|
|
4
|
+
query: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
workspaceId?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ChatContextPackage {
|
|
10
|
+
systemPrompt: string;
|
|
11
|
+
contextNodeIds: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Composes the system prompt for chat messages by assembling:
|
|
15
|
+
* 1. Org-level guidelines (always-applied system instructions)
|
|
16
|
+
* 2. Conversation history (from the session)
|
|
17
|
+
* 3. RAG context from the knowledge graph
|
|
18
|
+
* 4. Priority document content
|
|
19
|
+
*
|
|
20
|
+
* Token budget allocation (configurable):
|
|
21
|
+
* - Guidelines: 2K tokens
|
|
22
|
+
* - History: 8K tokens
|
|
23
|
+
* - RAG: 4K tokens
|
|
24
|
+
* - Priority docs: 2K tokens
|
|
25
|
+
*/
|
|
26
|
+
export declare class ChatContextService {
|
|
27
|
+
private contextService;
|
|
28
|
+
private chatService;
|
|
29
|
+
private db;
|
|
30
|
+
constructor(contextService: ContextService, chatService: ChatService, db: import("@prisma/client").PrismaClient);
|
|
31
|
+
assemble(options: ChatContextOptions): Promise<ChatContextPackage>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=chat-context-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-context-service.d.ts","sourceRoot":"","sources":["../../src/services/chat-context-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAcD;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,EAAE;gBAFF,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,EACxB,EAAE,EAAE,OAAO,gBAAgB,EAAE,YAAY;IAG7C,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;CA2FzE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composes the system prompt for chat messages by assembling:
|
|
3
|
+
* 1. Org-level guidelines (always-applied system instructions)
|
|
4
|
+
* 2. Conversation history (from the session)
|
|
5
|
+
* 3. RAG context from the knowledge graph
|
|
6
|
+
* 4. Priority document content
|
|
7
|
+
*
|
|
8
|
+
* Token budget allocation (configurable):
|
|
9
|
+
* - Guidelines: 2K tokens
|
|
10
|
+
* - History: 8K tokens
|
|
11
|
+
* - RAG: 4K tokens
|
|
12
|
+
* - Priority docs: 2K tokens
|
|
13
|
+
*/
|
|
14
|
+
export class ChatContextService {
|
|
15
|
+
contextService;
|
|
16
|
+
chatService;
|
|
17
|
+
db;
|
|
18
|
+
constructor(contextService, chatService, db) {
|
|
19
|
+
this.contextService = contextService;
|
|
20
|
+
this.chatService = chatService;
|
|
21
|
+
this.db = db;
|
|
22
|
+
}
|
|
23
|
+
async assemble(options) {
|
|
24
|
+
const parts = [];
|
|
25
|
+
const contextNodeIds = [];
|
|
26
|
+
// 1. Org guidelines — always-applied system instructions
|
|
27
|
+
try {
|
|
28
|
+
const guidelines = await this.db.orgChatGuideline.findMany({
|
|
29
|
+
where: { enabled: true },
|
|
30
|
+
orderBy: { priority: "desc" },
|
|
31
|
+
});
|
|
32
|
+
if (guidelines.length > 0) {
|
|
33
|
+
parts.push("## Organization Guidelines\n");
|
|
34
|
+
for (const g of guidelines) {
|
|
35
|
+
parts.push(`### ${g.title}\n${g.content}\n`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Guidelines table may not exist yet — continue without
|
|
41
|
+
}
|
|
42
|
+
// 2. Conversation history
|
|
43
|
+
try {
|
|
44
|
+
const messages = await this.chatService.getMessages(options.sessionId, { limit: 50 });
|
|
45
|
+
if (messages.length > 0) {
|
|
46
|
+
parts.push("## Conversation History\n");
|
|
47
|
+
for (const msg of messages) {
|
|
48
|
+
const role = msg.role === "user" ? "User" : "Assistant";
|
|
49
|
+
// Use PII-stripped content for context if available
|
|
50
|
+
const content = msg.contentClean ?? msg.content;
|
|
51
|
+
parts.push(`${role}: ${content}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Session may not have messages yet
|
|
57
|
+
}
|
|
58
|
+
// 3. RAG context from the knowledge graph
|
|
59
|
+
try {
|
|
60
|
+
const contextPackage = await this.contextService.assemble({
|
|
61
|
+
query: options.query,
|
|
62
|
+
maxNodes: 10,
|
|
63
|
+
maxDepth: 2,
|
|
64
|
+
workspace: options.workspaceId,
|
|
65
|
+
});
|
|
66
|
+
if (contextPackage.nodes.length > 0) {
|
|
67
|
+
parts.push("## Relevant Knowledge\n");
|
|
68
|
+
for (const node of contextPackage.nodes) {
|
|
69
|
+
parts.push(`### ${node.title} (${node.type})\n${node.content}\n`);
|
|
70
|
+
contextNodeIds.push(node.id);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Context service may fail — continue without RAG
|
|
76
|
+
}
|
|
77
|
+
// 4. Priority documents
|
|
78
|
+
try {
|
|
79
|
+
const priorityDocs = await this.db.orgPriorityDocument.findMany({
|
|
80
|
+
orderBy: { boostWeight: "desc" },
|
|
81
|
+
take: 5,
|
|
82
|
+
});
|
|
83
|
+
if (priorityDocs.length > 0) {
|
|
84
|
+
// Fetch the actual node content for priority docs
|
|
85
|
+
const nodeIds = priorityDocs.map((d) => d.nodeId);
|
|
86
|
+
const nodes = await this.db.node.findMany({
|
|
87
|
+
where: { id: { in: nodeIds } },
|
|
88
|
+
select: { id: true, title: true, content: true, type: true },
|
|
89
|
+
});
|
|
90
|
+
if (nodes.length > 0) {
|
|
91
|
+
parts.push("## Priority Documents\n");
|
|
92
|
+
for (const node of nodes) {
|
|
93
|
+
parts.push(`### ${node.title} (${node.type})\n${node.content}\n`);
|
|
94
|
+
if (!contextNodeIds.includes(node.id)) {
|
|
95
|
+
contextNodeIds.push(node.id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Priority docs may not exist
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
systemPrompt: parts.join("\n"),
|
|
106
|
+
contextNodeIds,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=chat-context-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-context-service.js","sourceRoot":"","sources":["../../src/services/chat-context-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { PrismaClient } from "@prisma/client";
|
|
2
|
+
import type { TenantContext } from "../db/tenant.js";
|
|
3
|
+
export interface ChatSessionRecord {
|
|
4
|
+
id: string;
|
|
5
|
+
organizationId: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
title: string | null;
|
|
8
|
+
privacy: string;
|
|
9
|
+
status: string;
|
|
10
|
+
workspaceId: string | null;
|
|
11
|
+
graphCaptured: boolean;
|
|
12
|
+
createdAt: Date;
|
|
13
|
+
updatedAt: Date;
|
|
14
|
+
}
|
|
15
|
+
export interface ChatMessageRecord {
|
|
16
|
+
id: string;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
organizationId: string;
|
|
19
|
+
role: string;
|
|
20
|
+
content: string;
|
|
21
|
+
contentClean: string | null;
|
|
22
|
+
model: string | null;
|
|
23
|
+
providerId: string | null;
|
|
24
|
+
tokensIn: number | null;
|
|
25
|
+
tokensOut: number | null;
|
|
26
|
+
costCents: number | null;
|
|
27
|
+
durationMs: number | null;
|
|
28
|
+
piiDetected: boolean;
|
|
29
|
+
piiReport: unknown;
|
|
30
|
+
contextNodeIds: string[];
|
|
31
|
+
documentIds: string[];
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
}
|
|
34
|
+
export interface CreateSessionInput {
|
|
35
|
+
userId: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
privacy?: string;
|
|
38
|
+
workspaceId?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface CreateMessageInput {
|
|
41
|
+
sessionId: string;
|
|
42
|
+
role: string;
|
|
43
|
+
content: string;
|
|
44
|
+
contentClean?: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
providerId?: string;
|
|
47
|
+
tokensIn?: number;
|
|
48
|
+
tokensOut?: number;
|
|
49
|
+
costCents?: number;
|
|
50
|
+
durationMs?: number;
|
|
51
|
+
piiDetected?: boolean;
|
|
52
|
+
piiReport?: unknown;
|
|
53
|
+
contextNodeIds?: string[];
|
|
54
|
+
documentIds?: string[];
|
|
55
|
+
}
|
|
56
|
+
export interface ListSessionsOptions {
|
|
57
|
+
userId: string;
|
|
58
|
+
includeShared?: boolean;
|
|
59
|
+
status?: string;
|
|
60
|
+
limit?: number;
|
|
61
|
+
offset?: number;
|
|
62
|
+
}
|
|
63
|
+
export declare class ChatService {
|
|
64
|
+
private db;
|
|
65
|
+
private tenantCtx;
|
|
66
|
+
constructor(db: PrismaClient, tenantCtx: TenantContext);
|
|
67
|
+
createSession(input: CreateSessionInput): Promise<ChatSessionRecord>;
|
|
68
|
+
getSession(id: string): Promise<ChatSessionRecord | null>;
|
|
69
|
+
listSessions(options: ListSessionsOptions): Promise<ChatSessionRecord[]>;
|
|
70
|
+
updateSession(id: string, patch: {
|
|
71
|
+
title?: string;
|
|
72
|
+
privacy?: string;
|
|
73
|
+
status?: string;
|
|
74
|
+
graphCaptured?: boolean;
|
|
75
|
+
}): Promise<ChatSessionRecord>;
|
|
76
|
+
addMessage(input: CreateMessageInput): Promise<ChatMessageRecord>;
|
|
77
|
+
getMessages(sessionId: string, options?: {
|
|
78
|
+
limit?: number;
|
|
79
|
+
offset?: number;
|
|
80
|
+
}): Promise<ChatMessageRecord[]>;
|
|
81
|
+
getMessage(id: string): Promise<ChatMessageRecord | null>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=chat-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-service.d.ts","sourceRoot":"","sources":["../../src/services/chat-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export class ChatService {
|
|
2
|
+
db;
|
|
3
|
+
tenantCtx;
|
|
4
|
+
constructor(db, tenantCtx) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
this.tenantCtx = tenantCtx;
|
|
7
|
+
}
|
|
8
|
+
async createSession(input) {
|
|
9
|
+
const session = await this.db.chatSession.create({
|
|
10
|
+
data: {
|
|
11
|
+
userId: input.userId,
|
|
12
|
+
title: input.title ?? null,
|
|
13
|
+
privacy: input.privacy ?? "shared",
|
|
14
|
+
workspaceId: input.workspaceId ?? null,
|
|
15
|
+
organizationId: this.tenantCtx.organizationId,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
return session;
|
|
19
|
+
}
|
|
20
|
+
async getSession(id) {
|
|
21
|
+
const session = await this.db.chatSession.findUnique({
|
|
22
|
+
where: { id },
|
|
23
|
+
});
|
|
24
|
+
return session;
|
|
25
|
+
}
|
|
26
|
+
async listSessions(options) {
|
|
27
|
+
const where = {
|
|
28
|
+
status: options.status ?? "active",
|
|
29
|
+
};
|
|
30
|
+
if (options.includeShared) {
|
|
31
|
+
where.OR = [
|
|
32
|
+
{ userId: options.userId },
|
|
33
|
+
{ privacy: "shared" },
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
where.userId = options.userId;
|
|
38
|
+
}
|
|
39
|
+
const sessions = await this.db.chatSession.findMany({
|
|
40
|
+
where,
|
|
41
|
+
orderBy: { updatedAt: "desc" },
|
|
42
|
+
take: options.limit ?? 50,
|
|
43
|
+
skip: options.offset ?? 0,
|
|
44
|
+
});
|
|
45
|
+
return sessions;
|
|
46
|
+
}
|
|
47
|
+
async updateSession(id, patch) {
|
|
48
|
+
const session = await this.db.chatSession.update({
|
|
49
|
+
where: { id },
|
|
50
|
+
data: {
|
|
51
|
+
...(patch.title !== undefined && { title: patch.title }),
|
|
52
|
+
...(patch.privacy !== undefined && { privacy: patch.privacy }),
|
|
53
|
+
...(patch.status !== undefined && { status: patch.status }),
|
|
54
|
+
...(patch.graphCaptured !== undefined && { graphCaptured: patch.graphCaptured }),
|
|
55
|
+
updatedAt: new Date(),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return session;
|
|
59
|
+
}
|
|
60
|
+
async addMessage(input) {
|
|
61
|
+
const message = await this.db.chatMessage.create({
|
|
62
|
+
data: {
|
|
63
|
+
sessionId: input.sessionId,
|
|
64
|
+
organizationId: this.tenantCtx.organizationId,
|
|
65
|
+
role: input.role,
|
|
66
|
+
content: input.content,
|
|
67
|
+
contentClean: input.contentClean ?? null,
|
|
68
|
+
model: input.model ?? null,
|
|
69
|
+
providerId: input.providerId ?? null,
|
|
70
|
+
tokensIn: input.tokensIn ?? null,
|
|
71
|
+
tokensOut: input.tokensOut ?? null,
|
|
72
|
+
costCents: input.costCents ?? null,
|
|
73
|
+
durationMs: input.durationMs ?? null,
|
|
74
|
+
piiDetected: input.piiDetected ?? false,
|
|
75
|
+
piiReport: input.piiReport ?? undefined,
|
|
76
|
+
contextNodeIds: input.contextNodeIds ?? [],
|
|
77
|
+
documentIds: input.documentIds ?? [],
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
// Touch the session's updatedAt
|
|
81
|
+
await this.db.chatSession.update({
|
|
82
|
+
where: { id: input.sessionId },
|
|
83
|
+
data: { updatedAt: new Date() },
|
|
84
|
+
});
|
|
85
|
+
return message;
|
|
86
|
+
}
|
|
87
|
+
async getMessages(sessionId, options) {
|
|
88
|
+
const messages = await this.db.chatMessage.findMany({
|
|
89
|
+
where: { sessionId },
|
|
90
|
+
orderBy: { createdAt: "asc" },
|
|
91
|
+
take: options?.limit ?? 200,
|
|
92
|
+
skip: options?.offset ?? 0,
|
|
93
|
+
});
|
|
94
|
+
return messages;
|
|
95
|
+
}
|
|
96
|
+
async getMessage(id) {
|
|
97
|
+
const message = await this.db.chatMessage.findUnique({
|
|
98
|
+
where: { id },
|
|
99
|
+
});
|
|
100
|
+
return message;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=chat-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-service.js","sourceRoot":"","sources":["../../src/services/chat-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UsageService } from "./usage-service.js";
|
|
2
|
+
export interface ChatMessageUsageInput {
|
|
3
|
+
organizationId: string;
|
|
4
|
+
tokensIn: number;
|
|
5
|
+
tokensOut: number;
|
|
6
|
+
costCents: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ChatUsageSummary {
|
|
9
|
+
totalMessages: number;
|
|
10
|
+
totalTokensIn: number;
|
|
11
|
+
totalTokensOut: number;
|
|
12
|
+
totalCostCents: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extends UsageService with chat-specific metrics. Uses the existing
|
|
16
|
+
* incrementMetric() pattern from UsageService to track:
|
|
17
|
+
* - chat_messages: number of messages sent
|
|
18
|
+
* - chat_tokens_in: input tokens consumed
|
|
19
|
+
* - chat_tokens_out: output tokens consumed
|
|
20
|
+
* - chat_cost_cents: cost in integer cents
|
|
21
|
+
*/
|
|
22
|
+
export declare class ChatUsageService {
|
|
23
|
+
private usageService;
|
|
24
|
+
private db;
|
|
25
|
+
constructor(usageService: UsageService, db: import("@prisma/client").PrismaClient);
|
|
26
|
+
recordMessageUsage(input: ChatMessageUsageInput): Promise<void>;
|
|
27
|
+
getUserUsage(organizationId: string, userId: string, period?: {
|
|
28
|
+
start: Date;
|
|
29
|
+
end: Date;
|
|
30
|
+
}): Promise<ChatUsageSummary>;
|
|
31
|
+
getOrgUsage(organizationId: string, period?: {
|
|
32
|
+
start: Date;
|
|
33
|
+
end: Date;
|
|
34
|
+
}): Promise<ChatUsageSummary>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=chat-usage-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-usage-service.d.ts","sourceRoot":"","sources":["../../src/services/chat-usage-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,EAAE;gBADF,YAAY,EAAE,YAAY,EAC1B,EAAE,EAAE,OAAO,gBAAgB,EAAE,YAAY;IAG7C,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D,YAAY,CAChB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,GAAG,EAAE,IAAI,CAAA;KAAE,GAClC,OAAO,CAAC,gBAAgB,CAAC;IAqCtB,WAAW,CACf,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,IAAI,CAAC;QAAC,GAAG,EAAE,IAAI,CAAA;KAAE,GAClC,OAAO,CAAC,gBAAgB,CAAC;CAgC7B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extends UsageService with chat-specific metrics. Uses the existing
|
|
3
|
+
* incrementMetric() pattern from UsageService to track:
|
|
4
|
+
* - chat_messages: number of messages sent
|
|
5
|
+
* - chat_tokens_in: input tokens consumed
|
|
6
|
+
* - chat_tokens_out: output tokens consumed
|
|
7
|
+
* - chat_cost_cents: cost in integer cents
|
|
8
|
+
*/
|
|
9
|
+
export class ChatUsageService {
|
|
10
|
+
usageService;
|
|
11
|
+
db;
|
|
12
|
+
constructor(usageService, db) {
|
|
13
|
+
this.usageService = usageService;
|
|
14
|
+
this.db = db;
|
|
15
|
+
}
|
|
16
|
+
async recordMessageUsage(input) {
|
|
17
|
+
await Promise.all([
|
|
18
|
+
this.usageService.incrementApiCalls(input.organizationId, 1),
|
|
19
|
+
// We track chat-specific metrics via the generic usage_records table
|
|
20
|
+
// using the same incrementMetric pattern. These are separate from
|
|
21
|
+
// the general api_calls counter.
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
async getUserUsage(organizationId, userId, period) {
|
|
25
|
+
const where = {
|
|
26
|
+
organizationId,
|
|
27
|
+
session: { userId },
|
|
28
|
+
};
|
|
29
|
+
if (period) {
|
|
30
|
+
where.createdAt = {
|
|
31
|
+
gte: period.start,
|
|
32
|
+
lte: period.end,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Default to current month
|
|
37
|
+
const now = new Date();
|
|
38
|
+
where.createdAt = {
|
|
39
|
+
gte: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const result = await this.db.chatMessage.aggregate({
|
|
43
|
+
where,
|
|
44
|
+
_count: { id: true },
|
|
45
|
+
_sum: {
|
|
46
|
+
tokensIn: true,
|
|
47
|
+
tokensOut: true,
|
|
48
|
+
costCents: true,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
totalMessages: result._count.id,
|
|
53
|
+
totalTokensIn: result._sum.tokensIn ?? 0,
|
|
54
|
+
totalTokensOut: result._sum.tokensOut ?? 0,
|
|
55
|
+
totalCostCents: result._sum.costCents ?? 0,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async getOrgUsage(organizationId, period) {
|
|
59
|
+
const where = { organizationId };
|
|
60
|
+
if (period) {
|
|
61
|
+
where.createdAt = {
|
|
62
|
+
gte: period.start,
|
|
63
|
+
lte: period.end,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const now = new Date();
|
|
68
|
+
where.createdAt = {
|
|
69
|
+
gte: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const result = await this.db.chatMessage.aggregate({
|
|
73
|
+
where,
|
|
74
|
+
_count: { id: true },
|
|
75
|
+
_sum: {
|
|
76
|
+
tokensIn: true,
|
|
77
|
+
tokensOut: true,
|
|
78
|
+
costCents: true,
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
totalMessages: result._count.id,
|
|
83
|
+
totalTokensIn: result._sum.tokensIn ?? 0,
|
|
84
|
+
totalTokensOut: result._sum.tokensOut ?? 0,
|
|
85
|
+
totalCostCents: result._sum.costCents ?? 0,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=chat-usage-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-usage-service.js","sourceRoot":"","sources":["../../src/services/chat-usage-service.ts"],"names":[],"mappings":"AAgBA;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAgB;IAEjB;IACA;IAFV,YACU,YAA0B,EAC1B,EAAyC;QADzC,iBAAY,GAAZ,YAAY,CAAc;QAC1B,OAAE,GAAF,EAAE,CAAuC;IAChD,CAAC;IAEJ,KAAK,CAAC,kBAAkB,CAAC,KAA4B;QACnD,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;YAC5D,qEAAqE;YACrE,kEAAkE;YAClE,iCAAiC;SAClC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,cAAsB,EACtB,MAAc,EACd,MAAmC;QAEnC,MAAM,KAAK,GAAQ;YACjB,cAAc;YACd,OAAO,EAAE,EAAE,MAAM,EAAE;SACpB,CAAC;QAEF,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,SAAS,GAAG;gBAChB,GAAG,EAAE,MAAM,CAAC,KAAK;gBACjB,GAAG,EAAE,MAAM,CAAC,GAAG;aAChB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,SAAS,GAAG;gBAChB,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;aACpE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC;YACjD,KAAK;YACL,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;YACpB,IAAI,EAAE;gBACJ,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,OAAO;YACL,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE;YAC/B,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC;YACxC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC;YAC1C,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC;SAC3C,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CACf,cAAsB,EACtB,MAAmC;QAEnC,MAAM,KAAK,GAAQ,EAAE,cAAc,EAAE,CAAC;QAEtC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,SAAS,GAAG;gBAChB,GAAG,EAAE,MAAM,CAAC,KAAK;gBACjB,GAAG,EAAE,MAAM,CAAC,GAAG;aAChB,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,SAAS,GAAG;gBAChB,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;aACpE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC;YACjD,KAAK;YACL,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;YACpB,IAAI,EAAE;gBACJ,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,IAAI;gBACf,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAC;QAEH,OAAO;YACL,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE;YAC/B,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC;YACxC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC;YAC1C,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { PrismaClient, OrgContentPolicy } from "@prisma/client";
|
|
2
|
+
import type { TenantContext } from "../db/tenant.js";
|
|
3
|
+
export interface CreatePolicyInput {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
category: string;
|
|
7
|
+
keywords: string[];
|
|
8
|
+
action: "block" | "warn";
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
priority?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface UpdatePolicyInput {
|
|
13
|
+
name?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
keywords?: string[];
|
|
17
|
+
action?: "block" | "warn";
|
|
18
|
+
enabled?: boolean;
|
|
19
|
+
priority?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface PolicyViolation {
|
|
22
|
+
policyId: string;
|
|
23
|
+
policyName: string;
|
|
24
|
+
category: string;
|
|
25
|
+
action: "block" | "warn";
|
|
26
|
+
matchedKeyword: string;
|
|
27
|
+
}
|
|
28
|
+
export interface PolicyEvaluation {
|
|
29
|
+
allowed: boolean;
|
|
30
|
+
violations: PolicyViolation[];
|
|
31
|
+
}
|
|
32
|
+
export interface LogViolationInput {
|
|
33
|
+
policyId: string;
|
|
34
|
+
policyName: string;
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
userId: string;
|
|
37
|
+
action: string;
|
|
38
|
+
matchedKeyword: string;
|
|
39
|
+
}
|
|
40
|
+
export declare class ContentPolicyService {
|
|
41
|
+
private db;
|
|
42
|
+
private tenantCtx?;
|
|
43
|
+
constructor(db: PrismaClient, tenantCtx?: TenantContext | undefined);
|
|
44
|
+
list(): Promise<OrgContentPolicy[]>;
|
|
45
|
+
get(id: string): Promise<OrgContentPolicy | null>;
|
|
46
|
+
create(input: CreatePolicyInput): Promise<OrgContentPolicy>;
|
|
47
|
+
update(id: string, input: UpdatePolicyInput): Promise<OrgContentPolicy>;
|
|
48
|
+
delete(id: string): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Evaluate content against all enabled policies.
|
|
51
|
+
* Returns whether the content is allowed and any violations found.
|
|
52
|
+
*/
|
|
53
|
+
evaluate(content: string): Promise<PolicyEvaluation>;
|
|
54
|
+
logViolation(input: LogViolationInput): Promise<void>;
|
|
55
|
+
listLogs(options?: {
|
|
56
|
+
limit?: number;
|
|
57
|
+
offset?: number;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
id: string;
|
|
60
|
+
createdAt: Date;
|
|
61
|
+
organizationId: string;
|
|
62
|
+
userId: string;
|
|
63
|
+
sessionId: string | null;
|
|
64
|
+
action: string;
|
|
65
|
+
policyId: string;
|
|
66
|
+
policyName: string;
|
|
67
|
+
matchedKeyword: string;
|
|
68
|
+
userOverride: boolean;
|
|
69
|
+
}[]>;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=content-policy-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-policy-service.d.ts","sourceRoot":"","sources":["../../src/services/content-policy-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,SAAS,CAAC;gBADV,EAAE,EAAE,YAAY,EAChB,SAAS,CAAC,EAAE,aAAa,YAAA;IAG7B,IAAI,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAMnC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAIjD,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAe3D,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgBvE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C;;;OAGG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgCpD,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrD,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;CAO7D"}
|