@loopstack/meeting-notes-example-workflow 0.21.6 → 0.22.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/meeting-notes-example.module.d.ts.map +1 -1
- package/dist/meeting-notes-example.module.js +1 -2
- package/dist/meeting-notes-example.module.js.map +1 -1
- package/dist/meeting-notes.workflow.d.ts +2 -2
- package/dist/meeting-notes.workflow.d.ts.map +1 -1
- package/dist/meeting-notes.workflow.js +15 -19
- package/dist/meeting-notes.workflow.js.map +1 -1
- package/dist/templates/extract-notes.md +5 -0
- package/package.json +10 -34
- package/src/__tests__/meeting-notes.workflow.spec.ts +17 -23
- package/src/meeting-notes-example.module.ts +1 -2
- package/src/meeting-notes.workflow.ts +18 -15
- package/src/templates/extract-notes.md +5 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes-example.module.d.ts","sourceRoot":"","sources":["../src/meeting-notes-example.module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"meeting-notes-example.module.d.ts","sourceRoot":"","sources":["../src/meeting-notes-example.module.ts"],"names":[],"mappings":"AAMA,qBAKa,yBAAyB;CAAG"}
|
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.MeetingNotesExampleModule = void 0;
|
|
10
10
|
const common_1 = require("@nestjs/common");
|
|
11
11
|
const claude_module_1 = require("@loopstack/claude-module");
|
|
12
|
-
const core_1 = require("@loopstack/core");
|
|
13
12
|
const meeting_notes_document_1 = require("./documents/meeting-notes-document");
|
|
14
13
|
const optimized_notes_document_1 = require("./documents/optimized-notes-document");
|
|
15
14
|
const meeting_notes_workflow_1 = require("./meeting-notes.workflow");
|
|
@@ -18,7 +17,7 @@ let MeetingNotesExampleModule = class MeetingNotesExampleModule {
|
|
|
18
17
|
exports.MeetingNotesExampleModule = MeetingNotesExampleModule;
|
|
19
18
|
exports.MeetingNotesExampleModule = MeetingNotesExampleModule = __decorate([
|
|
20
19
|
(0, common_1.Module)({
|
|
21
|
-
imports: [
|
|
20
|
+
imports: [claude_module_1.ClaudeModule],
|
|
22
21
|
providers: [meeting_notes_workflow_1.MeetingNotesWorkflow, meeting_notes_document_1.MeetingNotesDocument, optimized_notes_document_1.OptimizedNotesDocument],
|
|
23
22
|
exports: [meeting_notes_workflow_1.MeetingNotesWorkflow],
|
|
24
23
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes-example.module.js","sourceRoot":"","sources":["../src/meeting-notes-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD
|
|
1
|
+
{"version":3,"file":"meeting-notes-example.module.js","sourceRoot":"","sources":["../src/meeting-notes-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD,+EAA0E;AAC1E,mFAA8E;AAC9E,qEAAgE;AAOzD,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;CAAG,CAAA;AAA5B,8DAAyB;oCAAzB,yBAAyB;IALrC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,SAAS,EAAE,CAAC,6CAAoB,EAAE,6CAAoB,EAAE,iDAAsB,CAAC;QAC/E,OAAO,EAAE,CAAC,6CAAoB,CAAC;KAChC,CAAC;GACW,yBAAyB,CAAG"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { ClaudeGenerateDocument } from '@loopstack/claude-module';
|
|
3
2
|
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
4
4
|
import { MeetingNotesDocumentSchema } from './documents/meeting-notes-document';
|
|
5
5
|
import { OptimizedMeetingNotesDocumentSchema } from './documents/optimized-notes-document';
|
|
6
6
|
export declare class MeetingNotesWorkflow extends BaseWorkflow<{
|
|
7
7
|
inputText: string;
|
|
8
8
|
}> {
|
|
9
|
-
|
|
9
|
+
llmGenerateObject: LlmGenerateObjectTool;
|
|
10
10
|
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
11
11
|
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
12
12
|
createForm(args: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes.workflow.d.ts","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"meeting-notes.workflow.d.ts","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAoD,MAAM,mBAAmB,CAAC;AAEnG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAwB,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACtG,OAAO,EAAE,mCAAmC,EAA0B,MAAM,sCAAsC,CAAC;AAEnH,qBAUa,oBAAqB,SAAQ,YAAY,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;IAE3E,iBAAiB,EAAE,qBAAqB,CAAC;IAEzC,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;IAG/D,UAAU,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE;IAStC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC;IAMhE,aAAa;IAkBb,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC;CAI3E"}
|
|
@@ -11,35 +11,31 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.MeetingNotesWorkflow = void 0;
|
|
13
13
|
const zod_1 = require("zod");
|
|
14
|
-
const
|
|
14
|
+
const zod_2 = require("zod");
|
|
15
15
|
const common_1 = require("@loopstack/common");
|
|
16
|
+
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
16
17
|
const meeting_notes_document_1 = require("./documents/meeting-notes-document");
|
|
17
18
|
const optimized_notes_document_1 = require("./documents/optimized-notes-document");
|
|
18
19
|
let MeetingNotesWorkflow = class MeetingNotesWorkflow extends common_1.BaseWorkflow {
|
|
19
|
-
|
|
20
|
+
llmGenerateObject;
|
|
20
21
|
meetingNotes;
|
|
21
22
|
optimizedNotes;
|
|
22
23
|
async createForm(args) {
|
|
23
|
-
await this.repository.save(meeting_notes_document_1.MeetingNotesDocument, {
|
|
24
|
-
text: `Unstructured Notes:\n\n${args.inputText}`,
|
|
25
|
-
}, { id: 'input' });
|
|
24
|
+
await this.repository.save(meeting_notes_document_1.MeetingNotesDocument, { text: `Unstructured Notes:\n\n${args.inputText}` }, { id: 'input' });
|
|
26
25
|
}
|
|
27
26
|
async userResponse(payload) {
|
|
28
27
|
const result = await this.repository.save(meeting_notes_document_1.MeetingNotesDocument, payload, { id: 'input' });
|
|
29
28
|
this.meetingNotes = result.content;
|
|
30
29
|
}
|
|
31
30
|
async optimizeNotes() {
|
|
32
|
-
await this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<Meeting Notes>
|
|
41
|
-
${this.meetingNotes?.text}
|
|
42
|
-
</Meeting Notes>`,
|
|
31
|
+
const result = await this.llmGenerateObject.call({
|
|
32
|
+
outputSchema: (0, zod_2.toJSONSchema)(optimized_notes_document_1.OptimizedMeetingNotesDocumentSchema),
|
|
33
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', { text: this.meetingNotes?.text }),
|
|
34
|
+
});
|
|
35
|
+
const objectResult = result.data;
|
|
36
|
+
await this.repository.save(optimized_notes_document_1.OptimizedNotesDocument, objectResult.data, {
|
|
37
|
+
id: 'final',
|
|
38
|
+
validate: 'skip',
|
|
43
39
|
});
|
|
44
40
|
}
|
|
45
41
|
async confirm(payload) {
|
|
@@ -49,9 +45,9 @@ ${this.meetingNotes?.text}
|
|
|
49
45
|
};
|
|
50
46
|
exports.MeetingNotesWorkflow = MeetingNotesWorkflow;
|
|
51
47
|
__decorate([
|
|
52
|
-
(0, common_1.InjectTool)(),
|
|
53
|
-
__metadata("design:type",
|
|
54
|
-
], MeetingNotesWorkflow.prototype, "
|
|
48
|
+
(0, common_1.InjectTool)({ provider: 'claude', model: 'claude-sonnet-4-6' }),
|
|
49
|
+
__metadata("design:type", llm_provider_module_1.LlmGenerateObjectTool)
|
|
50
|
+
], MeetingNotesWorkflow.prototype, "llmGenerateObject", void 0);
|
|
55
51
|
__decorate([
|
|
56
52
|
(0, common_1.Initial)({ to: 'waiting_for_response' }),
|
|
57
53
|
__metadata("design:type", Function),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes.workflow.js","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"meeting-notes.workflow.js","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,6BAAmC;AACnC,8CAAmG;AAEnG,wEAAuE;AACvE,+EAAsG;AACtG,mFAAmH;AAY5G,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,qBAAmC;IAE3E,iBAAiB,CAAwB;IAEzC,YAAY,CAA8C;IAC1D,cAAc,CAAuD;IAG/D,AAAN,KAAK,CAAC,UAAU,CAAC,IAA2B;QAC1C,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CACxB,6CAAoB,EACpB,EAAE,IAAI,EAAE,0BAA0B,IAAI,CAAC,SAAS,EAAE,EAAE,EACpD,EAAE,EAAE,EAAE,OAAO,EAAE,CAChB,CAAC;IACJ,CAAC;IAGK,AAAN,KAAK,CAAC,YAAY,CAAC,OAAmD;QACpE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,6CAAoB,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1F,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,OAAqD,CAAC;IACnF,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa;QACjB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAC/C,YAAY,EAAE,IAAA,kBAAY,EAAC,8DAAmC,CAA4B;YAC1F,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,6BAA6B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;SAClG,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,MAAM,CAAC,IAA+B,CAAC;QAC5D,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CACxB,iDAAsB,EACtB,YAAY,CAAC,IAA2D,EACxE;YACE,EAAE,EAAE,OAAO;YACX,QAAQ,EAAE,MAAM;SACjB,CACF,CAAC;IACJ,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAC,OAA4D;QACxE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,iDAAsB,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,OAA8D,CAAC;IAC9F,CAAC;CACF,CAAA;AA7CY,oDAAoB;AAE/B;IADC,IAAA,mBAAU,EAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;8BAC5C,2CAAqB;+DAAC;AAMnC;IADL,IAAA,gBAAO,EAAC,EAAE,EAAE,EAAE,sBAAsB,EAAE,CAAC;;;;sDAOvC;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,mDAA0B,EAAE,CAAC;;;;wDAIrH;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC;;;;yDAgBhE;AAGK;IADL,IAAA,cAAK,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,8DAAmC,EAAE,CAAC;;;;mDAI3F;+BA5CU,oBAAoB;IAVhC,IAAA,iBAAQ,EAAC;QACR,QAAQ,EAAE,SAAS,GAAG,wBAAwB;QAC9C,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,OAAC;iBACT,MAAM,EAAE;iBACR,OAAO,CACN,2IAA2I,CAC5I;SACJ,CAAC;KACH,CAAC;GACW,oBAAoB,CA6ChC"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"summary",
|
|
10
10
|
"workflow"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.22.0",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Jakob Klippel",
|
|
@@ -26,13 +26,14 @@
|
|
|
26
26
|
"compile": "tsc --noEmit",
|
|
27
27
|
"format": "prettier --write .",
|
|
28
28
|
"lint": "eslint .",
|
|
29
|
-
"test": "
|
|
29
|
+
"test": "vitest run",
|
|
30
30
|
"watch": "nest build --watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@loopstack/claude-module": "^0.
|
|
34
|
-
"@loopstack/
|
|
35
|
-
"@loopstack/
|
|
33
|
+
"@loopstack/claude-module": "^0.24.0",
|
|
34
|
+
"@loopstack/llm-provider-module": "^0.3.0",
|
|
35
|
+
"@loopstack/common": "^0.30.0",
|
|
36
|
+
"@loopstack/core": "^0.30.0",
|
|
36
37
|
"@nestjs/common": "^11.1.19",
|
|
37
38
|
"zod": "^4.3.6"
|
|
38
39
|
},
|
|
@@ -40,34 +41,9 @@
|
|
|
40
41
|
"dist",
|
|
41
42
|
"src"
|
|
42
43
|
],
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"transform": {
|
|
48
|
-
"^.+\\.ts$": "ts-jest"
|
|
49
|
-
},
|
|
50
|
-
"testTimeout": 10000,
|
|
51
|
-
"forceExit": true,
|
|
52
|
-
"maxWorkers": 1
|
|
53
|
-
},
|
|
54
|
-
"loopstack": {
|
|
55
|
-
"modules": [
|
|
56
|
-
{
|
|
57
|
-
"path": "src/meeting-notes-example.module.ts",
|
|
58
|
-
"className": "MeetingNotesExampleModule"
|
|
59
|
-
}
|
|
60
|
-
],
|
|
61
|
-
"workflows": [
|
|
62
|
-
{
|
|
63
|
-
"path": "src/meeting-notes.workflow.ts",
|
|
64
|
-
"className": "MeetingNotesWorkflow",
|
|
65
|
-
"propertyName": "meetingNotes"
|
|
66
|
-
}
|
|
67
|
-
],
|
|
68
|
-
"installModes": [
|
|
69
|
-
"add",
|
|
70
|
-
"install"
|
|
71
|
-
]
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"vitest": "^4.1.6",
|
|
46
|
+
"@swc/core": "^1.15.33",
|
|
47
|
+
"unplugin-swc": "^1.5.9"
|
|
72
48
|
}
|
|
73
49
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { TestingModule } from '@nestjs/testing';
|
|
2
|
-
import {
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
import { ClaudeModule } from '@loopstack/claude-module';
|
|
3
4
|
import { RunContext, WorkflowEntity, getBlockTools } from '@loopstack/common';
|
|
4
|
-
import {
|
|
5
|
+
import { WorkflowProcessorService } from '@loopstack/core';
|
|
6
|
+
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
5
7
|
import { ToolMock, createStatelessContext, createWorkflowTest } from '@loopstack/testing';
|
|
6
8
|
import { MeetingNotesDocument } from '../documents/meeting-notes-document';
|
|
7
9
|
import { OptimizedNotesDocument } from '../documents/optimized-notes-document';
|
|
@@ -11,22 +13,20 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
11
13
|
let module: TestingModule;
|
|
12
14
|
let workflow: MeetingNotesWorkflow;
|
|
13
15
|
let processor: WorkflowProcessorService;
|
|
14
|
-
|
|
15
|
-
let mockClaudeGenerateDocument: ToolMock;
|
|
16
|
+
let mockLlmGenerateObject: ToolMock;
|
|
16
17
|
|
|
17
18
|
beforeEach(async () => {
|
|
18
19
|
module = await createWorkflowTest()
|
|
19
20
|
.forWorkflow(MeetingNotesWorkflow)
|
|
20
|
-
.withImports(
|
|
21
|
+
.withImports(ClaudeModule)
|
|
21
22
|
.withProvider(MeetingNotesDocument)
|
|
22
23
|
.withProvider(OptimizedNotesDocument)
|
|
23
|
-
.withToolOverride(
|
|
24
|
+
.withToolOverride(LlmGenerateObjectTool)
|
|
24
25
|
.compile();
|
|
25
26
|
|
|
26
27
|
workflow = module.get(MeetingNotesWorkflow);
|
|
27
28
|
processor = module.get(WorkflowProcessorService);
|
|
28
|
-
|
|
29
|
-
mockClaudeGenerateDocument = module.get(ClaudeGenerateDocument);
|
|
29
|
+
mockLlmGenerateObject = module.get(LlmGenerateObjectTool);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
afterEach(async () => {
|
|
@@ -36,14 +36,13 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
36
36
|
describe('initialization', () => {
|
|
37
37
|
it('should be defined with correct tools', () => {
|
|
38
38
|
expect(workflow).toBeDefined();
|
|
39
|
-
expect(getBlockTools(workflow)).toContain('
|
|
39
|
+
expect(getBlockTools(workflow)).toContain('llmGenerateObject');
|
|
40
40
|
});
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
describe('initial step', () => {
|
|
44
44
|
it('should execute initial step and stop at waiting_for_response', async () => {
|
|
45
45
|
const context = createStatelessContext();
|
|
46
|
-
|
|
47
46
|
const result = await processor.process(workflow, {}, context);
|
|
48
47
|
|
|
49
48
|
expect(result.hasError).toBe(false);
|
|
@@ -63,12 +62,10 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
63
62
|
|
|
64
63
|
it('should use custom input text when provided', async () => {
|
|
65
64
|
const context = createStatelessContext();
|
|
66
|
-
|
|
67
65
|
const result = await processor.process(workflow, { inputText: 'Custom meeting notes here' }, context);
|
|
68
66
|
|
|
69
67
|
expect(result.hasError).toBe(false);
|
|
70
68
|
expect(result.stop).toBe(true);
|
|
71
|
-
|
|
72
69
|
expect(result.documents[0]).toEqual(
|
|
73
70
|
expect.objectContaining({
|
|
74
71
|
content: expect.objectContaining({
|
|
@@ -83,7 +80,9 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
83
80
|
it('should process user response and call LLM to optimize notes', async () => {
|
|
84
81
|
const workflowId = '00000000-0000-0000-0000-000000000001';
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
mockLlmGenerateObject.call.mockResolvedValue({
|
|
84
|
+
data: { data: {} },
|
|
85
|
+
});
|
|
87
86
|
|
|
88
87
|
const context = {
|
|
89
88
|
workflowEntity: {
|
|
@@ -106,7 +105,6 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
106
105
|
expect(result.stop).toBe(true);
|
|
107
106
|
expect(result.place).toBe('notes_optimized');
|
|
108
107
|
|
|
109
|
-
// User response should have been saved as document
|
|
110
108
|
expect(result.documents).toEqual(
|
|
111
109
|
expect.arrayContaining([
|
|
112
110
|
expect.objectContaining({
|
|
@@ -115,15 +113,13 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
115
113
|
]),
|
|
116
114
|
);
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
expect(
|
|
120
|
-
expect(mockClaudeGenerateDocument.call).toHaveBeenCalledWith(
|
|
116
|
+
expect(mockLlmGenerateObject.call).toHaveBeenCalledTimes(1);
|
|
117
|
+
expect(mockLlmGenerateObject.call).toHaveBeenCalledWith(
|
|
121
118
|
expect.objectContaining({
|
|
122
|
-
|
|
123
|
-
response: expect.objectContaining({ id: 'final' }),
|
|
119
|
+
outputSchema: expect.any(Object),
|
|
124
120
|
prompt: expect.stringContaining('meeting notes'),
|
|
125
121
|
}),
|
|
126
|
-
|
|
122
|
+
expect.anything(),
|
|
127
123
|
);
|
|
128
124
|
});
|
|
129
125
|
});
|
|
@@ -161,7 +157,6 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
161
157
|
expect(result.stop).toBe(false);
|
|
162
158
|
expect(result.place).toBe('end');
|
|
163
159
|
|
|
164
|
-
// Confirmed payload should have been saved as OptimizedNotesDocument
|
|
165
160
|
expect(result.documents).toEqual(
|
|
166
161
|
expect.arrayContaining([
|
|
167
162
|
expect.objectContaining({
|
|
@@ -170,8 +165,7 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
170
165
|
]),
|
|
171
166
|
);
|
|
172
167
|
|
|
173
|
-
|
|
174
|
-
expect(mockClaudeGenerateDocument.call).not.toHaveBeenCalled();
|
|
168
|
+
expect(mockLlmGenerateObject.call).not.toHaveBeenCalled();
|
|
175
169
|
});
|
|
176
170
|
});
|
|
177
171
|
});
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
2
|
import { ClaudeModule } from '@loopstack/claude-module';
|
|
3
|
-
import { LoopCoreModule } from '@loopstack/core';
|
|
4
3
|
import { MeetingNotesDocument } from './documents/meeting-notes-document';
|
|
5
4
|
import { OptimizedNotesDocument } from './documents/optimized-notes-document';
|
|
6
5
|
import { MeetingNotesWorkflow } from './meeting-notes.workflow';
|
|
7
6
|
|
|
8
7
|
@Module({
|
|
9
|
-
imports: [
|
|
8
|
+
imports: [ClaudeModule],
|
|
10
9
|
providers: [MeetingNotesWorkflow, MeetingNotesDocument, OptimizedNotesDocument],
|
|
11
10
|
exports: [MeetingNotesWorkflow],
|
|
12
11
|
})
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { toJSONSchema } from 'zod';
|
|
3
3
|
import { BaseWorkflow, Final, Initial, InjectTool, Transition, Workflow } from '@loopstack/common';
|
|
4
|
+
import type { LlmGenerateObjectResult } from '@loopstack/llm-provider-module';
|
|
5
|
+
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
4
6
|
import { MeetingNotesDocument, MeetingNotesDocumentSchema } from './documents/meeting-notes-document';
|
|
5
7
|
import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './documents/optimized-notes-document';
|
|
6
8
|
|
|
@@ -15,7 +17,8 @@ import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './d
|
|
|
15
17
|
}),
|
|
16
18
|
})
|
|
17
19
|
export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
18
|
-
@InjectTool(
|
|
20
|
+
@InjectTool({ provider: 'claude', model: 'claude-sonnet-4-6' })
|
|
21
|
+
llmGenerateObject: LlmGenerateObjectTool;
|
|
19
22
|
|
|
20
23
|
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
21
24
|
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
@@ -24,9 +27,7 @@ export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
|
24
27
|
async createForm(args: { inputText: string }) {
|
|
25
28
|
await this.repository.save(
|
|
26
29
|
MeetingNotesDocument,
|
|
27
|
-
{
|
|
28
|
-
text: `Unstructured Notes:\n\n${args.inputText}`,
|
|
29
|
-
},
|
|
30
|
+
{ text: `Unstructured Notes:\n\n${args.inputText}` },
|
|
30
31
|
{ id: 'input' },
|
|
31
32
|
);
|
|
32
33
|
}
|
|
@@ -39,18 +40,20 @@ export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
|
39
40
|
|
|
40
41
|
@Transition({ from: 'response_received', to: 'notes_optimized' })
|
|
41
42
|
async optimizeNotes() {
|
|
42
|
-
await this.
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const result = await this.llmGenerateObject.call({
|
|
44
|
+
outputSchema: toJSONSchema(OptimizedMeetingNotesDocumentSchema) as Record<string, unknown>,
|
|
45
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', { text: this.meetingNotes?.text }),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const objectResult = result.data as LlmGenerateObjectResult;
|
|
49
|
+
await this.repository.save(
|
|
50
|
+
OptimizedNotesDocument,
|
|
51
|
+
objectResult.data as z.infer<typeof OptimizedMeetingNotesDocumentSchema>,
|
|
52
|
+
{
|
|
45
53
|
id: 'final',
|
|
46
|
-
|
|
54
|
+
validate: 'skip',
|
|
47
55
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<Meeting Notes>
|
|
51
|
-
${this.meetingNotes?.text}
|
|
52
|
-
</Meeting Notes>`,
|
|
53
|
-
});
|
|
56
|
+
);
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
@Final({ from: 'notes_optimized', wait: true, schema: OptimizedMeetingNotesDocumentSchema })
|