@loopstack/meeting-notes-example-workflow 0.22.1 → 0.23.1
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/README.md +5 -5
- package/dist/documents/meeting-notes-document.js +1 -1
- package/dist/documents/meeting-notes-document.js.map +1 -1
- package/dist/documents/meeting-notes-document.yaml +10 -13
- package/dist/documents/optimized-notes-document.js +1 -1
- package/dist/documents/optimized-notes-document.js.map +1 -1
- package/dist/documents/optimized-notes-document.yaml +33 -36
- package/dist/meeting-notes.workflow.d.ts +13 -10
- package/dist/meeting-notes.workflow.d.ts.map +1 -1
- package/dist/meeting-notes.workflow.js +31 -26
- package/dist/meeting-notes.workflow.js.map +1 -1
- package/package.json +4 -5
- package/src/__tests__/meeting-notes.workflow.spec.ts +7 -8
- package/src/documents/meeting-notes-document.ts +1 -1
- package/src/documents/meeting-notes-document.yaml +10 -13
- package/src/documents/optimized-notes-document.ts +1 -1
- package/src/documents/optimized-notes-document.yaml +33 -36
- package/src/meeting-notes.workflow.ts +43 -24
- package/dist/meeting-notes.ui.yaml +0 -10
- package/src/meeting-notes.ui.yaml +0 -10
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Use `wait: true` with a `schema` to pause the workflow and wait for user interac
|
|
|
66
66
|
```typescript
|
|
67
67
|
@Transition({ from: 'waiting_for_response', to: 'response_received', wait: true, schema: MeetingNotesDocumentSchema })
|
|
68
68
|
async userResponse(payload: z.infer<typeof MeetingNotesDocumentSchema>) {
|
|
69
|
-
const result = await this.
|
|
69
|
+
const result = await this.documentStore.save(MeetingNotesDocument, payload, { id: 'input' });
|
|
70
70
|
this.meetingNotes = result.content as z.infer<typeof MeetingNotesDocumentSchema>;
|
|
71
71
|
}
|
|
72
72
|
```
|
|
@@ -179,12 +179,12 @@ async optimizeNotes() {
|
|
|
179
179
|
|
|
180
180
|
#### 7. Final Confirmation with Wait
|
|
181
181
|
|
|
182
|
-
Use `@
|
|
182
|
+
Use terminal `@Transition` with `wait: true` to create a review step before the workflow ends:
|
|
183
183
|
|
|
184
184
|
```typescript
|
|
185
|
-
@
|
|
185
|
+
@Transition({ from: 'notes_optimized', to: 'end', wait: true, schema: OptimizedMeetingNotesDocumentSchema })
|
|
186
186
|
async confirm(payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>) {
|
|
187
|
-
const result = await this.
|
|
187
|
+
const result = await this.documentStore.save(OptimizedNotesDocument, payload, { id: 'final' });
|
|
188
188
|
this.optimizedNotes = result.content as z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
189
189
|
}
|
|
190
190
|
```
|
|
@@ -193,7 +193,7 @@ async confirm(payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>) {
|
|
|
193
193
|
|
|
194
194
|
This workflow uses the following Loopstack modules:
|
|
195
195
|
|
|
196
|
-
- `@loopstack/common` - Core framework decorators (`BaseWorkflow`, `@Workflow`, `@
|
|
196
|
+
- `@loopstack/common` - Core framework decorators (`BaseWorkflow`, `@Workflow`, `@Transition`, `@Transition`, terminal `@Transition`, `@InjectTool`, `Document`)
|
|
197
197
|
- `@loopstack/claude-module` - Provides `ClaudeGenerateDocument` tool for AI-powered document generation
|
|
198
198
|
|
|
199
199
|
## About
|
|
@@ -19,7 +19,7 @@ exports.MeetingNotesDocument = MeetingNotesDocument;
|
|
|
19
19
|
exports.MeetingNotesDocument = MeetingNotesDocument = __decorate([
|
|
20
20
|
(0, common_1.Document)({
|
|
21
21
|
schema: exports.MeetingNotesDocumentSchema,
|
|
22
|
-
|
|
22
|
+
widget: __dirname + '/meeting-notes-document.yaml',
|
|
23
23
|
})
|
|
24
24
|
], MeetingNotesDocument);
|
|
25
25
|
//# sourceMappingURL=meeting-notes-document.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes-document.js","sourceRoot":"","sources":["../../src/documents/meeting-notes-document.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA6C;AAEhC,QAAA,0BAA0B,GAAG,OAAC,CAAC,MAAM,CAAC;IACjD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAMI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAC/B,IAAI,CAAS;CACd,CAAA;AAFY,oDAAoB;+BAApB,oBAAoB;IAJhC,IAAA,iBAAQ,EAAC;QACR,MAAM,EAAE,kCAA0B;QAClC,
|
|
1
|
+
{"version":3,"file":"meeting-notes-document.js","sourceRoot":"","sources":["../../src/documents/meeting-notes-document.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA6C;AAEhC,QAAA,0BAA0B,GAAG,OAAC,CAAC,MAAM,CAAC;IACjD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAMI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAC/B,IAAI,CAAS;CACd,CAAA;AAFY,oDAAoB;+BAApB,oBAAoB;IAJhC,IAAA,iBAAQ,EAAC;QACR,MAAM,EAAE,kCAA0B;QAClC,MAAM,EAAE,SAAS,GAAG,8BAA8B;KACnD,CAAC;GACW,oBAAoB,CAEhC"}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- type: button
|
|
12
|
-
transition: userResponse
|
|
13
|
-
label: 'Optimize Notes'
|
|
1
|
+
widget: form
|
|
2
|
+
options:
|
|
3
|
+
properties:
|
|
4
|
+
text:
|
|
5
|
+
title: Text
|
|
6
|
+
widget: textarea
|
|
7
|
+
actions:
|
|
8
|
+
- type: button
|
|
9
|
+
transition: userResponse
|
|
10
|
+
label: 'Optimize Notes'
|
|
@@ -27,7 +27,7 @@ exports.OptimizedNotesDocument = OptimizedNotesDocument;
|
|
|
27
27
|
exports.OptimizedNotesDocument = OptimizedNotesDocument = __decorate([
|
|
28
28
|
(0, common_1.Document)({
|
|
29
29
|
schema: exports.OptimizedMeetingNotesDocumentSchema,
|
|
30
|
-
|
|
30
|
+
widget: __dirname + '/optimized-notes-document.yaml',
|
|
31
31
|
})
|
|
32
32
|
], OptimizedNotesDocument);
|
|
33
33
|
//# sourceMappingURL=optimized-notes-document.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimized-notes-document.js","sourceRoot":"","sources":["../../src/documents/optimized-notes-document.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA6C;AAEhC,QAAA,mCAAmC,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1D,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IACjC,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAC9B,WAAW,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAMI,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACjC,IAAI,CAAS;IACb,OAAO,CAAS;IAChB,YAAY,CAAW;IACvB,SAAS,CAAW;IACpB,WAAW,CAAW;CACvB,CAAA;AANY,wDAAsB;iCAAtB,sBAAsB;IAJlC,IAAA,iBAAQ,EAAC;QACR,MAAM,EAAE,2CAAmC;QAC3C,
|
|
1
|
+
{"version":3,"file":"optimized-notes-document.js","sourceRoot":"","sources":["../../src/documents/optimized-notes-document.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA6C;AAEhC,QAAA,mCAAmC,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1D,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IACjC,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAC9B,WAAW,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAMI,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACjC,IAAI,CAAS;IACb,OAAO,CAAS;IAChB,YAAY,CAAW;IACvB,SAAS,CAAW;IACpB,WAAW,CAAW;CACvB,CAAA;AANY,wDAAsB;iCAAtB,sBAAsB;IAJlC,IAAA,iBAAQ,EAAC;QACR,MAAM,EAAE,2CAAmC;QAC3C,MAAM,EAAE,SAAS,GAAG,gCAAgC;KACrD,CAAC;GACW,sBAAsB,CAMlC"}
|
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- type: button
|
|
35
|
-
transition: confirm
|
|
36
|
-
label: 'Confirm'
|
|
1
|
+
widget: form
|
|
2
|
+
options:
|
|
3
|
+
order:
|
|
4
|
+
- date
|
|
5
|
+
- summary
|
|
6
|
+
- participants
|
|
7
|
+
- decisions
|
|
8
|
+
- actionItems
|
|
9
|
+
properties:
|
|
10
|
+
date:
|
|
11
|
+
title: Date
|
|
12
|
+
summary:
|
|
13
|
+
title: Summary
|
|
14
|
+
widget: textarea
|
|
15
|
+
participants:
|
|
16
|
+
title: Participants
|
|
17
|
+
collapsed: true
|
|
18
|
+
items:
|
|
19
|
+
title: Participant
|
|
20
|
+
decisions:
|
|
21
|
+
title: Decisions
|
|
22
|
+
collapsed: true
|
|
23
|
+
items:
|
|
24
|
+
title: Decision
|
|
25
|
+
actionItems:
|
|
26
|
+
title: Action Items
|
|
27
|
+
collapsed: true
|
|
28
|
+
items:
|
|
29
|
+
title: Action Item
|
|
30
|
+
actions:
|
|
31
|
+
- type: button
|
|
32
|
+
transition: confirm
|
|
33
|
+
label: 'Confirm'
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
4
|
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
4
5
|
import { MeetingNotesDocumentSchema } from './documents/meeting-notes-document';
|
|
5
6
|
import { OptimizedMeetingNotesDocumentSchema } from './documents/optimized-notes-document';
|
|
6
|
-
|
|
7
|
-
inputText: string;
|
|
8
|
-
}> {
|
|
9
|
-
llmGenerateObject: LlmGenerateObjectTool;
|
|
7
|
+
interface MeetingNotesState {
|
|
10
8
|
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
11
9
|
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
12
|
-
createForm(args: {
|
|
13
|
-
inputText: string;
|
|
14
|
-
}): Promise<void>;
|
|
15
|
-
userResponse(payload: z.infer<typeof MeetingNotesDocumentSchema>): Promise<void>;
|
|
16
|
-
optimizeNotes(): Promise<void>;
|
|
17
|
-
confirm(payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>): Promise<void>;
|
|
18
10
|
}
|
|
11
|
+
export declare class MeetingNotesWorkflow extends BaseWorkflow<{
|
|
12
|
+
inputText: string;
|
|
13
|
+
}, MeetingNotesState> {
|
|
14
|
+
private readonly llmGenerateObject;
|
|
15
|
+
constructor(llmGenerateObject: LlmGenerateObjectTool);
|
|
16
|
+
createForm(state: MeetingNotesState, ctx: LoopstackContext): Promise<MeetingNotesState>;
|
|
17
|
+
userResponse(state: MeetingNotesState, payload: z.infer<typeof MeetingNotesDocumentSchema>): Promise<MeetingNotesState>;
|
|
18
|
+
optimizeNotes(state: MeetingNotesState): Promise<MeetingNotesState>;
|
|
19
|
+
confirm(state: MeetingNotesState, payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>): Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
19
22
|
//# sourceMappingURL=meeting-notes.workflow.d.ts.map
|
|
@@ -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;AAExB,OAAO,EAAE,YAAY,
|
|
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,EAAwB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAwB,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACtG,OAAO,EAAE,mCAAmC,EAA0B,MAAM,sCAAsC,CAAC;AAEnH,UAAU,iBAAiB;IACzB,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;CACtE;AAED,qBAWa,oBAAqB,SAAQ,YAAY,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,iBAAiB,CAAC;IAClF,OAAO,CAAC,QAAQ,CAAC,iBAAiB;gBAAjB,iBAAiB,EAAE,qBAAqB;IAK/D,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAWvF,YAAY,CAChB,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,GAClD,OAAO,CAAC,iBAAiB,CAAC;IAMvB,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAwBnE,OAAO,CACX,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,GAC3D,OAAO,CAAC,OAAO,CAAC;CAIpB"}
|
|
@@ -18,68 +18,73 @@ const meeting_notes_document_1 = require("./documents/meeting-notes-document");
|
|
|
18
18
|
const optimized_notes_document_1 = require("./documents/optimized-notes-document");
|
|
19
19
|
let MeetingNotesWorkflow = class MeetingNotesWorkflow extends common_1.BaseWorkflow {
|
|
20
20
|
llmGenerateObject;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
await this.repository.save(meeting_notes_document_1.MeetingNotesDocument, { text: `Unstructured Notes:\n\n${args.inputText}` }, { id: 'input' });
|
|
21
|
+
constructor(llmGenerateObject) {
|
|
22
|
+
super();
|
|
23
|
+
this.llmGenerateObject = llmGenerateObject;
|
|
25
24
|
}
|
|
26
|
-
async
|
|
27
|
-
const
|
|
28
|
-
this.
|
|
25
|
+
async createForm(state, ctx) {
|
|
26
|
+
const args = ctx.args;
|
|
27
|
+
await this.documentStore.save(meeting_notes_document_1.MeetingNotesDocument, { text: `Unstructured Notes:\n\n${args.inputText}` }, { id: 'input' });
|
|
28
|
+
return state;
|
|
29
29
|
}
|
|
30
|
-
async
|
|
30
|
+
async userResponse(state, payload) {
|
|
31
|
+
const result = await this.documentStore.save(meeting_notes_document_1.MeetingNotesDocument, payload, { id: 'input' });
|
|
32
|
+
return { ...state, meetingNotes: result.content };
|
|
33
|
+
}
|
|
34
|
+
async optimizeNotes(state) {
|
|
31
35
|
const result = await this.llmGenerateObject.call({
|
|
32
36
|
outputSchema: (0, zod_2.toJSONSchema)(optimized_notes_document_1.OptimizedMeetingNotesDocumentSchema),
|
|
33
|
-
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
34
|
-
|
|
37
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
38
|
+
text: state.meetingNotes?.text,
|
|
39
|
+
}),
|
|
40
|
+
}, { config: { provider: 'claude', model: 'claude-sonnet-4-6' } });
|
|
35
41
|
const objectResult = result.data;
|
|
36
|
-
await this.
|
|
42
|
+
await this.documentStore.save(optimized_notes_document_1.OptimizedNotesDocument, objectResult.data, {
|
|
37
43
|
id: 'final',
|
|
38
44
|
validate: 'skip',
|
|
39
45
|
});
|
|
46
|
+
return state;
|
|
40
47
|
}
|
|
41
|
-
async confirm(payload) {
|
|
42
|
-
const result = await this.
|
|
43
|
-
|
|
48
|
+
async confirm(state, payload) {
|
|
49
|
+
const result = await this.documentStore.save(optimized_notes_document_1.OptimizedNotesDocument, payload, { id: 'final' });
|
|
50
|
+
return { optimizedNotes: result.content };
|
|
44
51
|
}
|
|
45
52
|
};
|
|
46
53
|
exports.MeetingNotesWorkflow = MeetingNotesWorkflow;
|
|
47
54
|
__decorate([
|
|
48
|
-
(0, common_1.
|
|
49
|
-
__metadata("design:type", llm_provider_module_1.LlmGenerateObjectTool)
|
|
50
|
-
], MeetingNotesWorkflow.prototype, "llmGenerateObject", void 0);
|
|
51
|
-
__decorate([
|
|
52
|
-
(0, common_1.Initial)({ to: 'waiting_for_response' }),
|
|
55
|
+
(0, common_1.Transition)({ to: 'waiting_for_response' }),
|
|
53
56
|
__metadata("design:type", Function),
|
|
54
|
-
__metadata("design:paramtypes", [Object]),
|
|
57
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
55
58
|
__metadata("design:returntype", Promise)
|
|
56
59
|
], MeetingNotesWorkflow.prototype, "createForm", null);
|
|
57
60
|
__decorate([
|
|
58
61
|
(0, common_1.Transition)({ from: 'waiting_for_response', to: 'response_received', wait: true, schema: meeting_notes_document_1.MeetingNotesDocumentSchema }),
|
|
59
62
|
__metadata("design:type", Function),
|
|
60
|
-
__metadata("design:paramtypes", [Object]),
|
|
63
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
61
64
|
__metadata("design:returntype", Promise)
|
|
62
65
|
], MeetingNotesWorkflow.prototype, "userResponse", null);
|
|
63
66
|
__decorate([
|
|
64
67
|
(0, common_1.Transition)({ from: 'response_received', to: 'notes_optimized' }),
|
|
65
68
|
__metadata("design:type", Function),
|
|
66
|
-
__metadata("design:paramtypes", []),
|
|
69
|
+
__metadata("design:paramtypes", [Object]),
|
|
67
70
|
__metadata("design:returntype", Promise)
|
|
68
71
|
], MeetingNotesWorkflow.prototype, "optimizeNotes", null);
|
|
69
72
|
__decorate([
|
|
70
|
-
(0, common_1.
|
|
73
|
+
(0, common_1.Transition)({ from: 'notes_optimized', to: 'end', wait: true, schema: optimized_notes_document_1.OptimizedMeetingNotesDocumentSchema }),
|
|
71
74
|
__metadata("design:type", Function),
|
|
72
|
-
__metadata("design:paramtypes", [Object]),
|
|
75
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
73
76
|
__metadata("design:returntype", Promise)
|
|
74
77
|
], MeetingNotesWorkflow.prototype, "confirm", null);
|
|
75
78
|
exports.MeetingNotesWorkflow = MeetingNotesWorkflow = __decorate([
|
|
76
79
|
(0, common_1.Workflow)({
|
|
77
|
-
|
|
80
|
+
title: 'Human-in-the-loop Demo (Meeting Notes Optimizer)',
|
|
81
|
+
description: 'A demo workflow to demonstrate how to use AI to structure meeting notes.',
|
|
78
82
|
schema: zod_1.z.object({
|
|
79
83
|
inputText: zod_1.z
|
|
80
84
|
.string()
|
|
81
85
|
.default('- meeting 1.1.2025\n- budget: need 2 cut costs sarah said\n- hire new person?? --> marketing\n- vendor pricing - follow up needed by anna'),
|
|
82
86
|
}),
|
|
83
|
-
})
|
|
87
|
+
}),
|
|
88
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateObjectTool])
|
|
84
89
|
], MeetingNotesWorkflow);
|
|
85
90
|
//# sourceMappingURL=meeting-notes.workflow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meeting-notes.workflow.js","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,6BAAmC;AACnC,
|
|
1
|
+
{"version":3,"file":"meeting-notes.workflow.js","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"summary",
|
|
10
10
|
"workflow"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.23.1",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Jakob Klippel",
|
|
@@ -30,10 +30,9 @@
|
|
|
30
30
|
"watch": "nest build --watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@loopstack/claude-module": "^0.
|
|
34
|
-
"@loopstack/llm-provider-module": "^0.
|
|
35
|
-
"@loopstack/common": "^0.
|
|
36
|
-
"@loopstack/core": "^0.31.0",
|
|
33
|
+
"@loopstack/claude-module": "^0.25.0",
|
|
34
|
+
"@loopstack/llm-provider-module": "^0.4.0",
|
|
35
|
+
"@loopstack/common": "^0.32.1",
|
|
37
36
|
"@nestjs/common": "^11.1.19",
|
|
38
37
|
"zod": "^4.3.6"
|
|
39
38
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TestingModule } from '@nestjs/testing';
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
3
|
import { ClaudeModule } from '@loopstack/claude-module';
|
|
4
|
-
import { RunContext, WorkflowEntity
|
|
4
|
+
import { RunContext, WorkflowEntity } from '@loopstack/common';
|
|
5
5
|
import { WorkflowProcessorService } from '@loopstack/core';
|
|
6
|
-
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
6
|
+
import { LlmGenerateObjectTool, LlmProviderModule } from '@loopstack/llm-provider-module';
|
|
7
7
|
import { ToolMock, createStatelessContext, createWorkflowTest } from '@loopstack/testing';
|
|
8
8
|
import { MeetingNotesDocument } from '../documents/meeting-notes-document';
|
|
9
9
|
import { OptimizedNotesDocument } from '../documents/optimized-notes-document';
|
|
@@ -18,7 +18,7 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
18
18
|
beforeEach(async () => {
|
|
19
19
|
module = await createWorkflowTest()
|
|
20
20
|
.forWorkflow(MeetingNotesWorkflow)
|
|
21
|
-
.withImports(ClaudeModule)
|
|
21
|
+
.withImports(LlmProviderModule.forRoot({}), ClaudeModule)
|
|
22
22
|
.withProvider(MeetingNotesDocument)
|
|
23
23
|
.withProvider(OptimizedNotesDocument)
|
|
24
24
|
.withToolOverride(LlmGenerateObjectTool)
|
|
@@ -34,9 +34,8 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
describe('initialization', () => {
|
|
37
|
-
it('should be defined
|
|
37
|
+
it('should be defined', () => {
|
|
38
38
|
expect(workflow).toBeDefined();
|
|
39
|
-
expect(getBlockTools(workflow)).toContain('llmGenerateObject');
|
|
40
39
|
});
|
|
41
40
|
});
|
|
42
41
|
|
|
@@ -52,7 +51,7 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
52
51
|
expect(result.documents).toHaveLength(1);
|
|
53
52
|
expect(result.documents[0]).toEqual(
|
|
54
53
|
expect.objectContaining({
|
|
55
|
-
|
|
54
|
+
documentName: 'meeting_notes',
|
|
56
55
|
content: expect.objectContaining({
|
|
57
56
|
text: expect.stringContaining('1.1.2025'),
|
|
58
57
|
}),
|
|
@@ -108,7 +107,7 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
108
107
|
expect(result.documents).toEqual(
|
|
109
108
|
expect.arrayContaining([
|
|
110
109
|
expect.objectContaining({
|
|
111
|
-
|
|
110
|
+
documentName: 'meeting_notes',
|
|
112
111
|
}),
|
|
113
112
|
]),
|
|
114
113
|
);
|
|
@@ -160,7 +159,7 @@ describe('MeetingNotesWorkflow', () => {
|
|
|
160
159
|
expect(result.documents).toEqual(
|
|
161
160
|
expect.arrayContaining([
|
|
162
161
|
expect.objectContaining({
|
|
163
|
-
|
|
162
|
+
documentName: 'optimized_notes',
|
|
164
163
|
}),
|
|
165
164
|
]),
|
|
166
165
|
);
|
|
@@ -7,7 +7,7 @@ export const MeetingNotesDocumentSchema = z.object({
|
|
|
7
7
|
|
|
8
8
|
@Document({
|
|
9
9
|
schema: MeetingNotesDocumentSchema,
|
|
10
|
-
|
|
10
|
+
widget: __dirname + '/meeting-notes-document.yaml',
|
|
11
11
|
})
|
|
12
12
|
export class MeetingNotesDocument {
|
|
13
13
|
text: string;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- type: button
|
|
12
|
-
transition: userResponse
|
|
13
|
-
label: 'Optimize Notes'
|
|
1
|
+
widget: form
|
|
2
|
+
options:
|
|
3
|
+
properties:
|
|
4
|
+
text:
|
|
5
|
+
title: Text
|
|
6
|
+
widget: textarea
|
|
7
|
+
actions:
|
|
8
|
+
- type: button
|
|
9
|
+
transition: userResponse
|
|
10
|
+
label: 'Optimize Notes'
|
|
@@ -11,7 +11,7 @@ export const OptimizedMeetingNotesDocumentSchema = z.object({
|
|
|
11
11
|
|
|
12
12
|
@Document({
|
|
13
13
|
schema: OptimizedMeetingNotesDocumentSchema,
|
|
14
|
-
|
|
14
|
+
widget: __dirname + '/optimized-notes-document.yaml',
|
|
15
15
|
})
|
|
16
16
|
export class OptimizedNotesDocument {
|
|
17
17
|
date: string;
|
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- type: button
|
|
35
|
-
transition: confirm
|
|
36
|
-
label: 'Confirm'
|
|
1
|
+
widget: form
|
|
2
|
+
options:
|
|
3
|
+
order:
|
|
4
|
+
- date
|
|
5
|
+
- summary
|
|
6
|
+
- participants
|
|
7
|
+
- decisions
|
|
8
|
+
- actionItems
|
|
9
|
+
properties:
|
|
10
|
+
date:
|
|
11
|
+
title: Date
|
|
12
|
+
summary:
|
|
13
|
+
title: Summary
|
|
14
|
+
widget: textarea
|
|
15
|
+
participants:
|
|
16
|
+
title: Participants
|
|
17
|
+
collapsed: true
|
|
18
|
+
items:
|
|
19
|
+
title: Participant
|
|
20
|
+
decisions:
|
|
21
|
+
title: Decisions
|
|
22
|
+
collapsed: true
|
|
23
|
+
items:
|
|
24
|
+
title: Decision
|
|
25
|
+
actionItems:
|
|
26
|
+
title: Action Items
|
|
27
|
+
collapsed: true
|
|
28
|
+
items:
|
|
29
|
+
title: Action Item
|
|
30
|
+
actions:
|
|
31
|
+
- type: button
|
|
32
|
+
transition: confirm
|
|
33
|
+
label: 'Confirm'
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { toJSONSchema } from 'zod';
|
|
3
|
-
import { BaseWorkflow,
|
|
3
|
+
import { BaseWorkflow, Transition, Workflow } from '@loopstack/common';
|
|
4
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
4
5
|
import type { LlmGenerateObjectResult } from '@loopstack/llm-provider-module';
|
|
5
6
|
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
6
7
|
import { MeetingNotesDocument, MeetingNotesDocumentSchema } from './documents/meeting-notes-document';
|
|
7
8
|
import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './documents/optimized-notes-document';
|
|
8
9
|
|
|
10
|
+
interface MeetingNotesState {
|
|
11
|
+
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
12
|
+
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
@Workflow({
|
|
10
|
-
|
|
16
|
+
title: 'Human-in-the-loop Demo (Meeting Notes Optimizer)',
|
|
17
|
+
description: 'A demo workflow to demonstrate how to use AI to structure meeting notes.',
|
|
11
18
|
schema: z.object({
|
|
12
19
|
inputText: z
|
|
13
20
|
.string()
|
|
@@ -16,37 +23,45 @@ import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './d
|
|
|
16
23
|
),
|
|
17
24
|
}),
|
|
18
25
|
})
|
|
19
|
-
export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
24
|
-
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
26
|
+
export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }, MeetingNotesState> {
|
|
27
|
+
constructor(private readonly llmGenerateObject: LlmGenerateObjectTool) {
|
|
28
|
+
super();
|
|
29
|
+
}
|
|
25
30
|
|
|
26
|
-
@
|
|
27
|
-
async createForm(
|
|
28
|
-
|
|
31
|
+
@Transition({ to: 'waiting_for_response' })
|
|
32
|
+
async createForm(state: MeetingNotesState, ctx: LoopstackContext): Promise<MeetingNotesState> {
|
|
33
|
+
const args = ctx.args as { inputText: string };
|
|
34
|
+
await this.documentStore.save(
|
|
29
35
|
MeetingNotesDocument,
|
|
30
36
|
{ text: `Unstructured Notes:\n\n${args.inputText}` },
|
|
31
37
|
{ id: 'input' },
|
|
32
38
|
);
|
|
39
|
+
return state;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
@Transition({ from: 'waiting_for_response', to: 'response_received', wait: true, schema: MeetingNotesDocumentSchema })
|
|
36
|
-
async userResponse(
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
async userResponse(
|
|
44
|
+
state: MeetingNotesState,
|
|
45
|
+
payload: z.infer<typeof MeetingNotesDocumentSchema>,
|
|
46
|
+
): Promise<MeetingNotesState> {
|
|
47
|
+
const result = await this.documentStore.save(MeetingNotesDocument, payload, { id: 'input' });
|
|
48
|
+
return { ...state, meetingNotes: result.content as z.infer<typeof MeetingNotesDocumentSchema> };
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
@Transition({ from: 'response_received', to: 'notes_optimized' })
|
|
42
|
-
async optimizeNotes() {
|
|
43
|
-
const result = await this.llmGenerateObject.call(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
async optimizeNotes(state: MeetingNotesState): Promise<MeetingNotesState> {
|
|
53
|
+
const result = await this.llmGenerateObject.call(
|
|
54
|
+
{
|
|
55
|
+
outputSchema: toJSONSchema(OptimizedMeetingNotesDocumentSchema) as Record<string, unknown>,
|
|
56
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
57
|
+
text: state.meetingNotes?.text,
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
61
|
+
);
|
|
47
62
|
|
|
48
63
|
const objectResult = result.data as LlmGenerateObjectResult;
|
|
49
|
-
await this.
|
|
64
|
+
await this.documentStore.save(
|
|
50
65
|
OptimizedNotesDocument,
|
|
51
66
|
objectResult.data as z.infer<typeof OptimizedMeetingNotesDocumentSchema>,
|
|
52
67
|
{
|
|
@@ -54,11 +69,15 @@ export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
|
54
69
|
validate: 'skip',
|
|
55
70
|
},
|
|
56
71
|
);
|
|
72
|
+
return state;
|
|
57
73
|
}
|
|
58
74
|
|
|
59
|
-
@
|
|
60
|
-
async confirm(
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
@Transition({ from: 'notes_optimized', to: 'end', wait: true, schema: OptimizedMeetingNotesDocumentSchema })
|
|
76
|
+
async confirm(
|
|
77
|
+
state: MeetingNotesState,
|
|
78
|
+
payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>,
|
|
79
|
+
): Promise<unknown> {
|
|
80
|
+
const result = await this.documentStore.save(OptimizedNotesDocument, payload, { id: 'final' });
|
|
81
|
+
return { optimizedNotes: result.content as z.infer<typeof OptimizedMeetingNotesDocumentSchema> };
|
|
63
82
|
}
|
|
64
83
|
}
|