@carlonicora/nestjs-neo4jsonapi 1.62.7 → 1.63.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/agents/agents.modules.d.ts.map +1 -1
- package/dist/agents/agents.modules.js +3 -0
- package/dist/agents/agents.modules.js.map +1 -1
- package/dist/agents/chatbot/chatbot.module.d.ts +3 -0
- package/dist/agents/chatbot/chatbot.module.d.ts.map +1 -0
- package/dist/agents/chatbot/chatbot.module.js +65 -0
- package/dist/agents/chatbot/chatbot.module.js.map +1 -0
- package/dist/agents/chatbot/interfaces/chatbot.response.interface.d.ts +25 -0
- package/dist/agents/chatbot/interfaces/chatbot.response.interface.d.ts.map +1 -0
- package/dist/agents/chatbot/interfaces/chatbot.response.interface.js +3 -0
- package/dist/agents/chatbot/interfaces/chatbot.response.interface.js.map +1 -0
- package/dist/agents/chatbot/interfaces/graph.catalog.interface.d.ts +50 -0
- package/dist/agents/chatbot/interfaces/graph.catalog.interface.d.ts.map +1 -0
- package/dist/agents/chatbot/interfaces/graph.catalog.interface.js +3 -0
- package/dist/agents/chatbot/interfaces/graph.catalog.interface.js.map +1 -0
- package/dist/agents/chatbot/prompts/chatbot.system.prompt.d.ts +3 -0
- package/dist/agents/chatbot/prompts/chatbot.system.prompt.d.ts.map +1 -0
- package/dist/agents/chatbot/prompts/chatbot.system.prompt.js +60 -0
- package/dist/agents/chatbot/prompts/chatbot.system.prompt.js.map +1 -0
- package/dist/agents/chatbot/repositories/user-modules.repository.d.ts +28 -0
- package/dist/agents/chatbot/repositories/user-modules.repository.d.ts.map +1 -0
- package/dist/agents/chatbot/repositories/user-modules.repository.js +76 -0
- package/dist/agents/chatbot/repositories/user-modules.repository.js.map +1 -0
- package/dist/agents/chatbot/services/chatbot.index.manager.d.ts +17 -0
- package/dist/agents/chatbot/services/chatbot.index.manager.d.ts.map +1 -0
- package/dist/agents/chatbot/services/chatbot.index.manager.js +84 -0
- package/dist/agents/chatbot/services/chatbot.index.manager.js.map +1 -0
- package/dist/agents/chatbot/services/chatbot.search.service.d.ts +46 -0
- package/dist/agents/chatbot/services/chatbot.search.service.d.ts.map +1 -0
- package/dist/agents/chatbot/services/chatbot.search.service.js +148 -0
- package/dist/agents/chatbot/services/chatbot.search.service.js.map +1 -0
- package/dist/agents/chatbot/services/chatbot.service.d.ts +36 -0
- package/dist/agents/chatbot/services/chatbot.service.d.ts.map +1 -0
- package/dist/agents/chatbot/services/chatbot.service.js +220 -0
- package/dist/agents/chatbot/services/chatbot.service.js.map +1 -0
- package/dist/agents/chatbot/services/descriptor.source.d.ts +18 -0
- package/dist/agents/chatbot/services/descriptor.source.d.ts.map +1 -0
- package/dist/agents/chatbot/services/descriptor.source.js +41 -0
- package/dist/agents/chatbot/services/descriptor.source.js.map +1 -0
- package/dist/agents/chatbot/services/field-formatting.d.ts +18 -0
- package/dist/agents/chatbot/services/field-formatting.d.ts.map +1 -0
- package/dist/agents/chatbot/services/field-formatting.js +43 -0
- package/dist/agents/chatbot/services/field-formatting.js.map +1 -0
- package/dist/agents/chatbot/services/graph.catalog.service.d.ts +60 -0
- package/dist/agents/chatbot/services/graph.catalog.service.d.ts.map +1 -0
- package/dist/agents/chatbot/services/graph.catalog.service.js +217 -0
- package/dist/agents/chatbot/services/graph.catalog.service.js.map +1 -0
- package/dist/agents/chatbot/services/humanize-tool.d.ts +9 -0
- package/dist/agents/chatbot/services/humanize-tool.d.ts.map +1 -0
- package/dist/agents/chatbot/services/humanize-tool.js +35 -0
- package/dist/agents/chatbot/services/humanize-tool.js.map +1 -0
- package/dist/agents/chatbot/tools/describe-entity.tool.d.ts +14 -0
- package/dist/agents/chatbot/tools/describe-entity.tool.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/describe-entity.tool.js +63 -0
- package/dist/agents/chatbot/tools/describe-entity.tool.js.map +1 -0
- package/dist/agents/chatbot/tools/read-entity.tool.d.ts +16 -0
- package/dist/agents/chatbot/tools/read-entity.tool.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/read-entity.tool.js +102 -0
- package/dist/agents/chatbot/tools/read-entity.tool.js.map +1 -0
- package/dist/agents/chatbot/tools/resolve-entity.tool.d.ts +16 -0
- package/dist/agents/chatbot/tools/resolve-entity.tool.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/resolve-entity.tool.js +48 -0
- package/dist/agents/chatbot/tools/resolve-entity.tool.js.map +1 -0
- package/dist/agents/chatbot/tools/search-entities.tool.d.ts +20 -0
- package/dist/agents/chatbot/tools/search-entities.tool.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/search-entities.tool.js +122 -0
- package/dist/agents/chatbot/tools/search-entities.tool.js.map +1 -0
- package/dist/agents/chatbot/tools/tool.factory.d.ts +29 -0
- package/dist/agents/chatbot/tools/tool.factory.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/tool.factory.js +72 -0
- package/dist/agents/chatbot/tools/tool.factory.js.map +1 -0
- package/dist/agents/chatbot/tools/traverse.tool.d.ts +58 -0
- package/dist/agents/chatbot/tools/traverse.tool.d.ts.map +1 -0
- package/dist/agents/chatbot/tools/traverse.tool.js +212 -0
- package/dist/agents/chatbot/tools/traverse.tool.js.map +1 -0
- package/dist/agents/index.d.ts +9 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +17 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/common/helpers/define-entity.d.ts.map +1 -1
- package/dist/common/helpers/define-entity.js +5 -1
- package/dist/common/helpers/define-entity.js.map +1 -1
- package/dist/common/interfaces/datamodel.interface.d.ts +10 -0
- package/dist/common/interfaces/datamodel.interface.d.ts.map +1 -1
- package/dist/common/interfaces/datamodel.interface.js.map +1 -1
- package/dist/common/interfaces/entity.descriptor.interface.d.ts +1 -1
- package/dist/common/interfaces/entity.descriptor.interface.d.ts.map +1 -1
- package/dist/common/interfaces/entity.descriptor.interface.js.map +1 -1
- package/dist/common/interfaces/entity.schema.interface.d.ts +48 -0
- package/dist/common/interfaces/entity.schema.interface.d.ts.map +1 -1
- package/dist/common/registries/entity.service.registry.d.ts +13 -0
- package/dist/common/registries/entity.service.registry.d.ts.map +1 -0
- package/dist/common/registries/entity.service.registry.js +52 -0
- package/dist/common/registries/entity.service.registry.js.map +1 -0
- package/dist/common/registries/index.d.ts +1 -0
- package/dist/common/registries/index.d.ts.map +1 -1
- package/dist/common/registries/index.js +1 -0
- package/dist/common/registries/index.js.map +1 -1
- package/dist/core/core.module.d.ts.map +1 -1
- package/dist/core/core.module.js +6 -2
- package/dist/core/core.module.js.map +1 -1
- package/dist/core/llm/services/llm.service.d.ts.map +1 -1
- package/dist/core/llm/services/llm.service.js +8 -0
- package/dist/core/llm/services/llm.service.js.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.repository.d.ts +48 -1
- package/dist/core/neo4j/abstracts/abstract.repository.d.ts.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.repository.js +147 -9
- package/dist/core/neo4j/abstracts/abstract.repository.js.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.service.d.ts +47 -0
- package/dist/core/neo4j/abstracts/abstract.service.d.ts.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.service.js +57 -0
- package/dist/core/neo4j/abstracts/abstract.service.js.map +1 -1
- package/dist/core/neo4j/factories/entity.factory.d.ts.map +1 -1
- package/dist/core/neo4j/factories/entity.factory.js +27 -6
- package/dist/core/neo4j/factories/entity.factory.js.map +1 -1
- package/dist/core/neo4j/helpers/build-filter-clauses.d.ts +11 -0
- package/dist/core/neo4j/helpers/build-filter-clauses.d.ts.map +1 -0
- package/dist/core/neo4j/helpers/build-filter-clauses.js +69 -0
- package/dist/core/neo4j/helpers/build-filter-clauses.js.map +1 -0
- package/dist/core/neo4j/helpers/build-order-by.d.ts +6 -0
- package/dist/core/neo4j/helpers/build-order-by.d.ts.map +1 -0
- package/dist/core/neo4j/helpers/build-order-by.js +20 -0
- package/dist/core/neo4j/helpers/build-order-by.js.map +1 -0
- package/dist/core/neo4j/index.d.ts +1 -0
- package/dist/core/neo4j/index.d.ts.map +1 -1
- package/dist/core/neo4j/index.js +2 -0
- package/dist/core/neo4j/index.js.map +1 -1
- package/dist/core/neo4j/types/filter.criterion.d.ts +20 -0
- package/dist/core/neo4j/types/filter.criterion.d.ts.map +1 -0
- package/dist/core/neo4j/types/filter.criterion.js +3 -0
- package/dist/core/neo4j/types/filter.criterion.js.map +1 -0
- package/dist/core/neo4j/types/index.d.ts +2 -0
- package/dist/core/neo4j/types/index.d.ts.map +1 -0
- package/dist/core/neo4j/types/index.js +3 -0
- package/dist/core/neo4j/types/index.js.map +1 -0
- package/dist/foundations/assistant/assistant.module.d.ts +5 -0
- package/dist/foundations/assistant/assistant.module.d.ts.map +1 -0
- package/dist/foundations/assistant/assistant.module.js +32 -0
- package/dist/foundations/assistant/assistant.module.js.map +1 -0
- package/dist/foundations/assistant/controllers/assistant.controller.d.ts +67 -0
- package/dist/foundations/assistant/controllers/assistant.controller.d.ts.map +1 -0
- package/dist/foundations/assistant/controllers/assistant.controller.js +226 -0
- package/dist/foundations/assistant/controllers/assistant.controller.js.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-append.dto.d.ts +11 -0
- package/dist/foundations/assistant/dtos/assistant-append.dto.d.ts.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-append.dto.js +44 -0
- package/dist/foundations/assistant/dtos/assistant-append.dto.js.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-patch.dto.d.ts +12 -0
- package/dist/foundations/assistant/dtos/assistant-patch.dto.d.ts.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-patch.dto.js +52 -0
- package/dist/foundations/assistant/dtos/assistant-patch.dto.js.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-post.dto.d.ts +12 -0
- package/dist/foundations/assistant/dtos/assistant-post.dto.d.ts.map +1 -0
- package/dist/foundations/assistant/dtos/assistant-post.dto.js +51 -0
- package/dist/foundations/assistant/dtos/assistant-post.dto.js.map +1 -0
- package/dist/foundations/assistant/entities/assistant.d.ts +48 -0
- package/dist/foundations/assistant/entities/assistant.d.ts.map +1 -0
- package/dist/foundations/assistant/entities/assistant.js +44 -0
- package/dist/foundations/assistant/entities/assistant.js.map +1 -0
- package/dist/foundations/assistant/entities/assistant.meta.d.ts +3 -0
- package/dist/foundations/assistant/entities/assistant.meta.d.ts.map +1 -0
- package/dist/foundations/assistant/entities/assistant.meta.js +10 -0
- package/dist/foundations/assistant/entities/assistant.meta.js.map +1 -0
- package/dist/foundations/assistant/index.d.ts +7 -0
- package/dist/foundations/assistant/index.d.ts.map +1 -0
- package/dist/foundations/assistant/index.js +12 -0
- package/dist/foundations/assistant/index.js.map +1 -0
- package/dist/foundations/assistant/repositories/assistant.repository.d.ts +50 -0
- package/dist/foundations/assistant/repositories/assistant.repository.d.ts.map +1 -0
- package/dist/foundations/assistant/repositories/assistant.repository.js +65 -0
- package/dist/foundations/assistant/repositories/assistant.repository.js.map +1 -0
- package/dist/foundations/assistant/services/assistant.service.d.ts +113 -0
- package/dist/foundations/assistant/services/assistant.service.d.ts.map +1 -0
- package/dist/foundations/assistant/services/assistant.service.js +395 -0
- package/dist/foundations/assistant/services/assistant.service.js.map +1 -0
- package/dist/foundations/assistant-message/assistant-message.module.d.ts +6 -0
- package/dist/foundations/assistant-message/assistant-message.module.d.ts.map +1 -0
- package/dist/foundations/assistant-message/assistant-message.module.js +36 -0
- package/dist/foundations/assistant-message/assistant-message.module.js.map +1 -0
- package/dist/foundations/assistant-message/controllers/assistant-message.controller.d.ts +16 -0
- package/dist/foundations/assistant-message/controllers/assistant-message.controller.d.ts.map +1 -0
- package/dist/foundations/assistant-message/controllers/assistant-message.controller.js +84 -0
- package/dist/foundations/assistant-message/controllers/assistant-message.controller.js.map +1 -0
- package/dist/foundations/assistant-message/dtos/assistant-message.dto.d.ts +11 -0
- package/dist/foundations/assistant-message/dtos/assistant-message.dto.d.ts.map +1 -0
- package/dist/foundations/assistant-message/dtos/assistant-message.dto.js +45 -0
- package/dist/foundations/assistant-message/dtos/assistant-message.dto.js.map +1 -0
- package/dist/foundations/assistant-message/entities/assistant-message.d.ts +49 -0
- package/dist/foundations/assistant-message/entities/assistant-message.d.ts.map +1 -0
- package/dist/foundations/assistant-message/entities/assistant-message.js +52 -0
- package/dist/foundations/assistant-message/entities/assistant-message.js.map +1 -0
- package/dist/foundations/assistant-message/entities/assistant-message.meta.d.ts +3 -0
- package/dist/foundations/assistant-message/entities/assistant-message.meta.d.ts.map +1 -0
- package/dist/foundations/assistant-message/entities/assistant-message.meta.js +10 -0
- package/dist/foundations/assistant-message/entities/assistant-message.meta.js.map +1 -0
- package/dist/foundations/assistant-message/index.d.ts +8 -0
- package/dist/foundations/assistant-message/index.d.ts.map +1 -0
- package/dist/foundations/assistant-message/index.js +24 -0
- package/dist/foundations/assistant-message/index.js.map +1 -0
- package/dist/foundations/assistant-message/repositories/assistant-message.repository.d.ts +70 -0
- package/dist/foundations/assistant-message/repositories/assistant-message.repository.d.ts.map +1 -0
- package/dist/foundations/assistant-message/repositories/assistant-message.repository.js +119 -0
- package/dist/foundations/assistant-message/repositories/assistant-message.repository.js.map +1 -0
- package/dist/foundations/assistant-message/services/assistant-message.service.d.ts +31 -0
- package/dist/foundations/assistant-message/services/assistant-message.service.d.ts.map +1 -0
- package/dist/foundations/assistant-message/services/assistant-message.service.js +32 -0
- package/dist/foundations/assistant-message/services/assistant-message.service.js.map +1 -0
- package/dist/foundations/foundations.modules.d.ts.map +1 -1
- package/dist/foundations/foundations.modules.js +2 -0
- package/dist/foundations/foundations.modules.js.map +1 -1
- package/dist/foundations/index.d.ts +2 -0
- package/dist/foundations/index.d.ts.map +1 -1
- package/dist/foundations/index.js +2 -0
- package/dist/foundations/index.js.map +1 -1
- package/dist/foundations/stripe/__tests__/mocks/stripe.mock.d.ts +62 -62
- package/package.json +1 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ClsService } from "nestjs-cls";
|
|
2
|
+
import { AbstractRepository } from "../../../core/neo4j/abstracts/abstract.repository";
|
|
3
|
+
import { Neo4jService } from "../../../core/neo4j/services/neo4j.service";
|
|
4
|
+
import { SecurityService } from "../../../core/security/services/security.service";
|
|
5
|
+
import { Assistant, AssistantDescriptor } from "../entities/assistant";
|
|
6
|
+
/**
|
|
7
|
+
* AssistantRepository
|
|
8
|
+
*
|
|
9
|
+
* Extends the standard company-scoped match with an additional owner check —
|
|
10
|
+
* a user can only see/modify assistants they created.
|
|
11
|
+
*
|
|
12
|
+
* The `$currentUserId` parameter is auto-injected into queryParams by
|
|
13
|
+
* `Neo4jService.initQuery()` (reads `clsService.get("userId")`), so the
|
|
14
|
+
* `buildUserHasAccess` override can reference `$currentUserId` directly.
|
|
15
|
+
*/
|
|
16
|
+
export declare class AssistantRepository extends AbstractRepository<Assistant, typeof AssistantDescriptor.relationships> {
|
|
17
|
+
protected readonly descriptor: import("../../..").EntityDescriptor<Assistant, {
|
|
18
|
+
owner: {
|
|
19
|
+
model: import("../../..").DataMeta;
|
|
20
|
+
direction: "out";
|
|
21
|
+
relationship: string;
|
|
22
|
+
cardinality: "one";
|
|
23
|
+
required: false;
|
|
24
|
+
dtoKey: string;
|
|
25
|
+
contextKey: string;
|
|
26
|
+
immutable: true;
|
|
27
|
+
};
|
|
28
|
+
messages: {
|
|
29
|
+
model: import("../../..").DataMeta;
|
|
30
|
+
direction: "out";
|
|
31
|
+
relationship: string;
|
|
32
|
+
cardinality: "many";
|
|
33
|
+
required: false;
|
|
34
|
+
dtoKey: string;
|
|
35
|
+
};
|
|
36
|
+
}>;
|
|
37
|
+
constructor(neo4j: Neo4jService, securityService: SecurityService, clsService: ClsService);
|
|
38
|
+
protected buildUserHasAccess(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Override delete to cascade through HAS_MESSAGE children so that
|
|
41
|
+
* `AssistantMessage` nodes (and their REFERENCES edges) are removed with
|
|
42
|
+
* the parent Assistant. DETACH DELETE drops every relationship incident to
|
|
43
|
+
* the deleted nodes — including outgoing REFERENCES edges — without
|
|
44
|
+
* affecting the referenced domain entities.
|
|
45
|
+
*/
|
|
46
|
+
delete(params: {
|
|
47
|
+
id: string;
|
|
48
|
+
}): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=assistant.repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant.repository.d.ts","sourceRoot":"","sources":["../../../../src/foundations/assistant/repositories/assistant.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mDAAmD,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,kDAAkD,CAAC;AACnF,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;;;;;;;;GASG;AACH,qBACa,mBAAoB,SAAQ,kBAAkB,CAAC,SAAS,EAAE,OAAO,mBAAmB,CAAC,aAAa,CAAC;IAC9G,SAAS,CAAC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;;;;;;OAAuB;gBAExC,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU;IAIzF,SAAS,CAAC,kBAAkB,IAAI,MAAM;IAStC;;;;;;OAMG;IACG,MAAM,CAAC,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAUpD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AssistantRepository = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const nestjs_cls_1 = require("nestjs-cls");
|
|
15
|
+
const abstract_repository_1 = require("../../../core/neo4j/abstracts/abstract.repository");
|
|
16
|
+
const neo4j_service_1 = require("../../../core/neo4j/services/neo4j.service");
|
|
17
|
+
const security_service_1 = require("../../../core/security/services/security.service");
|
|
18
|
+
const assistant_1 = require("../entities/assistant");
|
|
19
|
+
/**
|
|
20
|
+
* AssistantRepository
|
|
21
|
+
*
|
|
22
|
+
* Extends the standard company-scoped match with an additional owner check —
|
|
23
|
+
* a user can only see/modify assistants they created.
|
|
24
|
+
*
|
|
25
|
+
* The `$currentUserId` parameter is auto-injected into queryParams by
|
|
26
|
+
* `Neo4jService.initQuery()` (reads `clsService.get("userId")`), so the
|
|
27
|
+
* `buildUserHasAccess` override can reference `$currentUserId` directly.
|
|
28
|
+
*/
|
|
29
|
+
let AssistantRepository = class AssistantRepository extends abstract_repository_1.AbstractRepository {
|
|
30
|
+
constructor(neo4j, securityService, clsService) {
|
|
31
|
+
super(neo4j, securityService, clsService);
|
|
32
|
+
this.descriptor = assistant_1.AssistantDescriptor;
|
|
33
|
+
}
|
|
34
|
+
buildUserHasAccess() {
|
|
35
|
+
const { nodeName } = this.descriptor.model;
|
|
36
|
+
return `WITH ${nodeName}
|
|
37
|
+
WHERE EXISTS {
|
|
38
|
+
MATCH (${nodeName})-[:CREATED_BY]->(:User {id: $currentUserId})
|
|
39
|
+
}
|
|
40
|
+
WITH ${nodeName}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Override delete to cascade through HAS_MESSAGE children so that
|
|
44
|
+
* `AssistantMessage` nodes (and their REFERENCES edges) are removed with
|
|
45
|
+
* the parent Assistant. DETACH DELETE drops every relationship incident to
|
|
46
|
+
* the deleted nodes — including outgoing REFERENCES edges — without
|
|
47
|
+
* affecting the referenced domain entities.
|
|
48
|
+
*/
|
|
49
|
+
async delete(params) {
|
|
50
|
+
await this.neo4j.writeOne({
|
|
51
|
+
query: `
|
|
52
|
+
MATCH (a:Assistant {id: $id})
|
|
53
|
+
OPTIONAL MATCH (a)-[:HAS_MESSAGE]->(m:AssistantMessage)
|
|
54
|
+
DETACH DELETE a, m
|
|
55
|
+
`,
|
|
56
|
+
queryParams: { id: params.id },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
exports.AssistantRepository = AssistantRepository;
|
|
61
|
+
exports.AssistantRepository = AssistantRepository = __decorate([
|
|
62
|
+
(0, common_1.Injectable)(),
|
|
63
|
+
__metadata("design:paramtypes", [neo4j_service_1.Neo4jService, security_service_1.SecurityService, nestjs_cls_1.ClsService])
|
|
64
|
+
], AssistantRepository);
|
|
65
|
+
//# sourceMappingURL=assistant.repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant.repository.js","sourceRoot":"","sources":["../../../../src/foundations/assistant/repositories/assistant.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,2CAAwC;AACxC,2FAAuF;AACvF,8EAA0E;AAC1E,uFAAmF;AACnF,qDAAuE;AAEvE;;;;;;;;;GASG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,wCAAuE;IAG9G,YAAY,KAAmB,EAAE,eAAgC,EAAE,UAAsB;QACvF,KAAK,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;QAHzB,eAAU,GAAG,+BAAmB,CAAC;IAIpD,CAAC;IAES,kBAAkB;QAC1B,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAC3C,OAAO,QAAQ,QAAQ;;uBAEJ,QAAQ;;mBAEZ,QAAQ,EAAE,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,MAAsB;QACjC,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YACxB,KAAK,EAAE;;;;OAIN;YACD,WAAW,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;SAC/B,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAjCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAIQ,4BAAY,EAAmB,kCAAe,EAAc,uBAAU;GAH9E,mBAAmB,CAiC/B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ClsService } from "nestjs-cls";
|
|
2
|
+
import { ChatbotService } from "../../../agents/chatbot/services/chatbot.service";
|
|
3
|
+
import { GraphCatalogService } from "../../../agents/chatbot/services/graph.catalog.service";
|
|
4
|
+
import { UserModulesRepository } from "../../../agents/chatbot/repositories/user-modules.repository";
|
|
5
|
+
import { ChatbotToolCall } from "../../../agents/chatbot/interfaces/chatbot.response.interface";
|
|
6
|
+
import { EntityServiceRegistry } from "../../../common/registries/entity.service.registry";
|
|
7
|
+
import { JsonApiService } from "../../../core/jsonapi/services/jsonapi.service";
|
|
8
|
+
import { AbstractService } from "../../../core/neo4j/abstracts/abstract.service";
|
|
9
|
+
import { AssistantMessage } from "../../assistant-message/entities/assistant-message";
|
|
10
|
+
import { AssistantMessageRepository } from "../../assistant-message/repositories/assistant-message.repository";
|
|
11
|
+
import { AssistantMessageService } from "../../assistant-message/services/assistant-message.service";
|
|
12
|
+
import { Assistant, AssistantDescriptor } from "../entities/assistant";
|
|
13
|
+
import { AssistantRepository } from "../repositories/assistant.repository";
|
|
14
|
+
/**
|
|
15
|
+
* Maximum number of prior messages (turns) passed to the LLM on each turn.
|
|
16
|
+
* Keeps prompt size and cost bounded for long conversations.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MAX_MESSAGES_TO_LLM = 20;
|
|
19
|
+
/**
|
|
20
|
+
* AssistantService
|
|
21
|
+
*
|
|
22
|
+
* Wraps the stateless ChatbotService.run() in a stateful lifecycle. Extends
|
|
23
|
+
* AbstractService so standard CRUD (find / findById / patch / delete) is
|
|
24
|
+
* inherited and wired through the framework's JSON:API pipeline — only the
|
|
25
|
+
* agent-turn methods below are bespoke:
|
|
26
|
+
* - `createWithFirstMessage` — persists a brand-new assistant thread with the first turn.
|
|
27
|
+
* - `appendMessage` — appends a user turn + agent turn to an existing assistant thread.
|
|
28
|
+
*
|
|
29
|
+
* Messages are stored as first-class `AssistantMessage` nodes linked via
|
|
30
|
+
* `(Assistant)-[:HAS_MESSAGE]->(AssistantMessage)`. Per-turn `references` are
|
|
31
|
+
* materialised as `(AssistantMessage)-[:REFERENCES]->(entity)` edges (see
|
|
32
|
+
* AssistantMessageRepository.linkReferences).
|
|
33
|
+
*/
|
|
34
|
+
export declare class AssistantService extends AbstractService<Assistant, typeof AssistantDescriptor.relationships> {
|
|
35
|
+
private readonly userModuleIdsRepository;
|
|
36
|
+
private readonly chatbot;
|
|
37
|
+
private readonly assistantMessages;
|
|
38
|
+
private readonly assistantMessageRepo;
|
|
39
|
+
private readonly graphCatalog;
|
|
40
|
+
private readonly entityServices;
|
|
41
|
+
protected readonly descriptor: import("../../..").EntityDescriptor<Assistant, {
|
|
42
|
+
owner: {
|
|
43
|
+
model: import("../../..").DataMeta;
|
|
44
|
+
direction: "out";
|
|
45
|
+
relationship: string;
|
|
46
|
+
cardinality: "one";
|
|
47
|
+
required: false;
|
|
48
|
+
dtoKey: string;
|
|
49
|
+
contextKey: string;
|
|
50
|
+
immutable: true;
|
|
51
|
+
};
|
|
52
|
+
messages: {
|
|
53
|
+
model: import("../../..").DataMeta;
|
|
54
|
+
direction: "out";
|
|
55
|
+
relationship: string;
|
|
56
|
+
cardinality: "many";
|
|
57
|
+
required: false;
|
|
58
|
+
dtoKey: string;
|
|
59
|
+
};
|
|
60
|
+
}>;
|
|
61
|
+
private readonly assistantLogger;
|
|
62
|
+
constructor(jsonApiService: JsonApiService, assistantRepository: AssistantRepository, clsService: ClsService, userModuleIdsRepository: UserModulesRepository, chatbot: ChatbotService, assistantMessages: AssistantMessageService, assistantMessageRepo: AssistantMessageRepository, graphCatalog: GraphCatalogService, entityServices: EntityServiceRegistry);
|
|
63
|
+
createWithFirstMessage(params: {
|
|
64
|
+
companyId: string;
|
|
65
|
+
userId: string;
|
|
66
|
+
firstMessage: string;
|
|
67
|
+
title?: string;
|
|
68
|
+
}): Promise<{
|
|
69
|
+
assistant: Assistant;
|
|
70
|
+
userMessage: AssistantMessage;
|
|
71
|
+
assistantMessage: AssistantMessage;
|
|
72
|
+
toolCalls: ChatbotToolCall[];
|
|
73
|
+
}>;
|
|
74
|
+
appendMessage(params: {
|
|
75
|
+
assistantId: string;
|
|
76
|
+
companyId: string;
|
|
77
|
+
userId: string;
|
|
78
|
+
newMessage: string;
|
|
79
|
+
}): Promise<{
|
|
80
|
+
userMessage: AssistantMessage;
|
|
81
|
+
assistantMessage: AssistantMessage;
|
|
82
|
+
toolCalls: ChatbotToolCall[];
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Load the most recent N messages for an Assistant, ordered chronologically
|
|
86
|
+
* (position ASC). Used to build the LLM prompt without pulling full history.
|
|
87
|
+
*/
|
|
88
|
+
private loadRecentMessages;
|
|
89
|
+
/**
|
|
90
|
+
* Runs a single agent turn. Builds a message list of:
|
|
91
|
+
* [ optional reference-memory system message, ...prior messages, new user message ]
|
|
92
|
+
* and invokes the stateless chatbot. Returns the assistant reply metadata.
|
|
93
|
+
*/
|
|
94
|
+
private runAgentTurn;
|
|
95
|
+
/**
|
|
96
|
+
* Two-tier hydration:
|
|
97
|
+
* - Focus: full records re-read for every {type,id} referenced by the most
|
|
98
|
+
* recent assistant message.
|
|
99
|
+
* - Background: id + label stubs for references from earlier messages.
|
|
100
|
+
* Returns null when there is nothing to hydrate. On any unexpected error
|
|
101
|
+
* the whole builder returns null so a single bad Neo4j hiccup does not
|
|
102
|
+
* fail the chat turn.
|
|
103
|
+
*/
|
|
104
|
+
private buildHydrationMessage;
|
|
105
|
+
private loadFocusRecords;
|
|
106
|
+
private loadBackgroundStubs;
|
|
107
|
+
/**
|
|
108
|
+
* Auto-generate a title from the first user message: trim to 60 chars on a
|
|
109
|
+
* word boundary. Falls back to a hard 60-char cut if no suitable break exists.
|
|
110
|
+
*/
|
|
111
|
+
private autoTitle;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=assistant.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/assistant/services/assistant.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wDAAwD,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,8DAA8D,CAAC;AACrG,OAAO,EAAoB,eAAe,EAAE,MAAM,+DAA+D,CAAC;AAClH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;AAC3F,OAAO,EAAE,cAAc,EAAE,MAAM,gDAAgD,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAA8B,MAAM,oDAAoD,CAAC;AAElH,OAAO,EAAE,0BAA0B,EAAE,MAAM,mEAAmE,CAAC;AAC/G,OAAO,EAAE,uBAAuB,EAAE,MAAM,4DAA4D,CAAC;AACrG,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAiBtC;;;;;;;;;;;;;;GAcG;AACH,qBACa,gBAAiB,SAAQ,eAAe,CAAC,SAAS,EAAE,OAAO,mBAAmB,CAAC,aAAa,CAAC;IAQtG,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAZjC,SAAS,CAAC,QAAQ,CAAC,UAAU;;;;;;;;;;;;;;;;;;;OAAuB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;gBAGnE,cAAc,EAAE,cAAc,EAC9B,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,UAAU,EACL,uBAAuB,EAAE,qBAAqB,EAC9C,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,uBAAuB,EAC1C,oBAAoB,EAAE,0BAA0B,EAChD,YAAY,EAAE,mBAAmB,EACjC,cAAc,EAAE,qBAAqB;IAKlD,sBAAsB,CAAC,MAAM,EAAE;QACnC,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC;QACV,SAAS,EAAE,SAAS,CAAC;QACrB,WAAW,EAAE,gBAAgB,CAAC;QAC9B,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,SAAS,EAAE,eAAe,EAAE,CAAC;KAC9B,CAAC;IAgFI,aAAa,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QACnH,WAAW,EAAE,gBAAgB,CAAC;QAC9B,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,SAAS,EAAE,eAAe,EAAE,CAAC;KAC9B,CAAC;IA4EF;;;OAGG;YACW,kBAAkB;IAUhC;;;;OAIG;YACW,YAAY;IAuC1B;;;;;;;;OAQG;YACW,qBAAqB;YAmFrB,gBAAgB;YAwBhB,mBAAmB;IAuBjC;;;OAGG;IACH,OAAO,CAAC,SAAS;CAOlB"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var AssistantService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.AssistantService = exports.MAX_MESSAGES_TO_LLM = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const crypto_1 = require("crypto");
|
|
16
|
+
const nestjs_cls_1 = require("nestjs-cls");
|
|
17
|
+
const chatbot_service_1 = require("../../../agents/chatbot/services/chatbot.service");
|
|
18
|
+
const graph_catalog_service_1 = require("../../../agents/chatbot/services/graph.catalog.service");
|
|
19
|
+
const user_modules_repository_1 = require("../../../agents/chatbot/repositories/user-modules.repository");
|
|
20
|
+
const entity_service_registry_1 = require("../../../common/registries/entity.service.registry");
|
|
21
|
+
const jsonapi_service_1 = require("../../../core/jsonapi/services/jsonapi.service");
|
|
22
|
+
const abstract_service_1 = require("../../../core/neo4j/abstracts/abstract.service");
|
|
23
|
+
const assistant_message_1 = require("../../assistant-message/entities/assistant-message");
|
|
24
|
+
const assistant_message_meta_1 = require("../../assistant-message/entities/assistant-message.meta");
|
|
25
|
+
const assistant_message_repository_1 = require("../../assistant-message/repositories/assistant-message.repository");
|
|
26
|
+
const assistant_message_service_1 = require("../../assistant-message/services/assistant-message.service");
|
|
27
|
+
const assistant_1 = require("../entities/assistant");
|
|
28
|
+
const assistant_meta_1 = require("../entities/assistant.meta");
|
|
29
|
+
const assistant_repository_1 = require("../repositories/assistant.repository");
|
|
30
|
+
/**
|
|
31
|
+
* Maximum number of prior messages (turns) passed to the LLM on each turn.
|
|
32
|
+
* Keeps prompt size and cost bounded for long conversations.
|
|
33
|
+
*/
|
|
34
|
+
exports.MAX_MESSAGES_TO_LLM = 20;
|
|
35
|
+
/**
|
|
36
|
+
* AssistantService
|
|
37
|
+
*
|
|
38
|
+
* Wraps the stateless ChatbotService.run() in a stateful lifecycle. Extends
|
|
39
|
+
* AbstractService so standard CRUD (find / findById / patch / delete) is
|
|
40
|
+
* inherited and wired through the framework's JSON:API pipeline — only the
|
|
41
|
+
* agent-turn methods below are bespoke:
|
|
42
|
+
* - `createWithFirstMessage` — persists a brand-new assistant thread with the first turn.
|
|
43
|
+
* - `appendMessage` — appends a user turn + agent turn to an existing assistant thread.
|
|
44
|
+
*
|
|
45
|
+
* Messages are stored as first-class `AssistantMessage` nodes linked via
|
|
46
|
+
* `(Assistant)-[:HAS_MESSAGE]->(AssistantMessage)`. Per-turn `references` are
|
|
47
|
+
* materialised as `(AssistantMessage)-[:REFERENCES]->(entity)` edges (see
|
|
48
|
+
* AssistantMessageRepository.linkReferences).
|
|
49
|
+
*/
|
|
50
|
+
let AssistantService = AssistantService_1 = class AssistantService extends abstract_service_1.AbstractService {
|
|
51
|
+
constructor(jsonApiService, assistantRepository, clsService, userModuleIdsRepository, chatbot, assistantMessages, assistantMessageRepo, graphCatalog, entityServices) {
|
|
52
|
+
super(jsonApiService, assistantRepository, clsService, assistant_1.AssistantDescriptor.model);
|
|
53
|
+
this.userModuleIdsRepository = userModuleIdsRepository;
|
|
54
|
+
this.chatbot = chatbot;
|
|
55
|
+
this.assistantMessages = assistantMessages;
|
|
56
|
+
this.assistantMessageRepo = assistantMessageRepo;
|
|
57
|
+
this.graphCatalog = graphCatalog;
|
|
58
|
+
this.entityServices = entityServices;
|
|
59
|
+
this.descriptor = assistant_1.AssistantDescriptor;
|
|
60
|
+
this.assistantLogger = new common_1.Logger(AssistantService_1.name);
|
|
61
|
+
}
|
|
62
|
+
async createWithFirstMessage(params) {
|
|
63
|
+
const userModuleIds = await this.userModuleIdsRepository.findModuleIdsForUser(params.userId);
|
|
64
|
+
const title = params.title?.trim() || this.autoTitle(params.firstMessage);
|
|
65
|
+
const assistantId = (0, crypto_1.randomUUID)();
|
|
66
|
+
const userMessageId = (0, crypto_1.randomUUID)();
|
|
67
|
+
// 1. Create the Assistant (owner edge attached from CLS via contextKey).
|
|
68
|
+
await this.createFromDTO({
|
|
69
|
+
data: {
|
|
70
|
+
type: assistant_meta_1.assistantMeta.type,
|
|
71
|
+
id: assistantId,
|
|
72
|
+
attributes: { title },
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// 2. Create the first user message at position 0.
|
|
76
|
+
await this.assistantMessages.createFromDTO({
|
|
77
|
+
data: {
|
|
78
|
+
type: assistant_message_meta_1.assistantMessageMeta.type,
|
|
79
|
+
id: userMessageId,
|
|
80
|
+
attributes: {
|
|
81
|
+
role: "user",
|
|
82
|
+
content: params.firstMessage,
|
|
83
|
+
position: 0,
|
|
84
|
+
},
|
|
85
|
+
relationships: {
|
|
86
|
+
assistant: { data: { type: assistant_meta_1.assistantMeta.type, id: assistantId } },
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
const userMessage = await this.assistantMessageRepo.findById({ id: userMessageId });
|
|
91
|
+
// 3. Run the agent turn using the just-created user message as context.
|
|
92
|
+
const turn = await this.runAgentTurn({
|
|
93
|
+
companyId: params.companyId,
|
|
94
|
+
userId: params.userId,
|
|
95
|
+
userModuleIds,
|
|
96
|
+
priorMessages: [],
|
|
97
|
+
newUserMessage: { role: "user", content: params.firstMessage },
|
|
98
|
+
assistantId,
|
|
99
|
+
});
|
|
100
|
+
// 4. Create the assistant message at position 1 with denormalised references JSON.
|
|
101
|
+
const assistantMessageId = turn.id;
|
|
102
|
+
await this.assistantMessages.createFromDTO({
|
|
103
|
+
data: {
|
|
104
|
+
type: assistant_message_meta_1.assistantMessageMeta.type,
|
|
105
|
+
id: assistantMessageId,
|
|
106
|
+
attributes: {
|
|
107
|
+
role: "assistant",
|
|
108
|
+
content: turn.content,
|
|
109
|
+
position: 1,
|
|
110
|
+
suggestedQuestions: turn.suggestedQuestions,
|
|
111
|
+
inputTokens: turn.tokens.input,
|
|
112
|
+
outputTokens: turn.tokens.output,
|
|
113
|
+
},
|
|
114
|
+
relationships: {
|
|
115
|
+
assistant: { data: { type: assistant_meta_1.assistantMeta.type, id: assistantId } },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
// 5. Materialise REFERENCES edges (no-op when references is empty).
|
|
120
|
+
if (turn.references.length) {
|
|
121
|
+
await this.assistantMessageRepo.linkReferences({
|
|
122
|
+
messageId: assistantMessageId,
|
|
123
|
+
references: turn.references,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const assistantMessage = await this.assistantMessageRepo.findById({ id: assistantMessageId });
|
|
127
|
+
this.assistantLogger.log(`createWithFirstMessage: id=${assistantId} userId=${params.userId} companyId=${params.companyId} titleLength=${title.length}`);
|
|
128
|
+
const assistant = await this.repository.findById({ id: assistantId });
|
|
129
|
+
return { assistant, userMessage, assistantMessage, toolCalls: turn.toolCalls };
|
|
130
|
+
}
|
|
131
|
+
async appendMessage(params) {
|
|
132
|
+
// Verify ownership via the owner-RBAC-enforcing findById.
|
|
133
|
+
await this.repository.findById({ id: params.assistantId });
|
|
134
|
+
const userModuleIds = await this.userModuleIdsRepository.findModuleIdsForUser(params.userId);
|
|
135
|
+
// Load prior messages for agent context.
|
|
136
|
+
const priorMessages = await this.loadRecentMessages({
|
|
137
|
+
assistantId: params.assistantId,
|
|
138
|
+
limit: exports.MAX_MESSAGES_TO_LLM,
|
|
139
|
+
});
|
|
140
|
+
const nextPosition = await this.assistantMessageRepo.getNextPosition({
|
|
141
|
+
assistantId: params.assistantId,
|
|
142
|
+
});
|
|
143
|
+
const userMessageId = (0, crypto_1.randomUUID)();
|
|
144
|
+
await this.assistantMessages.createFromDTO({
|
|
145
|
+
data: {
|
|
146
|
+
type: assistant_message_meta_1.assistantMessageMeta.type,
|
|
147
|
+
id: userMessageId,
|
|
148
|
+
attributes: {
|
|
149
|
+
role: "user",
|
|
150
|
+
content: params.newMessage,
|
|
151
|
+
position: nextPosition,
|
|
152
|
+
},
|
|
153
|
+
relationships: {
|
|
154
|
+
assistant: { data: { type: assistant_meta_1.assistantMeta.type, id: params.assistantId } },
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
const userMessage = await this.assistantMessageRepo.findById({ id: userMessageId });
|
|
159
|
+
const turn = await this.runAgentTurn({
|
|
160
|
+
companyId: params.companyId,
|
|
161
|
+
userId: params.userId,
|
|
162
|
+
userModuleIds,
|
|
163
|
+
priorMessages,
|
|
164
|
+
newUserMessage: { role: "user", content: params.newMessage },
|
|
165
|
+
assistantId: params.assistantId,
|
|
166
|
+
});
|
|
167
|
+
const assistantMessageId = turn.id;
|
|
168
|
+
await this.assistantMessages.createFromDTO({
|
|
169
|
+
data: {
|
|
170
|
+
type: assistant_message_meta_1.assistantMessageMeta.type,
|
|
171
|
+
id: assistantMessageId,
|
|
172
|
+
attributes: {
|
|
173
|
+
role: "assistant",
|
|
174
|
+
content: turn.content,
|
|
175
|
+
position: nextPosition + 1,
|
|
176
|
+
suggestedQuestions: turn.suggestedQuestions,
|
|
177
|
+
inputTokens: turn.tokens.input,
|
|
178
|
+
outputTokens: turn.tokens.output,
|
|
179
|
+
},
|
|
180
|
+
relationships: {
|
|
181
|
+
assistant: { data: { type: assistant_meta_1.assistantMeta.type, id: params.assistantId } },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
if (turn.references.length) {
|
|
186
|
+
await this.assistantMessageRepo.linkReferences({
|
|
187
|
+
messageId: assistantMessageId,
|
|
188
|
+
references: turn.references,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const assistantMessage = await this.assistantMessageRepo.findById({ id: assistantMessageId });
|
|
192
|
+
this.assistantLogger.log(`appendMessage: id=${params.assistantId} userId=${params.userId} newPos=${nextPosition}-${nextPosition + 1}`);
|
|
193
|
+
return { userMessage, assistantMessage, toolCalls: turn.toolCalls };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Load the most recent N messages for an Assistant, ordered chronologically
|
|
197
|
+
* (position ASC). Used to build the LLM prompt without pulling full history.
|
|
198
|
+
*/
|
|
199
|
+
async loadRecentMessages(params) {
|
|
200
|
+
const all = await this.assistantMessageRepo.findByRelated({
|
|
201
|
+
relationship: assistant_message_1.AssistantMessageDescriptor.relationshipKeys.assistant,
|
|
202
|
+
id: params.assistantId,
|
|
203
|
+
cursor: { limit: params.limit },
|
|
204
|
+
orderBy: "position DESC",
|
|
205
|
+
});
|
|
206
|
+
return all.slice(0, params.limit).reverse();
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Runs a single agent turn. Builds a message list of:
|
|
210
|
+
* [ optional reference-memory system message, ...prior messages, new user message ]
|
|
211
|
+
* and invokes the stateless chatbot. Returns the assistant reply metadata.
|
|
212
|
+
*/
|
|
213
|
+
async runAgentTurn(params) {
|
|
214
|
+
const hydrationContent = await this.buildHydrationMessage(params.priorMessages, params.userModuleIds);
|
|
215
|
+
const trimmed = params.priorMessages.slice(-exports.MAX_MESSAGES_TO_LLM).map((m) => ({
|
|
216
|
+
role: m.role,
|
|
217
|
+
content: m.content,
|
|
218
|
+
}));
|
|
219
|
+
const messages = [
|
|
220
|
+
...(hydrationContent ? [{ role: "system", content: hydrationContent }] : []),
|
|
221
|
+
...trimmed,
|
|
222
|
+
{ role: params.newUserMessage.role, content: params.newUserMessage.content },
|
|
223
|
+
];
|
|
224
|
+
const response = await this.chatbot.run({
|
|
225
|
+
companyId: params.companyId,
|
|
226
|
+
userId: params.userId,
|
|
227
|
+
userModuleIds: params.userModuleIds,
|
|
228
|
+
messages,
|
|
229
|
+
assistantId: params.assistantId,
|
|
230
|
+
});
|
|
231
|
+
return {
|
|
232
|
+
id: (0, crypto_1.randomUUID)(),
|
|
233
|
+
role: "assistant",
|
|
234
|
+
content: response.answer,
|
|
235
|
+
createdAt: new Date().toISOString(),
|
|
236
|
+
references: response.references ?? [],
|
|
237
|
+
suggestedQuestions: response.suggestedQuestions ?? [],
|
|
238
|
+
tokens: response.tokens ?? { input: 0, output: 0 },
|
|
239
|
+
toolCalls: response.toolCalls ?? [],
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Two-tier hydration:
|
|
244
|
+
* - Focus: full records re-read for every {type,id} referenced by the most
|
|
245
|
+
* recent assistant message.
|
|
246
|
+
* - Background: id + label stubs for references from earlier messages.
|
|
247
|
+
* Returns null when there is nothing to hydrate. On any unexpected error
|
|
248
|
+
* the whole builder returns null so a single bad Neo4j hiccup does not
|
|
249
|
+
* fail the chat turn.
|
|
250
|
+
*/
|
|
251
|
+
async buildHydrationMessage(messages, userModuleIds) {
|
|
252
|
+
if (messages.length === 0)
|
|
253
|
+
return null;
|
|
254
|
+
try {
|
|
255
|
+
const pairs = await this.assistantMessageRepo.findReferencedTypeIdPairs({
|
|
256
|
+
messageIds: messages.map((m) => m.id),
|
|
257
|
+
});
|
|
258
|
+
if (pairs.length === 0)
|
|
259
|
+
return null;
|
|
260
|
+
// The most recent assistant message is the focus anchor.
|
|
261
|
+
const prevAssistantId = [...messages].reverse().find((m) => m.role === "assistant")?.id;
|
|
262
|
+
// Partition references into focus (from previous assistant message) and
|
|
263
|
+
// background (from any earlier message). Entity dedup on (type,id).
|
|
264
|
+
const focusKeys = new Set();
|
|
265
|
+
const backgroundKeys = new Set();
|
|
266
|
+
const focusRefs = [];
|
|
267
|
+
const backgroundRefs = [];
|
|
268
|
+
for (const p of pairs) {
|
|
269
|
+
const key = `${p.type}/${p.id}`;
|
|
270
|
+
if (prevAssistantId && p.messageId === prevAssistantId) {
|
|
271
|
+
if (!focusKeys.has(key)) {
|
|
272
|
+
focusKeys.add(key);
|
|
273
|
+
focusRefs.push({ type: p.type, id: p.id });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else if (!backgroundKeys.has(key)) {
|
|
277
|
+
backgroundKeys.add(key);
|
|
278
|
+
backgroundRefs.push({ type: p.type, id: p.id });
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Anything also in focus must not appear in background.
|
|
282
|
+
const backgroundOnly = backgroundRefs.filter((b) => !focusKeys.has(`${b.type}/${b.id}`));
|
|
283
|
+
// Size caps.
|
|
284
|
+
const FOCUS_CAP = 25;
|
|
285
|
+
const BACKGROUND_CAP = 100;
|
|
286
|
+
const focusCapped = focusRefs.slice(0, FOCUS_CAP);
|
|
287
|
+
if (focusRefs.length > FOCUS_CAP) {
|
|
288
|
+
this.assistantLogger.warn(`buildHydrationMessage: focus set capped at ${FOCUS_CAP} (had ${focusRefs.length})`);
|
|
289
|
+
}
|
|
290
|
+
const backgroundCapped = backgroundOnly.slice(0, BACKGROUND_CAP);
|
|
291
|
+
if (backgroundOnly.length > BACKGROUND_CAP) {
|
|
292
|
+
this.assistantLogger.warn(`buildHydrationMessage: background set capped at ${BACKGROUND_CAP} (had ${backgroundOnly.length})`);
|
|
293
|
+
}
|
|
294
|
+
// Load focus records (full) and background records (project to label).
|
|
295
|
+
const focusRecords = await this.loadFocusRecords(focusCapped, userModuleIds);
|
|
296
|
+
const backgroundStubs = await this.loadBackgroundStubs(backgroundCapped, userModuleIds);
|
|
297
|
+
if (focusRecords.length === 0 && backgroundStubs.length === 0)
|
|
298
|
+
return null;
|
|
299
|
+
const sections = ["## Entities already in this conversation", ""];
|
|
300
|
+
if (focusRecords.length > 0) {
|
|
301
|
+
sections.push("### Full records from the previous answer");
|
|
302
|
+
sections.push('These are the entities your previous answer was about. When the user\'s new question refers to any of them — by name or implicitly ("these", "them", "other orders", "their invoices") — use their id directly. Do not call resolve_entity for a name that matches one of these.');
|
|
303
|
+
sections.push("");
|
|
304
|
+
sections.push(JSON.stringify(focusRecords, null, 2));
|
|
305
|
+
sections.push("");
|
|
306
|
+
}
|
|
307
|
+
if (backgroundStubs.length > 0) {
|
|
308
|
+
sections.push("### Other entities mentioned earlier in this conversation");
|
|
309
|
+
sections.push("These have been referenced in earlier turns. Recognise them if the user names them, and call read_entity(type, id) if you need their fields again.");
|
|
310
|
+
sections.push("");
|
|
311
|
+
for (const s of backgroundStubs) {
|
|
312
|
+
sections.push(s.label ? `- ${s.type}/${s.id} — "${s.label}"` : `- ${s.type}/${s.id}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return sections.join("\n");
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
this.assistantLogger.error(`buildHydrationMessage failed — proceeding without hydration: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err.stack : undefined);
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async loadFocusRecords(refs, userModuleIds) {
|
|
323
|
+
const out = [];
|
|
324
|
+
for (const ref of refs) {
|
|
325
|
+
// Per-type module gate. getEntityDetail returns null when the type is
|
|
326
|
+
// not accessible to the current userModuleIds.
|
|
327
|
+
const detail = this.graphCatalog.getEntityDetail(ref.type, userModuleIds);
|
|
328
|
+
if (!detail)
|
|
329
|
+
continue;
|
|
330
|
+
const svc = this.entityServices.get(ref.type);
|
|
331
|
+
if (!svc)
|
|
332
|
+
continue;
|
|
333
|
+
try {
|
|
334
|
+
const record = await svc.findRecordById({ id: ref.id });
|
|
335
|
+
if (!record)
|
|
336
|
+
continue;
|
|
337
|
+
out.push({ ...record, type: ref.type });
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
// Deleted or RBAC-denied: drop silently.
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
async loadBackgroundStubs(refs, userModuleIds) {
|
|
347
|
+
const out = [];
|
|
348
|
+
for (const ref of refs) {
|
|
349
|
+
const detail = this.graphCatalog.getEntityDetail(ref.type, userModuleIds);
|
|
350
|
+
if (!detail)
|
|
351
|
+
continue;
|
|
352
|
+
const labelField = detail.textSearchFields?.[0];
|
|
353
|
+
const svc = this.entityServices.get(ref.type);
|
|
354
|
+
if (!svc)
|
|
355
|
+
continue;
|
|
356
|
+
try {
|
|
357
|
+
const record = await svc.findRecordById({ id: ref.id });
|
|
358
|
+
if (!record)
|
|
359
|
+
continue;
|
|
360
|
+
const label = labelField ? record[labelField] : undefined;
|
|
361
|
+
out.push({ type: ref.type, id: ref.id, ...(label ? { label } : {}) });
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return out;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Auto-generate a title from the first user message: trim to 60 chars on a
|
|
371
|
+
* word boundary. Falls back to a hard 60-char cut if no suitable break exists.
|
|
372
|
+
*/
|
|
373
|
+
autoTitle(firstMessage) {
|
|
374
|
+
const trimmed = firstMessage.trim();
|
|
375
|
+
if (trimmed.length <= 60)
|
|
376
|
+
return trimmed;
|
|
377
|
+
const at60 = trimmed.slice(0, 60);
|
|
378
|
+
const lastSpace = at60.lastIndexOf(" ");
|
|
379
|
+
return lastSpace > 30 ? at60.slice(0, lastSpace).trim() : at60.trim();
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
exports.AssistantService = AssistantService;
|
|
383
|
+
exports.AssistantService = AssistantService = AssistantService_1 = __decorate([
|
|
384
|
+
(0, common_1.Injectable)(),
|
|
385
|
+
__metadata("design:paramtypes", [jsonapi_service_1.JsonApiService,
|
|
386
|
+
assistant_repository_1.AssistantRepository,
|
|
387
|
+
nestjs_cls_1.ClsService,
|
|
388
|
+
user_modules_repository_1.UserModulesRepository,
|
|
389
|
+
chatbot_service_1.ChatbotService,
|
|
390
|
+
assistant_message_service_1.AssistantMessageService,
|
|
391
|
+
assistant_message_repository_1.AssistantMessageRepository,
|
|
392
|
+
graph_catalog_service_1.GraphCatalogService,
|
|
393
|
+
entity_service_registry_1.EntityServiceRegistry])
|
|
394
|
+
], AssistantService);
|
|
395
|
+
//# sourceMappingURL=assistant.service.js.map
|