@tstdl/base 0.93.123 → 0.93.126
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/ai/genkit/tests/multi-region.test.js +6 -6
- package/ai/index.d.ts +2 -6
- package/ai/index.js +2 -6
- package/ai/parser/index.d.ts +1 -0
- package/ai/parser/index.js +1 -0
- package/ai/parser/parser.d.ts +12 -0
- package/ai/parser/parser.js +28 -0
- package/ai/prompts/build.d.ts +21 -0
- package/ai/prompts/build.js +25 -0
- package/ai/prompts/index.d.ts +2 -0
- package/ai/prompts/index.js +2 -0
- package/ai/prompts/instructions-formatter.d.ts +9 -22
- package/ai/prompts/instructions-formatter.js +20 -7
- package/ai/prompts/instructions.js +1 -1
- package/ai/prompts/steering.d.ts +27 -0
- package/ai/prompts/steering.js +54 -0
- package/ai/tests/instructions-formatter.test.js +115 -0
- package/ai/tests/steering.test.js +37 -0
- package/application/application.d.ts +2 -1
- package/application/application.js +3 -0
- package/authentication/client/module.d.ts +1 -1
- package/authentication/client/module.js +4 -5
- package/authentication/tests/authentication-ancillary.service.test.js +1 -1
- package/authentication/tests/authentication.api-controller.test.js +3 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
- package/authentication/tests/authentication.client-service.test.js +1 -1
- package/authentication/tests/authentication.service.test.js +1 -1
- package/authentication/tests/subject.service.test.js +1 -1
- package/circuit-breaker/tests/circuit-breaker.test.js +1 -1
- package/document-management/api/document-management.api.d.ts +16 -16
- package/document-management/api/document-management.api.js +12 -12
- package/document-management/models/ai-configuration.d.ts +59 -0
- package/document-management/models/ai-configuration.js +1 -0
- package/document-management/models/document-assignment-scope.model.js +2 -4
- package/document-management/models/document-assignment-task.model.js +2 -4
- package/document-management/models/document-collection-assignment.model.js +2 -4
- package/document-management/models/document-collection.model.js +2 -3
- package/document-management/models/document-content.model.d.ts +6 -0
- package/document-management/models/document-content.model.js +32 -0
- package/document-management/models/document-property-value.model.js +1 -2
- package/document-management/models/document-request-collection-assignment.model.js +2 -4
- package/document-management/models/document-request.model.js +2 -4
- package/document-management/models/document-tag-assignment.model.js +2 -3
- package/document-management/models/document-validation-execution-related-document.model.js +2 -4
- package/document-management/models/document-validation-execution.model.js +2 -5
- package/document-management/models/document-workflow.model.d.ts +2 -1
- package/document-management/models/document-workflow.model.js +4 -5
- package/document-management/models/document.model.js +2 -3
- package/document-management/models/index.d.ts +2 -0
- package/document-management/models/index.js +2 -0
- package/document-management/server/api/document-management.api.d.ts +7 -7
- package/document-management/server/api/document-management.api.js +9 -9
- package/document-management/server/configure.d.ts +4 -1
- package/document-management/server/configure.js +9 -4
- package/document-management/server/drizzle/{0000_silly_chimera.sql → 0000_curious_nighthawk.sql} +8 -28
- package/document-management/server/drizzle/meta/0000_snapshot.json +14 -286
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/document-management/server/module.d.ts +2 -0
- package/document-management/server/module.js +1 -0
- package/document-management/server/schemas.d.ts +2 -1
- package/document-management/server/services/document-file.service.d.ts +6 -6
- package/document-management/server/services/document-file.service.js +7 -81
- package/document-management/server/services/document-management-ai-provider.service.d.ts +66 -0
- package/document-management/server/services/document-management-ai-provider.service.js +2 -0
- package/document-management/server/services/document-management-ai.service.d.ts +44 -7
- package/document-management/server/services/document-management-ai.service.js +332 -329
- package/document-management/server/services/document-validation.service.d.ts +1 -1
- package/document-management/server/services/document-workflow.service.d.ts +4 -3
- package/document-management/server/services/document-workflow.service.js +26 -9
- package/document-management/server/services/document.service.d.ts +7 -3
- package/document-management/server/services/document.service.js +13 -4
- package/document-management/server/services/index.d.ts +1 -0
- package/document-management/server/services/index.js +1 -0
- package/document-management/server/validators/ai-validation-executor.d.ts +419 -12
- package/document-management/server/validators/ai-validation-executor.js +51 -46
- package/document-management/server/validators/single-document-validation-executor.d.ts +1 -3
- package/document-management/server/validators/single-document-validation-executor.js +2 -4
- package/document-management/service-models/document.service-model.d.ts +3 -3
- package/document-management/service-models/document.service-model.js +1 -1
- package/document-management/tests/ai-config-hierarchy.test.d.ts +1 -0
- package/document-management/tests/ai-config-hierarchy.test.js +64 -0
- package/document-management/tests/ai-config-integration.test.d.ts +1 -0
- package/document-management/tests/ai-config-integration.test.js +125 -0
- package/document-management/tests/ai-config-merge.test.d.ts +1 -0
- package/document-management/tests/ai-config-merge.test.js +38 -0
- package/document-management/tests/document-management-ai-overrides.test.d.ts +1 -0
- package/document-management/tests/document-management-ai-overrides.test.js +64 -0
- package/document-management/tests/document-management-core.test.js +6 -6
- package/document-management/tests/document-management.api.test.js +5 -5
- package/document-management/tests/document-statistics.service.test.js +10 -6
- package/document-management/tests/document-validation-ai-overrides.test.d.ts +1 -0
- package/document-management/tests/document-validation-ai-overrides.test.js +85 -0
- package/document-management/tests/document.service.test.js +15 -11
- package/document-management/tests/enum-helpers.test.js +5 -5
- package/examples/document-management/ai-provider.d.ts +20 -0
- package/examples/document-management/ai-provider.js +74 -0
- package/examples/document-management/main.js +9 -6
- package/examples/injector/graph-example.d.ts +1 -0
- package/examples/injector/graph-example.js +340 -0
- package/injector/decorators.d.ts +4 -4
- package/injector/decorators.js +5 -6
- package/injector/forward-ref.d.ts +15 -0
- package/injector/forward-ref.js +20 -0
- package/injector/graph.d.ts +113 -0
- package/injector/graph.js +631 -0
- package/injector/index.d.ts +2 -0
- package/injector/index.js +2 -0
- package/injector/inject.d.ts +15 -15
- package/injector/injector.d.ts +101 -13
- package/injector/injector.js +103 -59
- package/injector/resolve-chain.d.ts +20 -6
- package/injector/resolve-chain.js +39 -14
- package/injector/tests/advanced.test.d.ts +1 -0
- package/injector/tests/advanced.test.js +116 -0
- package/injector/tests/async-init.test.d.ts +1 -0
- package/injector/tests/async-init.test.js +77 -0
- package/injector/tests/basic.test.d.ts +1 -0
- package/injector/tests/basic.test.js +114 -0
- package/injector/tests/hierarchical.test.d.ts +1 -0
- package/injector/tests/hierarchical.test.js +59 -0
- package/injector/tests/lifecycles.test.d.ts +1 -0
- package/injector/tests/lifecycles.test.js +109 -0
- package/injector/token.d.ts +2 -1
- package/injector/token.js +4 -1
- package/injector/type-info.d.ts +1 -5
- package/injector/types.d.ts +4 -10
- package/logger/tests/pretty-print.test.d.ts +1 -0
- package/logger/{formatters → tests}/pretty-print.test.js +1 -1
- package/logger/transports/console.d.ts +3 -2
- package/logger/transports/console.js +4 -3
- package/notification/api/notification.api.d.ts +26 -6
- package/notification/api/notification.api.js +15 -4
- package/notification/client/notification-client.d.ts +6 -0
- package/notification/client/notification-client.js +13 -3
- package/notification/models/in-app-notification.model.d.ts +9 -3
- package/notification/models/in-app-notification.model.js +32 -11
- package/notification/models/notification-log.model.js +2 -3
- package/notification/server/api/notification.api-controller.d.ts +1 -0
- package/notification/server/api/notification.api-controller.js +7 -1
- package/notification/server/drizzle/{0000_oval_rage.sql → 0000_wise_pyro.sql} +22 -4
- package/notification/server/drizzle/meta/0000_snapshot.json +249 -37
- package/notification/server/drizzle/meta/_journal.json +2 -2
- package/notification/server/module.d.ts +5 -0
- package/notification/server/module.js +6 -1
- package/notification/server/providers/in-app-channel-provider.js +1 -0
- package/notification/server/schemas.d.ts +3 -2
- package/notification/server/schemas.js +3 -2
- package/notification/server/services/notification.service.d.ts +11 -6
- package/notification/server/services/notification.service.js +138 -42
- package/notification/tests/notification-api.test.js +16 -6
- package/notification/tests/notification-client.test.d.ts +1 -0
- package/notification/tests/{unit/notification-client.test.js → notification-client.test.js} +5 -5
- package/notification/tests/notification-flow.test.js +45 -7
- package/notification/tests/notification-sse.service.test.js +1 -1
- package/notification/tests/notification-type.service.test.js +1 -1
- package/object-storage/s3/s3.object-storage.js +3 -0
- package/object-storage/s3/tests/s3.object-storage.integration.test.js +1 -1
- package/orm/server/drizzle/schema-converter.js +5 -3
- package/orm/tests/repository-attributes.test.js +10 -17
- package/orm/tests/repository-cti-mapping.test.js +2 -2
- package/orm/tests/repository-cti-soft-delete.test.js +1 -1
- package/orm/tests/repository-cti.test.js +19 -33
- package/orm/tests/repository-extra-coverage.test.js +1 -1
- package/orm/tests/repository-search.test.js +5 -2
- package/orm/tests/schema-converter.test.js +1 -0
- package/orm/tests/transaction-safety.test.js +1 -1
- package/package.json +7 -9
- package/rate-limit/tests/postgres-rate-limiter.test.js +6 -16
- package/renderer/d2.d.ts +77 -0
- package/renderer/d2.js +68 -0
- package/renderer/graphviz.d.ts +47 -0
- package/renderer/graphviz.js +58 -0
- package/renderer/index.d.ts +4 -0
- package/renderer/index.js +4 -0
- package/renderer/typst.d.ts +57 -0
- package/renderer/typst.js +62 -0
- package/rpc/adapters/readable-stream.adapter.d.ts +3 -0
- package/rpc/adapters/readable-stream.adapter.js +5 -1
- package/rpc/rpc.js +28 -3
- package/rpc/tests/rpc.integration.test.js +3 -1
- package/schema/schemas/nullable.js +1 -1
- package/task-queue/task-queue.d.ts +2 -0
- package/task-queue/task-queue.js +6 -2
- package/task-queue/tests/complex.test.js +1 -1
- package/task-queue/tests/dependencies.test.js +3 -3
- package/task-queue/tests/extensive-dependencies.test.js +1 -1
- package/task-queue/tests/queue.test.js +1 -1
- package/task-queue/tests/worker.test.js +4 -7
- package/test5.js +52 -8
- package/{unit-test → testing}/integration-setup.d.ts +1 -0
- package/{unit-test → testing}/integration-setup.js +13 -0
- package/utils/base64.d.ts +7 -0
- package/utils/base64.js +10 -1
- package/utils/noop.d.ts +7 -1
- package/utils/noop.js +7 -1
- package/ai/ai-file.service.d.ts +0 -57
- package/ai/ai-file.service.js +0 -233
- package/ai/ai-session.d.ts +0 -38
- package/ai/ai-session.js +0 -50
- package/ai/ai.service.d.ts +0 -126
- package/ai/ai.service.js +0 -481
- package/ai/functions.d.ts +0 -9
- package/ai/functions.js +0 -38
- package/ai/module.d.ts +0 -26
- package/ai/module.js +0 -25
- package/ai/types.d.ts +0 -229
- package/ai/types.js +0 -33
- package/latex/index.d.ts +0 -1
- package/latex/index.js +0 -1
- package/typst/index.d.ts +0 -1
- package/typst/index.js +0 -1
- package/typst/render.d.ts +0 -23
- package/typst/render.js +0 -32
- /package/{logger/formatters/pretty-print.test.d.ts → ai/tests/instructions-formatter.test.d.ts} +0 -0
- /package/{notification/tests/unit/notification-client.test.d.ts → ai/tests/steering.test.d.ts} +0 -0
- /package/{latex/render.d.ts → renderer/latex.d.ts} +0 -0
- /package/{latex/render.js → renderer/latex.js} +0 -0
- /package/{unit-test → testing}/index.d.ts +0 -0
- /package/{unit-test → testing}/index.js +0 -0
|
@@ -39,7 +39,7 @@ export const deleteDocumentRequestTemplateParametersSchema = assign(pick(Documen
|
|
|
39
39
|
export const createDocumentRequestParametersSchema = assign(pick(DocumentRequest, ['typeId', 'comment']), object({ collectionIds: array(string()) }), metadataParameterObjectSchema);
|
|
40
40
|
export const updateDocumentRequestParametersSchema = assign(pick(DocumentRequest, ['id']), partial(pick(DocumentRequest, ['typeId', 'comment'])), metadataParameterObjectSchema);
|
|
41
41
|
export const deleteDocumentRequestParametersSchema = assign(pick(DocumentRequest, ['id']), metadataParameterObjectSchema);
|
|
42
|
-
export const
|
|
42
|
+
export const getDataParametersSchema = object({ collectionIds: oneOrMany(string()) });
|
|
43
43
|
export const createCollectionParametersSchema = assign(pick(DocumentCollection, ['parentId']), metadataParameterObjectSchema);
|
|
44
44
|
export const setDocumentPropertiesParametersSchema = object({
|
|
45
45
|
documentId: string(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { injectModel } from '../../ai/genkit/index.js';
|
|
3
|
+
import { runInInjectionContext } from '../../injector/index.js';
|
|
4
|
+
import { setupIntegrationTest } from '../../testing/index.js';
|
|
5
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
6
|
+
import { DocumentCategoryTypeService, DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
7
|
+
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
8
|
+
describe('DocumentManagementAiService Hierarchy', () => {
|
|
9
|
+
let injector;
|
|
10
|
+
let aiService;
|
|
11
|
+
let flashModel;
|
|
12
|
+
const tenantId = crypto.randomUUID();
|
|
13
|
+
const mockAiProvider = {
|
|
14
|
+
getGlobalConfiguration: vi.fn(),
|
|
15
|
+
getClassificationConfiguration: vi.fn(),
|
|
16
|
+
getDataExtractionConfiguration: vi.fn(),
|
|
17
|
+
getAssignmentConfiguration: vi.fn(),
|
|
18
|
+
getValidationConfiguration: vi.fn(),
|
|
19
|
+
getContentExtractionConfiguration: vi.fn(),
|
|
20
|
+
};
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
({ injector } = await setupIntegrationTest({
|
|
23
|
+
orm: { schema: 'document_management' },
|
|
24
|
+
modules: { messageBus: true, signals: true, objectStorage: true, documentManagement: true },
|
|
25
|
+
}));
|
|
26
|
+
runInInjectionContext(injector, () => {
|
|
27
|
+
flashModel = injectModel('gemini-2.5-flash');
|
|
28
|
+
});
|
|
29
|
+
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
30
|
+
// Ancillary and configuration are already registered by setupIntegrationTest, but we can override if needed
|
|
31
|
+
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
32
|
+
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
33
|
+
});
|
|
34
|
+
afterAll(async () => {
|
|
35
|
+
await injector?.dispose();
|
|
36
|
+
});
|
|
37
|
+
test('resolveAiConfiguration should implement Type > Category > Global Step > Global Defaults hierarchy', async () => {
|
|
38
|
+
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
39
|
+
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance-cat', parentId: null });
|
|
40
|
+
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice-type' });
|
|
41
|
+
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
42
|
+
defaults: { language: 'de', classification: 'Global Default Classify' },
|
|
43
|
+
steps: {
|
|
44
|
+
'data-extraction': { language: 'en', extraction: { title: 'Global Step Title' } }
|
|
45
|
+
},
|
|
46
|
+
categories: {
|
|
47
|
+
'finance-cat': { extraction: { title: 'Category Title', subtitle: 'Category Subtitle' } }
|
|
48
|
+
},
|
|
49
|
+
documentTypes: {
|
|
50
|
+
'invoice-type': { extraction: { title: 'Type Title' } }
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue({
|
|
54
|
+
extraction: { subtitle: 'Provider Subtitle' }
|
|
55
|
+
});
|
|
56
|
+
await runInInjectionContext(injector, async () => {
|
|
57
|
+
const config = await aiService.resolveAiConfiguration(tenantId, 'data-extraction', { type });
|
|
58
|
+
expect(config.language).toBe('en'); // Step > Defaults
|
|
59
|
+
expect(config.classification).toBe('Global Default Classify'); // Fallback to defaults
|
|
60
|
+
expect(config.extraction.title).toBe('Type Title'); // Type > Category > Step
|
|
61
|
+
expect(config.extraction.subtitle).toBe('Provider Subtitle'); // Provider > Category
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
const mockGenerate = vi.fn();
|
|
3
|
+
vi.mock('genkit', async () => {
|
|
4
|
+
const original = await vi.importActual('genkit');
|
|
5
|
+
return {
|
|
6
|
+
...original,
|
|
7
|
+
genkit: () => ({
|
|
8
|
+
generate: mockGenerate,
|
|
9
|
+
}),
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
import { injectModel } from '../../ai/genkit/index.js';
|
|
13
|
+
import { runInInjectionContext } from '../../injector/index.js';
|
|
14
|
+
import { ObjectStorage } from '../../object-storage/index.js';
|
|
15
|
+
import { setupIntegrationTest } from '../../testing/index.js';
|
|
16
|
+
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
17
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
18
|
+
import { DocumentService } from '../server/services/document.service.js';
|
|
19
|
+
import { DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
20
|
+
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
21
|
+
describe('DocumentManagementAiService Integration', () => {
|
|
22
|
+
let injector;
|
|
23
|
+
let aiService;
|
|
24
|
+
let flashModel;
|
|
25
|
+
const tenantId = crypto.randomUUID();
|
|
26
|
+
const mockAiProvider = {
|
|
27
|
+
getGlobalConfiguration: vi.fn(),
|
|
28
|
+
getClassificationConfiguration: vi.fn(),
|
|
29
|
+
getDataExtractionConfiguration: vi.fn(),
|
|
30
|
+
getAssignmentConfiguration: vi.fn(),
|
|
31
|
+
getValidationConfiguration: vi.fn(),
|
|
32
|
+
getContentExtractionConfiguration: vi.fn(),
|
|
33
|
+
};
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
({ injector } = await setupIntegrationTest({
|
|
36
|
+
modules: { messageBus: true, signals: true, objectStorage: true, documentManagement: true, taskQueue: true },
|
|
37
|
+
}));
|
|
38
|
+
const mockObjectStorage = {
|
|
39
|
+
store: vi.fn().mockResolvedValue({ mimeType: 'application/pdf', hash: 'hash', size: 100 }),
|
|
40
|
+
uploadObject: vi.fn(),
|
|
41
|
+
getDownloadUrl: vi.fn(),
|
|
42
|
+
getContent: vi.fn().mockResolvedValue(new Uint8Array([1, 2, 3])),
|
|
43
|
+
getContentStream: vi.fn(),
|
|
44
|
+
getObject: vi.fn(),
|
|
45
|
+
exists: vi.fn(),
|
|
46
|
+
};
|
|
47
|
+
runInInjectionContext(injector, () => {
|
|
48
|
+
flashModel = injectModel('gemini-2.5-flash');
|
|
49
|
+
});
|
|
50
|
+
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
51
|
+
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
52
|
+
injector.register(ObjectStorage, { useValue: mockObjectStorage });
|
|
53
|
+
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
54
|
+
});
|
|
55
|
+
afterAll(async () => {
|
|
56
|
+
await injector?.dispose();
|
|
57
|
+
});
|
|
58
|
+
test('extractData should include granular instructions in prompt', async () => {
|
|
59
|
+
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
60
|
+
const documentService = await injector.resolveAsync(DocumentService);
|
|
61
|
+
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance', parentId: null });
|
|
62
|
+
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice' });
|
|
63
|
+
const document = await documentService.create(tenantId, {
|
|
64
|
+
typeId: type.id,
|
|
65
|
+
originalFileName: 'test.pdf',
|
|
66
|
+
skipWorkflow: true,
|
|
67
|
+
assignment: { collections: [] }
|
|
68
|
+
}, new Uint8Array([1, 2, 3]));
|
|
69
|
+
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
70
|
+
documentTypes: {
|
|
71
|
+
'invoice': {
|
|
72
|
+
extraction: {
|
|
73
|
+
title: { format: 'INV-{{Date}}' },
|
|
74
|
+
summary: { content: 'Focus on items.', strategy: 'append' }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue(undefined);
|
|
80
|
+
// Mock Genkit output
|
|
81
|
+
mockGenerate.mockResolvedValue({
|
|
82
|
+
output: {
|
|
83
|
+
documentTitle: 'INV-2024',
|
|
84
|
+
documentSubtitle: null,
|
|
85
|
+
documentSummary: 'Summary',
|
|
86
|
+
documentTags: [],
|
|
87
|
+
documentDate: null
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
await runInInjectionContext(injector, async () => {
|
|
91
|
+
await aiService.extractData(tenantId, document.id);
|
|
92
|
+
const lastCall = mockGenerate.mock.calls[0][0];
|
|
93
|
+
const systemPrompt = lastCall.system;
|
|
94
|
+
const systemPromptText = systemPrompt.map((p) => p.text).join('\n');
|
|
95
|
+
expect(systemPromptText).toContain('Format the title of the document exactly as follows: INV-{{Date}}');
|
|
96
|
+
expect(systemPromptText).toContain('Focus on items.');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
test('classifyDocumentType should include granular instructions in prompt', async () => {
|
|
100
|
+
const documentService = await injector.resolveAsync(DocumentService);
|
|
101
|
+
const document = await documentService.create(tenantId, {
|
|
102
|
+
originalFileName: 'test.pdf',
|
|
103
|
+
skipWorkflow: true,
|
|
104
|
+
assignment: { collections: [] }
|
|
105
|
+
}, new Uint8Array([1, 2, 3]));
|
|
106
|
+
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
107
|
+
defaults: {
|
|
108
|
+
classification: { content: 'Prefer Finance types.', strategy: 'append' }
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
mockAiProvider.getClassificationConfiguration.mockResolvedValue(undefined);
|
|
112
|
+
mockGenerate.mockResolvedValue({
|
|
113
|
+
output: {
|
|
114
|
+
documentType: 'Category: Finance | Type: Invoice'
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
await runInInjectionContext(injector, async () => {
|
|
118
|
+
await aiService.classifyDocumentType(tenantId, document.id);
|
|
119
|
+
const lastCall = mockGenerate.mock.calls[1][0];
|
|
120
|
+
const systemPrompt = lastCall.system;
|
|
121
|
+
const systemPromptText = systemPrompt.map((p) => p.text).join('\n');
|
|
122
|
+
expect(systemPromptText).toContain('Prefer Finance types.');
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { mergeInstructions } from '../server/services/document-management-ai.service.js';
|
|
3
|
+
describe('AI Instruction Merging', () => {
|
|
4
|
+
test('should return base when no overrides are provided', () => {
|
|
5
|
+
const base = 'Default instruction';
|
|
6
|
+
expect(mergeInstructions(base, [])).toBe(base);
|
|
7
|
+
});
|
|
8
|
+
test('should replace with string override', () => {
|
|
9
|
+
const base = 'Default instruction';
|
|
10
|
+
const overrides = ['Custom instruction'];
|
|
11
|
+
expect(mergeInstructions(base, overrides)).toBe('Custom instruction');
|
|
12
|
+
});
|
|
13
|
+
test('should append with append strategy', () => {
|
|
14
|
+
const base = 'Default instruction';
|
|
15
|
+
const overrides = [{ content: 'Added instruction', strategy: 'append' }];
|
|
16
|
+
expect(mergeInstructions(base, overrides)).toBe('Default instruction\n\nAdded instruction');
|
|
17
|
+
});
|
|
18
|
+
test('should replace with replace strategy', () => {
|
|
19
|
+
const base = 'Default instruction';
|
|
20
|
+
const overrides = [{ content: 'New instruction', strategy: 'replace' }];
|
|
21
|
+
expect(mergeInstructions(base, overrides)).toBe('New instruction');
|
|
22
|
+
});
|
|
23
|
+
test('should handle multiple overrides in order', () => {
|
|
24
|
+
const base = 'Base';
|
|
25
|
+
const overrides = [
|
|
26
|
+
{ content: 'Global', strategy: 'append' },
|
|
27
|
+
{ content: 'Category', strategy: 'append' },
|
|
28
|
+
{ content: 'Type', strategy: 'replace' }
|
|
29
|
+
];
|
|
30
|
+
expect(mergeInstructions(base, overrides)).toBe('Type');
|
|
31
|
+
});
|
|
32
|
+
test('should handle format simple override', () => {
|
|
33
|
+
const base = 'Create a title.';
|
|
34
|
+
const overrides = [{ format: '[ID] - [Name]' }];
|
|
35
|
+
const result = mergeInstructions(base, overrides);
|
|
36
|
+
expect(result).toContain('[ID] - [Name]');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { injectModel } from '../../ai/genkit/index.js';
|
|
3
|
+
import { runInInjectionContext } from '../../injector/index.js';
|
|
4
|
+
import { ObjectStorage } from '../../object-storage/index.js';
|
|
5
|
+
import { setupIntegrationTest } from '../../testing/index.js';
|
|
6
|
+
import { DocumentManagementConfiguration } from '../server/module.js';
|
|
7
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
8
|
+
import { DocumentCategoryTypeService, DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
9
|
+
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
10
|
+
describe('DocumentManagementAiService Overrides', () => {
|
|
11
|
+
let injector;
|
|
12
|
+
let aiService;
|
|
13
|
+
let flashModel;
|
|
14
|
+
let proModel;
|
|
15
|
+
const tenantId = crypto.randomUUID();
|
|
16
|
+
const mockAiProvider = {
|
|
17
|
+
getGlobalConfiguration: vi.fn(),
|
|
18
|
+
getClassificationConfiguration: vi.fn(),
|
|
19
|
+
getDataExtractionConfiguration: vi.fn(),
|
|
20
|
+
getAssignmentConfiguration: vi.fn(),
|
|
21
|
+
getValidationConfiguration: vi.fn(),
|
|
22
|
+
};
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
({ injector } = await setupIntegrationTest({
|
|
25
|
+
orm: { schema: 'document_management' },
|
|
26
|
+
modules: { messageBus: true, signals: true, objectStorage: true },
|
|
27
|
+
}));
|
|
28
|
+
runInInjectionContext(injector, () => {
|
|
29
|
+
flashModel = injectModel('gemini-2.5-flash');
|
|
30
|
+
proModel = injectModel('gemini-2.5-pro');
|
|
31
|
+
});
|
|
32
|
+
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
33
|
+
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
34
|
+
injector.register(DocumentManagementConfiguration, { useValue: { fileObjectStorageModule: 'docs', fileUploadObjectStorageModule: 'uploads', filePreviewObjectStorageModule: 'previews' } });
|
|
35
|
+
aiService = await injector.resolveAsync(DocumentManagementAiService);
|
|
36
|
+
});
|
|
37
|
+
afterAll(async () => {
|
|
38
|
+
await injector?.dispose();
|
|
39
|
+
});
|
|
40
|
+
test('resolveAiConfiguration should merge configurations correctly', async () => {
|
|
41
|
+
const categoryTypeService = await injector.resolveAsync(DocumentCategoryTypeService);
|
|
42
|
+
const category = await categoryTypeService.createCategory({ tenantId, label: 'Finance', key: 'finance-cat', parentId: null });
|
|
43
|
+
const type = await categoryTypeService.createType({ tenantId, categoryId: category.id, label: 'Invoice', key: 'invoice-key' });
|
|
44
|
+
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
45
|
+
defaults: {
|
|
46
|
+
language: 'en',
|
|
47
|
+
model: flashModel,
|
|
48
|
+
prompt: { systemAddition: 'Global System' },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
mockAiProvider.getDataExtractionConfiguration.mockResolvedValue({
|
|
52
|
+
model: proModel,
|
|
53
|
+
prompt: { systemAddition: 'Extraction System', systemOverride: (base) => `OVERRIDDEN: ${base}` },
|
|
54
|
+
});
|
|
55
|
+
await runInInjectionContext(injector, async () => {
|
|
56
|
+
// Accessing private method for testing purposes
|
|
57
|
+
const config = await aiService.resolveAiConfiguration(tenantId, 'data-extraction', { type });
|
|
58
|
+
expect(config.language).toBe('en');
|
|
59
|
+
expect(config.model).toBe(proModel);
|
|
60
|
+
expect(config.prompt.systemAddition).toEqual(['Global System', 'Extraction System']);
|
|
61
|
+
expect(config.prompt.systemOverride('Base')).toBe('OVERRIDDEN: Base');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { AiModuleOptions } from '../../ai/module.js';
|
|
2
|
+
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
4
3
|
import { runInInjectionContext } from '../../injector/index.js';
|
|
5
4
|
import { ObjectStorage } from '../../object-storage/index.js';
|
|
6
5
|
import { TaskQueue } from '../../task-queue/index.js';
|
|
7
|
-
import {
|
|
6
|
+
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
8
7
|
import { configureDocumentManagement } from '../server/configure.js';
|
|
9
8
|
import { migrateDocumentManagementSchema } from '../server/module.js';
|
|
10
9
|
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
11
10
|
import { DocumentCollectionService } from '../server/services/document-collection.service.js';
|
|
11
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
12
12
|
import { DocumentManagementService } from '../server/services/document-management.service.js';
|
|
13
13
|
import { DocumentPropertyService } from '../server/services/document-property.service.js';
|
|
14
14
|
import { DocumentRequestService } from '../server/services/document-request.service.js';
|
|
@@ -22,8 +22,8 @@ describe('Document Management Core', () => {
|
|
|
22
22
|
let collectionService;
|
|
23
23
|
let requestService;
|
|
24
24
|
let managementService;
|
|
25
|
-
let workflowService;
|
|
26
25
|
let categoryTypeService;
|
|
26
|
+
let workflowService;
|
|
27
27
|
let propertyService;
|
|
28
28
|
const schema = 'document_management';
|
|
29
29
|
const tenantId = crypto.randomUUID();
|
|
@@ -32,8 +32,8 @@ describe('Document Management Core', () => {
|
|
|
32
32
|
modules: { taskQueue: false, messageBus: true }, // Disabled TaskQueue to avoid background noise
|
|
33
33
|
orm: { schema },
|
|
34
34
|
}));
|
|
35
|
-
injector.register(
|
|
36
|
-
injector.register(
|
|
35
|
+
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
36
|
+
injector.register(DocumentManagementAiService, { useValue: { extractContent: vi.fn(), classifyDocumentType: vi.fn(), extractData: vi.fn(), findSuitableCollectionsForDocument: vi.fn(), findSuitableRequestForDocument: vi.fn() } });
|
|
37
37
|
injector.register(ObjectStorage, {
|
|
38
38
|
useValue: {
|
|
39
39
|
uploadObject: vi.fn(),
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { AiModuleOptions } from '../../ai/module.js';
|
|
2
|
+
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
4
3
|
import { runInInjectionContext } from '../../injector/index.js';
|
|
5
4
|
import { ObjectStorage } from '../../object-storage/index.js';
|
|
6
5
|
import { TaskQueue } from '../../task-queue/index.js';
|
|
7
|
-
import { clearTenantData, setupIntegrationTest } from '../../
|
|
6
|
+
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
8
7
|
import { DocumentManagementAuthorizationService } from '../authorization/document-management-authorization.service.js';
|
|
9
8
|
import { DocumentManagementApiController } from '../server/api/document-management.api.js';
|
|
10
9
|
import { configureDocumentManagement } from '../server/configure.js';
|
|
11
10
|
import { migrateDocumentManagementSchema } from '../server/module.js';
|
|
12
11
|
import { DocumentCollectionService } from '../server/services/document-collection.service.js';
|
|
12
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
13
13
|
import { DocumentService } from '../server/services/document.service.js';
|
|
14
14
|
import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
|
|
15
15
|
describe('DocumentManagementApi Stats', () => {
|
|
@@ -25,8 +25,8 @@ describe('DocumentManagementApi Stats', () => {
|
|
|
25
25
|
modules: { taskQueue: false, messageBus: true },
|
|
26
26
|
orm: { schema },
|
|
27
27
|
}));
|
|
28
|
-
injector.register(
|
|
29
|
-
injector.register(
|
|
28
|
+
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
29
|
+
injector.register(DocumentManagementAiService, { useValue: { extractContent: vi.fn(), classifyDocumentType: vi.fn(), extractData: vi.fn(), findSuitableCollectionsForDocument: vi.fn(), findSuitableRequestForDocument: vi.fn() } });
|
|
30
30
|
injector.register(ObjectStorage, {
|
|
31
31
|
useValue: {
|
|
32
32
|
uploadObject: vi.fn(),
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { AiModuleOptions } from '../../ai/module.js';
|
|
2
|
+
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
4
3
|
import { runInInjectionContext } from '../../injector/index.js';
|
|
5
4
|
import { ObjectStorage } from '../../object-storage/index.js';
|
|
6
5
|
import { getRepository } from '../../orm/server/index.js';
|
|
7
|
-
import { clearTenantData, setupIntegrationTest } from '../../
|
|
6
|
+
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
8
7
|
import { DocumentValidationDefinition } from '../models/document-validation-definition.model.js';
|
|
9
8
|
import { DocumentValidationExecution, DocumentValidationExecutionState, DocumentValidationResultStatus } from '../models/document-validation-execution.model.js';
|
|
10
9
|
import { DocumentWorkflow, DocumentWorkflowState, DocumentWorkflowStep } from '../models/document-workflow.model.js';
|
|
@@ -13,6 +12,7 @@ import { configureDocumentManagement } from '../server/configure.js';
|
|
|
13
12
|
import { migrateDocumentManagementSchema } from '../server/module.js';
|
|
14
13
|
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
15
14
|
import { DocumentCollectionService } from '../server/services/document-collection.service.js';
|
|
15
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
16
16
|
import { DocumentStatisticsService } from '../server/services/document-statistics.service.js';
|
|
17
17
|
import { DocumentTagService } from '../server/services/document-tag.service.js';
|
|
18
18
|
import { DocumentService } from '../server/services/document.service.js';
|
|
@@ -41,11 +41,15 @@ describe('DocumentStatisticsService', () => {
|
|
|
41
41
|
exists: vi.fn(),
|
|
42
42
|
};
|
|
43
43
|
const mockAiService = {
|
|
44
|
-
|
|
44
|
+
extractContent: vi.fn(),
|
|
45
|
+
classifyDocumentType: vi.fn(),
|
|
46
|
+
extractData: vi.fn(),
|
|
47
|
+
findSuitableCollectionsForDocument: vi.fn(),
|
|
48
|
+
findSuitableRequestForDocument: vi.fn(),
|
|
45
49
|
};
|
|
46
50
|
injector.register(ObjectStorage, { useFactory: () => mockObjectStorage });
|
|
47
|
-
injector.register(
|
|
48
|
-
injector.register(
|
|
51
|
+
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
52
|
+
injector.register(DocumentManagementAiService, { useValue: mockAiService });
|
|
49
53
|
configureDocumentManagement({
|
|
50
54
|
ancillaryService: TestDocumentManagementAncillaryService,
|
|
51
55
|
authorizationService: TestDocumentManagementAuthorizationService,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { injectModel } from '../../ai/genkit/index.js';
|
|
3
|
+
import { formatInstructions } from '../../ai/prompts/index.js';
|
|
4
|
+
import { runInInjectionContext } from '../../injector/index.js';
|
|
5
|
+
import { object, string } from '../../schema/index.js';
|
|
6
|
+
import { setupIntegrationTest } from '../../testing/index.js';
|
|
7
|
+
import { isString } from '../../utils/type-guards.js';
|
|
8
|
+
import { DocumentManagementConfiguration } from '../server/module.js';
|
|
9
|
+
import { DocumentManagementAiProviderService, DocumentManagementAncillaryService } from '../server/services/index.js';
|
|
10
|
+
import { AiValidationExecutor } from '../server/validators/ai-validation-executor.js';
|
|
11
|
+
import { TestDocumentManagementAncillaryService } from './helper.js';
|
|
12
|
+
class TestAiValidationExecutor extends AiValidationExecutor {
|
|
13
|
+
identifier = 'test-validation';
|
|
14
|
+
schema = object({ valid: string() });
|
|
15
|
+
async getValidationInstructions() { return 'Test Prompt'; }
|
|
16
|
+
async getResult() { return { status: 'passed' }; }
|
|
17
|
+
executorConfig = {};
|
|
18
|
+
getAiConfiguration() { return this.executorConfig; }
|
|
19
|
+
// Expose protected method for testing
|
|
20
|
+
async publicExecute(context) {
|
|
21
|
+
return this.execute(context);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
describe('AiValidationExecutor Overrides', () => {
|
|
25
|
+
let injector;
|
|
26
|
+
let flashModel;
|
|
27
|
+
let proModel;
|
|
28
|
+
const tenantId = crypto.randomUUID();
|
|
29
|
+
const mockAiProvider = {
|
|
30
|
+
getGlobalConfiguration: vi.fn(),
|
|
31
|
+
getValidationConfiguration: vi.fn(),
|
|
32
|
+
};
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
({ injector } = await setupIntegrationTest({
|
|
35
|
+
orm: { schema: 'document_management' },
|
|
36
|
+
modules: { messageBus: true, signals: true, objectStorage: true },
|
|
37
|
+
}));
|
|
38
|
+
runInInjectionContext(injector, () => {
|
|
39
|
+
flashModel = injectModel('gemini-2.5-flash');
|
|
40
|
+
proModel = injectModel('gemini-2.5-pro');
|
|
41
|
+
});
|
|
42
|
+
injector.register(DocumentManagementAiProviderService, { useValue: mockAiProvider });
|
|
43
|
+
injector.register(DocumentManagementAncillaryService, { useToken: TestDocumentManagementAncillaryService });
|
|
44
|
+
injector.register(DocumentManagementConfiguration, { useValue: { fileObjectStorageModule: 'docs', fileUploadObjectStorageModule: 'uploads', filePreviewObjectStorageModule: 'previews' } });
|
|
45
|
+
});
|
|
46
|
+
afterAll(async () => {
|
|
47
|
+
await injector?.dispose();
|
|
48
|
+
});
|
|
49
|
+
test('AiValidationExecutor should merge configurations correctly', async () => {
|
|
50
|
+
mockAiProvider.getGlobalConfiguration.mockResolvedValue({
|
|
51
|
+
defaults: {
|
|
52
|
+
language: 'en',
|
|
53
|
+
model: flashModel,
|
|
54
|
+
prompt: { systemAddition: 'Global System', userAddition: 'Global User' },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
mockAiProvider.getValidationConfiguration.mockResolvedValue({
|
|
58
|
+
model: proModel,
|
|
59
|
+
prompt: { systemAddition: 'Validation System', systemOverride: (base) => `OVERRIDDEN: ${isString(base) ? base : formatInstructions(base)}` },
|
|
60
|
+
});
|
|
61
|
+
await runInInjectionContext(injector, async () => {
|
|
62
|
+
const executor = new TestAiValidationExecutor();
|
|
63
|
+
executor.executorConfig = {
|
|
64
|
+
prompt: { systemAddition: 'Executor System', userAddition: 'Executor User' },
|
|
65
|
+
};
|
|
66
|
+
const generateSpy = vi.spyOn(executor.genkit, 'generate').mockResolvedValue({ output: { valid: 'yes' } });
|
|
67
|
+
const context = {
|
|
68
|
+
execution: { tenantId },
|
|
69
|
+
definition: { identifier: 'test-validation' },
|
|
70
|
+
};
|
|
71
|
+
await executor.publicExecute(context);
|
|
72
|
+
const call = generateSpy.mock.calls[0][0];
|
|
73
|
+
const systemText = call.system.map((p) => p.text).join('\n');
|
|
74
|
+
const userText = call.prompt.map((p) => p.text).join('\n');
|
|
75
|
+
expect(call.model.name).toBe(proModel.name);
|
|
76
|
+
expect(systemText).toContain('Global System');
|
|
77
|
+
expect(systemText).toContain('Executor System');
|
|
78
|
+
expect(systemText).toContain('Validation System');
|
|
79
|
+
expect(systemText).toContain('OVERRIDDEN:');
|
|
80
|
+
expect(userText).toContain('Global User');
|
|
81
|
+
expect(userText).toContain('Executor User');
|
|
82
|
+
expect(userText).toContain('IMPORTANT: All generated text content MUST be in en.');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { AiModuleOptions } from '../../ai/module.js';
|
|
2
|
+
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
4
3
|
import { runInInjectionContext } from '../../injector/index.js';
|
|
5
4
|
import { ObjectStorage } from '../../object-storage/index.js';
|
|
6
|
-
import { clearTenantData, setupIntegrationTest } from '../../
|
|
7
|
-
import { DocumentWorkflowState } from '../models/document-workflow.model.js';
|
|
5
|
+
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
6
|
+
import { DocumentWorkflowState, DocumentWorkflowStep } from '../models/document-workflow.model.js';
|
|
8
7
|
import { DocumentApproval } from '../models/document.model.js';
|
|
9
8
|
import { configureDocumentManagement } from '../server/configure.js';
|
|
10
9
|
import { DocumentManagementConfiguration, migrateDocumentManagementSchema } from '../server/module.js';
|
|
11
10
|
import { DocumentCollectionService } from '../server/services/document-collection.service.js';
|
|
11
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
12
12
|
import { DocumentWorkflowService } from '../server/services/document-workflow.service.js';
|
|
13
13
|
import { DocumentService } from '../server/services/document.service.js';
|
|
14
14
|
import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
|
|
@@ -34,11 +34,15 @@ describe('DocumentService', () => {
|
|
|
34
34
|
exists: vi.fn(),
|
|
35
35
|
};
|
|
36
36
|
const mockAiService = {
|
|
37
|
-
|
|
37
|
+
extractContent: vi.fn(),
|
|
38
|
+
classifyDocumentType: vi.fn(),
|
|
39
|
+
extractData: vi.fn(),
|
|
40
|
+
findSuitableCollectionsForDocument: vi.fn(),
|
|
41
|
+
findSuitableRequestForDocument: vi.fn(),
|
|
38
42
|
};
|
|
39
43
|
injector.register(ObjectStorage, { useFactory: () => mockObjectStorage });
|
|
40
|
-
injector.register(
|
|
41
|
-
injector.register(
|
|
44
|
+
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
45
|
+
injector.register(DocumentManagementAiService, { useValue: mockAiService });
|
|
42
46
|
configureDocumentManagement({
|
|
43
47
|
ancillaryService: TestDocumentManagementAncillaryService,
|
|
44
48
|
authorizationService: TestDocumentManagementAuthorizationService,
|
|
@@ -99,9 +103,9 @@ describe('DocumentService', () => {
|
|
|
99
103
|
await workflowService.proceedWorkflow(tenantId, doc.id, crypto.randomUUID(), DocumentWorkflowState.Completed);
|
|
100
104
|
workflows = await workflowService.loadWorkflows(tenantId, doc.id);
|
|
101
105
|
expect(workflows).toHaveLength(2);
|
|
102
|
-
expect(workflows.find((w) => w.step ==
|
|
103
|
-
expect(workflows.find((w) => w.step ==
|
|
104
|
-
expect(workflows.find((w) => w.step ==
|
|
106
|
+
expect(workflows.find((w) => w.step == DocumentWorkflowStep.Classification)?.state).toBe('completed');
|
|
107
|
+
expect(workflows.find((w) => w.step == DocumentWorkflowStep.DataExtraction)?.state).toBe('pending');
|
|
108
|
+
expect(workflows.find((w) => w.step == DocumentWorkflowStep.DataExtraction)?.skipAi).toBe(true);
|
|
105
109
|
});
|
|
106
110
|
});
|
|
107
111
|
test('proceedWorkflow with skipAi: true should allow progression to Review', async () => {
|
|
@@ -112,7 +116,7 @@ describe('DocumentService', () => {
|
|
|
112
116
|
assignment: { collections: [collection.id] },
|
|
113
117
|
skipAi: true,
|
|
114
118
|
}, new Uint8Array([1, 2, 3]));
|
|
115
|
-
await workflowService.proceedWorkflow(tenantId, doc.id, crypto.randomUUID(),
|
|
119
|
+
await workflowService.proceedWorkflow(tenantId, doc.id, crypto.randomUUID(), DocumentWorkflowState.Review);
|
|
116
120
|
const workflows = await workflowService.loadWorkflows(tenantId, doc.id);
|
|
117
121
|
expect(workflows).toHaveLength(1);
|
|
118
122
|
expect(workflows[0].step).toBe('classification');
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { afterAll, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
import { AiModuleOptions } from '../../ai/module.js';
|
|
2
|
+
import { GenkitModuleOptions } from '../../ai/genkit/module.js';
|
|
4
3
|
import { NotFoundError } from '../../errors/not-found.error.js';
|
|
5
4
|
import { runInInjectionContext } from '../../injector/index.js';
|
|
6
5
|
import { ObjectStorage } from '../../object-storage/index.js';
|
|
7
6
|
import { TaskQueue } from '../../task-queue/index.js';
|
|
8
|
-
import { clearTenantData, setupIntegrationTest } from '../../
|
|
7
|
+
import { clearTenantData, setupIntegrationTest } from '../../testing/index.js';
|
|
9
8
|
import { DocumentPropertyDataType } from '../models/document-property.model.js';
|
|
10
9
|
import { configureDocumentManagement } from '../server/configure.js';
|
|
11
10
|
import { migrateDocumentManagementSchema } from '../server/module.js';
|
|
12
11
|
import { DocumentCategoryTypeService } from '../server/services/document-category-type.service.js';
|
|
12
|
+
import { DocumentManagementAiService } from '../server/services/document-management-ai.service.js';
|
|
13
13
|
import { DocumentManagementService } from '../server/services/document-management.service.js';
|
|
14
14
|
import { DocumentPropertyService } from '../server/services/document-property.service.js';
|
|
15
15
|
import { TestDocumentManagementAncillaryService, TestDocumentManagementAuthorizationService } from './helper.js';
|
|
@@ -27,8 +27,8 @@ describe('Document Management Extended Suite', () => {
|
|
|
27
27
|
modules: { taskQueue: false, messageBus: true },
|
|
28
28
|
orm: { schema },
|
|
29
29
|
}));
|
|
30
|
-
injector.register(
|
|
31
|
-
injector.register(
|
|
30
|
+
injector.register(GenkitModuleOptions, { useValue: {} });
|
|
31
|
+
injector.register(DocumentManagementAiService, { useValue: { extractContent: vi.fn(), classifyDocumentType: vi.fn(), extractData: vi.fn(), findSuitableCollectionsForDocument: vi.fn(), findSuitableRequestForDocument: vi.fn() } });
|
|
32
32
|
injector.register(ObjectStorage, {
|
|
33
33
|
useValue: {
|
|
34
34
|
uploadObject: vi.fn(),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AiConfiguration, DocumentManagementAiConfiguration, DocumentWorkflowStep } from '../../document-management/index.js';
|
|
2
|
+
import { DocumentManagementAiProviderService, type AiConfigurationResolveDataMap } from '../../document-management/server/index.js';
|
|
3
|
+
export declare class ExampleAiProviderService extends DocumentManagementAiProviderService {
|
|
4
|
+
/**
|
|
5
|
+
* Providing global defaults for the entire Document Management module.
|
|
6
|
+
*/
|
|
7
|
+
getGlobalConfiguration(): DocumentManagementAiConfiguration;
|
|
8
|
+
getContentExtractionConfiguration(): AiConfiguration;
|
|
9
|
+
/**
|
|
10
|
+
* Providing specific overrides for the Classification step.
|
|
11
|
+
*/
|
|
12
|
+
getClassificationConfiguration(): AiConfiguration;
|
|
13
|
+
/**
|
|
14
|
+
* Providing specific overrides for the Data Extraction step,
|
|
15
|
+
* potentially specific to a Document Type Key.
|
|
16
|
+
*/
|
|
17
|
+
getDataExtractionConfiguration(_tenantId: string, data: AiConfigurationResolveDataMap[typeof DocumentWorkflowStep.DataExtraction]): AiConfiguration;
|
|
18
|
+
getAssignmentConfiguration(): AiConfiguration;
|
|
19
|
+
getValidationConfiguration(): AiConfiguration;
|
|
20
|
+
}
|