@apart-tech/intelligence-core 1.17.3 → 1.19.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.
Files changed (47) hide show
  1. package/dist/auth/ability.d.ts +1 -1
  2. package/dist/auth/ability.d.ts.map +1 -1
  3. package/dist/auth/ability.js +19 -0
  4. package/dist/auth/ability.js.map +1 -1
  5. package/dist/auth/ability.test.js +58 -4
  6. package/dist/auth/ability.test.js.map +1 -1
  7. package/dist/db/tenant.d.ts.map +1 -1
  8. package/dist/db/tenant.js +10 -0
  9. package/dist/db/tenant.js.map +1 -1
  10. package/dist/index.d.ts +13 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/services/__tests__/agent-instruction-service.test.d.ts +2 -0
  15. package/dist/services/__tests__/agent-instruction-service.test.d.ts.map +1 -0
  16. package/dist/services/__tests__/agent-instruction-service.test.js +408 -0
  17. package/dist/services/__tests__/agent-instruction-service.test.js.map +1 -0
  18. package/dist/services/agent-instruction-service.d.ts +82 -0
  19. package/dist/services/agent-instruction-service.d.ts.map +1 -0
  20. package/dist/services/agent-instruction-service.js +249 -0
  21. package/dist/services/agent-instruction-service.js.map +1 -0
  22. package/dist/services/agent-run-service.d.ts +61 -0
  23. package/dist/services/agent-run-service.d.ts.map +1 -1
  24. package/dist/services/agent-run-service.js +72 -0
  25. package/dist/services/agent-run-service.js.map +1 -1
  26. package/dist/services/chat-context-service.d.ts +33 -0
  27. package/dist/services/chat-context-service.d.ts.map +1 -0
  28. package/dist/services/chat-context-service.js +110 -0
  29. package/dist/services/chat-context-service.js.map +1 -0
  30. package/dist/services/chat-service.d.ts +83 -0
  31. package/dist/services/chat-service.d.ts.map +1 -0
  32. package/dist/services/chat-service.js +103 -0
  33. package/dist/services/chat-service.js.map +1 -0
  34. package/dist/services/chat-usage-service.d.ts +36 -0
  35. package/dist/services/chat-usage-service.d.ts.map +1 -0
  36. package/dist/services/chat-usage-service.js +89 -0
  37. package/dist/services/chat-usage-service.js.map +1 -0
  38. package/dist/services/llm-router-service.d.ts +29 -0
  39. package/dist/services/llm-router-service.d.ts.map +1 -0
  40. package/dist/services/llm-router-service.js +70 -0
  41. package/dist/services/llm-router-service.js.map +1 -0
  42. package/dist/services/org-llm-provider-service.d.ts +47 -0
  43. package/dist/services/org-llm-provider-service.d.ts.map +1 -0
  44. package/dist/services/org-llm-provider-service.js +126 -0
  45. package/dist/services/org-llm-provider-service.js.map +1 -0
  46. package/package.json +1 -1
  47. package/prisma/schema.prisma +317 -162
@@ -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 ?? "private",
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":"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"}
@@ -0,0 +1,29 @@
1
+ import type { OrgLlmProviderService } from "./org-llm-provider-service.js";
2
+ export interface RoutingCriteria {
3
+ preferredModel?: string;
4
+ preferredProvider?: string;
5
+ dataResidency?: string;
6
+ }
7
+ export interface RoutingDecision {
8
+ provider: string;
9
+ model: string;
10
+ apiKey: string;
11
+ baseUrl: string | null;
12
+ providerId: string;
13
+ }
14
+ export declare class LlmRouterService {
15
+ private providerService;
16
+ constructor(providerService: OrgLlmProviderService);
17
+ /**
18
+ * Route to the best available LLM provider/model based on criteria.
19
+ *
20
+ * Logic:
21
+ * 1. If preferredModel + preferredProvider specified and available → use it
22
+ * 2. If preferredModel specified → find first enabled provider with that model
23
+ * 3. Otherwise pick highest-priority enabled provider
24
+ * 4. Respect data residency constraints
25
+ */
26
+ route(organizationId: string, criteria?: RoutingCriteria): Promise<RoutingDecision | null>;
27
+ private resolveDecision;
28
+ }
29
+ //# sourceMappingURL=llm-router-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-router-service.d.ts","sourceRoot":"","sources":["../../src/services/llm-router-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAyB,MAAM,+BAA+B,CAAC;AAElG,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,gBAAgB;IACf,OAAO,CAAC,eAAe;gBAAf,eAAe,EAAE,qBAAqB;IAE1D;;;;;;;;OAQG;IACG,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;YAoDtF,eAAe;CAgB9B"}
@@ -0,0 +1,70 @@
1
+ export class LlmRouterService {
2
+ providerService;
3
+ constructor(providerService) {
4
+ this.providerService = providerService;
5
+ }
6
+ /**
7
+ * Route to the best available LLM provider/model based on criteria.
8
+ *
9
+ * Logic:
10
+ * 1. If preferredModel + preferredProvider specified and available → use it
11
+ * 2. If preferredModel specified → find first enabled provider with that model
12
+ * 3. Otherwise pick highest-priority enabled provider
13
+ * 4. Respect data residency constraints
14
+ */
15
+ async route(organizationId, criteria = {}) {
16
+ const providers = await this.providerService.list(organizationId);
17
+ const enabledProviders = providers.filter((p) => p.enabled);
18
+ if (enabledProviders.length === 0)
19
+ return null;
20
+ // Filter by data residency
21
+ const residencyFiltered = criteria.dataResidency
22
+ ? enabledProviders.filter((p) => p.dataResidency === "any" || p.dataResidency === criteria.dataResidency)
23
+ : enabledProviders;
24
+ if (residencyFiltered.length === 0)
25
+ return null;
26
+ // If preferred provider + model specified
27
+ if (criteria.preferredProvider && criteria.preferredModel) {
28
+ const match = residencyFiltered.find((p) => p.provider === criteria.preferredProvider && p.models.includes(criteria.preferredModel));
29
+ if (match) {
30
+ return this.resolveDecision(organizationId, match.provider, criteria.preferredModel);
31
+ }
32
+ }
33
+ // If preferred model specified — find first provider that has it
34
+ if (criteria.preferredModel) {
35
+ const match = residencyFiltered.find((p) => p.models.includes(criteria.preferredModel));
36
+ if (match) {
37
+ return this.resolveDecision(organizationId, match.provider, criteria.preferredModel);
38
+ }
39
+ }
40
+ // If preferred provider specified — use its default model
41
+ if (criteria.preferredProvider) {
42
+ const match = residencyFiltered.find((p) => p.provider === criteria.preferredProvider);
43
+ if (match) {
44
+ const model = match.defaultModel ?? match.models[0];
45
+ if (model) {
46
+ return this.resolveDecision(organizationId, match.provider, model);
47
+ }
48
+ }
49
+ }
50
+ // Fall back to highest priority provider's default model
51
+ const best = residencyFiltered[0]; // already sorted by priority desc
52
+ const model = best.defaultModel ?? best.models[0];
53
+ if (!model)
54
+ return null;
55
+ return this.resolveDecision(organizationId, best.provider, model);
56
+ }
57
+ async resolveDecision(organizationId, provider, model) {
58
+ const withKey = await this.providerService.getWithKey(organizationId, provider);
59
+ if (!withKey)
60
+ return null;
61
+ return {
62
+ provider: withKey.provider,
63
+ model,
64
+ apiKey: withKey.apiKey,
65
+ baseUrl: withKey.baseUrl,
66
+ providerId: withKey.id,
67
+ };
68
+ }
69
+ }
70
+ //# sourceMappingURL=llm-router-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-router-service.js","sourceRoot":"","sources":["../../src/services/llm-router-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { PrismaClient } from "@prisma/client";
2
+ export type LlmProviderName = "openai" | "anthropic" | "google" | "mistral" | "ollama";
3
+ export interface OrgLlmProviderRecord {
4
+ id: string;
5
+ provider: string;
6
+ displayName: string;
7
+ baseUrl: string | null;
8
+ models: string[];
9
+ defaultModel: string | null;
10
+ dataResidency: string;
11
+ enabled: boolean;
12
+ priority: number;
13
+ maxTokensPerMin: number | null;
14
+ createdAt: Date;
15
+ updatedAt: Date;
16
+ }
17
+ export interface OrgLlmProviderWithKey extends OrgLlmProviderRecord {
18
+ apiKey: string;
19
+ }
20
+ export interface SetOrgLlmProviderInput {
21
+ provider: string;
22
+ displayName: string;
23
+ apiKey: string;
24
+ baseUrl?: string;
25
+ models: string[];
26
+ defaultModel?: string;
27
+ dataResidency?: string;
28
+ enabled?: boolean;
29
+ priority?: number;
30
+ maxTokensPerMin?: number;
31
+ }
32
+ export declare class OrgLlmProviderService {
33
+ private db;
34
+ constructor(db: PrismaClient);
35
+ set(organizationId: string, input: SetOrgLlmProviderInput): Promise<OrgLlmProviderRecord>;
36
+ get(organizationId: string, provider: string): Promise<OrgLlmProviderRecord | null>;
37
+ getWithKey(organizationId: string, provider: string): Promise<OrgLlmProviderWithKey | null>;
38
+ list(organizationId: string): Promise<OrgLlmProviderRecord[]>;
39
+ delete(organizationId: string, provider: string): Promise<boolean>;
40
+ listAvailableModels(organizationId: string): Promise<{
41
+ provider: string;
42
+ models: string[];
43
+ defaultModel: string | null;
44
+ }[]>;
45
+ private toRecord;
46
+ }
47
+ //# sourceMappingURL=org-llm-provider-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org-llm-provider-service.d.ts","sourceRoot":"","sources":["../../src/services/org-llm-provider-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAYnD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvF,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,qBAAqB;IACpB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE9B,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAwCzF,GAAG,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAYnF,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAiB3F,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAQ7D,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBlE,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IASjI,OAAO,CAAC,QAAQ;CA6BjB"}
@@ -0,0 +1,126 @@
1
+ import { encryptAesGcm, decryptAesGcm } from "../lib/crypto.js";
2
+ import { getAgentKeySecret } from "../lib/encryption-keys.js";
3
+ function encrypt(plaintext) {
4
+ return encryptAesGcm(plaintext, getAgentKeySecret());
5
+ }
6
+ function decrypt(encoded) {
7
+ return decryptAesGcm(encoded, getAgentKeySecret());
8
+ }
9
+ export class OrgLlmProviderService {
10
+ db;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async set(organizationId, input) {
15
+ const encryptedKey = encrypt(input.apiKey);
16
+ const record = await this.db.orgLlmProvider.upsert({
17
+ where: {
18
+ organizationId_provider: {
19
+ organizationId,
20
+ provider: input.provider,
21
+ },
22
+ },
23
+ create: {
24
+ organizationId,
25
+ provider: input.provider,
26
+ displayName: input.displayName,
27
+ encryptedApiKey: encryptedKey,
28
+ baseUrl: input.baseUrl ?? null,
29
+ models: input.models,
30
+ defaultModel: input.defaultModel ?? null,
31
+ dataResidency: input.dataResidency ?? "any",
32
+ enabled: input.enabled ?? true,
33
+ priority: input.priority ?? 0,
34
+ maxTokensPerMin: input.maxTokensPerMin ?? null,
35
+ },
36
+ update: {
37
+ displayName: input.displayName,
38
+ encryptedApiKey: encryptedKey,
39
+ baseUrl: input.baseUrl ?? null,
40
+ models: input.models,
41
+ defaultModel: input.defaultModel ?? undefined,
42
+ dataResidency: input.dataResidency ?? undefined,
43
+ enabled: input.enabled ?? undefined,
44
+ priority: input.priority ?? undefined,
45
+ maxTokensPerMin: input.maxTokensPerMin ?? undefined,
46
+ updatedAt: new Date(),
47
+ },
48
+ });
49
+ return this.toRecord(record);
50
+ }
51
+ async get(organizationId, provider) {
52
+ const record = await this.db.orgLlmProvider.findUnique({
53
+ where: {
54
+ organizationId_provider: {
55
+ organizationId,
56
+ provider,
57
+ },
58
+ },
59
+ });
60
+ return record ? this.toRecord(record) : null;
61
+ }
62
+ async getWithKey(organizationId, provider) {
63
+ const record = await this.db.orgLlmProvider.findUnique({
64
+ where: {
65
+ organizationId_provider: {
66
+ organizationId,
67
+ provider,
68
+ },
69
+ },
70
+ });
71
+ if (!record)
72
+ return null;
73
+ return {
74
+ ...this.toRecord(record),
75
+ apiKey: decrypt(record.encryptedApiKey),
76
+ };
77
+ }
78
+ async list(organizationId) {
79
+ const records = await this.db.orgLlmProvider.findMany({
80
+ where: { organizationId },
81
+ orderBy: { priority: "desc" },
82
+ });
83
+ return records.map((r) => this.toRecord(r));
84
+ }
85
+ async delete(organizationId, provider) {
86
+ try {
87
+ await this.db.orgLlmProvider.delete({
88
+ where: {
89
+ organizationId_provider: {
90
+ organizationId,
91
+ provider,
92
+ },
93
+ },
94
+ });
95
+ return true;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ async listAvailableModels(organizationId) {
102
+ const records = await this.db.orgLlmProvider.findMany({
103
+ where: { organizationId, enabled: true },
104
+ orderBy: { priority: "desc" },
105
+ select: { provider: true, models: true, defaultModel: true },
106
+ });
107
+ return records;
108
+ }
109
+ toRecord(row) {
110
+ return {
111
+ id: row.id,
112
+ provider: row.provider,
113
+ displayName: row.displayName,
114
+ baseUrl: row.baseUrl,
115
+ models: row.models,
116
+ defaultModel: row.defaultModel,
117
+ dataResidency: row.dataResidency,
118
+ enabled: row.enabled,
119
+ priority: row.priority,
120
+ maxTokensPerMin: row.maxTokensPerMin,
121
+ createdAt: row.createdAt,
122
+ updatedAt: row.updatedAt,
123
+ };
124
+ }
125
+ }
126
+ //# sourceMappingURL=org-llm-provider-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org-llm-provider-service.js","sourceRoot":"","sources":["../../src/services/org-llm-provider-service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apart-tech/intelligence-core",
3
- "version": "1.17.3",
3
+ "version": "1.19.0",
4
4
  "description": "Core library: database, services, and providers for Apart Intelligence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",