@loopstack/meeting-notes-example-workflow 0.22.1 → 0.23.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/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 +14 -10
- package/dist/meeting-notes.workflow.d.ts.map +1 -1
- package/dist/meeting-notes.workflow.js +43 -31
- 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 +47 -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,23 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext, TemplateRenderFn } 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
|
+
private readonly render;
|
|
16
|
+
constructor(llmGenerateObject: LlmGenerateObjectTool, render: TemplateRenderFn);
|
|
17
|
+
createForm(state: MeetingNotesState, ctx: LoopstackContext): Promise<MeetingNotesState>;
|
|
18
|
+
userResponse(state: MeetingNotesState, payload: z.infer<typeof MeetingNotesDocumentSchema>): Promise<MeetingNotesState>;
|
|
19
|
+
optimizeNotes(state: MeetingNotesState): Promise<MeetingNotesState>;
|
|
20
|
+
confirm(state: MeetingNotesState, payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>): Promise<unknown>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
19
23
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"meeting-notes.workflow.d.ts","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAA2C,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE5E,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;IAE5F,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IACP,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADjC,iBAAiB,EAAE,qBAAqB,EACb,MAAM,EAAE,gBAAgB;IAMhE,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"}
|
|
@@ -8,78 +8,90 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.MeetingNotesWorkflow = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
13
17
|
const zod_1 = require("zod");
|
|
14
18
|
const zod_2 = require("zod");
|
|
15
|
-
const
|
|
19
|
+
const common_2 = require("@loopstack/common");
|
|
16
20
|
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
17
21
|
const meeting_notes_document_1 = require("./documents/meeting-notes-document");
|
|
18
22
|
const optimized_notes_document_1 = require("./documents/optimized-notes-document");
|
|
19
|
-
let MeetingNotesWorkflow = class MeetingNotesWorkflow extends
|
|
23
|
+
let MeetingNotesWorkflow = class MeetingNotesWorkflow extends common_2.BaseWorkflow {
|
|
20
24
|
llmGenerateObject;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
render;
|
|
26
|
+
constructor(llmGenerateObject, render) {
|
|
27
|
+
super();
|
|
28
|
+
this.llmGenerateObject = llmGenerateObject;
|
|
29
|
+
this.render = render;
|
|
30
|
+
}
|
|
31
|
+
async createForm(state, ctx) {
|
|
32
|
+
const args = ctx.args;
|
|
33
|
+
await this.documentStore.save(meeting_notes_document_1.MeetingNotesDocument, { text: `Unstructured Notes:\n\n${args.inputText}` }, { id: 'input' });
|
|
34
|
+
return state;
|
|
25
35
|
}
|
|
26
|
-
async userResponse(payload) {
|
|
27
|
-
const result = await this.
|
|
28
|
-
|
|
36
|
+
async userResponse(state, payload) {
|
|
37
|
+
const result = await this.documentStore.save(meeting_notes_document_1.MeetingNotesDocument, payload, { id: 'input' });
|
|
38
|
+
return { ...state, meetingNotes: result.content };
|
|
29
39
|
}
|
|
30
|
-
async optimizeNotes() {
|
|
40
|
+
async optimizeNotes(state) {
|
|
31
41
|
const result = await this.llmGenerateObject.call({
|
|
32
42
|
outputSchema: (0, zod_2.toJSONSchema)(optimized_notes_document_1.OptimizedMeetingNotesDocumentSchema),
|
|
33
|
-
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
34
|
-
|
|
43
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
44
|
+
text: state.meetingNotes?.text,
|
|
45
|
+
}),
|
|
46
|
+
}, { config: { provider: 'claude', model: 'claude-sonnet-4-6' } });
|
|
35
47
|
const objectResult = result.data;
|
|
36
|
-
await this.
|
|
48
|
+
await this.documentStore.save(optimized_notes_document_1.OptimizedNotesDocument, objectResult.data, {
|
|
37
49
|
id: 'final',
|
|
38
50
|
validate: 'skip',
|
|
39
51
|
});
|
|
52
|
+
return state;
|
|
40
53
|
}
|
|
41
|
-
async confirm(payload) {
|
|
42
|
-
const result = await this.
|
|
43
|
-
|
|
54
|
+
async confirm(state, payload) {
|
|
55
|
+
const result = await this.documentStore.save(optimized_notes_document_1.OptimizedNotesDocument, payload, { id: 'final' });
|
|
56
|
+
return { optimizedNotes: result.content };
|
|
44
57
|
}
|
|
45
58
|
};
|
|
46
59
|
exports.MeetingNotesWorkflow = MeetingNotesWorkflow;
|
|
47
60
|
__decorate([
|
|
48
|
-
(0,
|
|
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' }),
|
|
61
|
+
(0, common_2.Transition)({ to: 'waiting_for_response' }),
|
|
53
62
|
__metadata("design:type", Function),
|
|
54
|
-
__metadata("design:paramtypes", [Object]),
|
|
63
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
55
64
|
__metadata("design:returntype", Promise)
|
|
56
65
|
], MeetingNotesWorkflow.prototype, "createForm", null);
|
|
57
66
|
__decorate([
|
|
58
|
-
(0,
|
|
67
|
+
(0, common_2.Transition)({ from: 'waiting_for_response', to: 'response_received', wait: true, schema: meeting_notes_document_1.MeetingNotesDocumentSchema }),
|
|
59
68
|
__metadata("design:type", Function),
|
|
60
|
-
__metadata("design:paramtypes", [Object]),
|
|
69
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
61
70
|
__metadata("design:returntype", Promise)
|
|
62
71
|
], MeetingNotesWorkflow.prototype, "userResponse", null);
|
|
63
72
|
__decorate([
|
|
64
|
-
(0,
|
|
73
|
+
(0, common_2.Transition)({ from: 'response_received', to: 'notes_optimized' }),
|
|
65
74
|
__metadata("design:type", Function),
|
|
66
|
-
__metadata("design:paramtypes", []),
|
|
75
|
+
__metadata("design:paramtypes", [Object]),
|
|
67
76
|
__metadata("design:returntype", Promise)
|
|
68
77
|
], MeetingNotesWorkflow.prototype, "optimizeNotes", null);
|
|
69
78
|
__decorate([
|
|
70
|
-
(0,
|
|
79
|
+
(0, common_2.Transition)({ from: 'notes_optimized', to: 'end', wait: true, schema: optimized_notes_document_1.OptimizedMeetingNotesDocumentSchema }),
|
|
71
80
|
__metadata("design:type", Function),
|
|
72
|
-
__metadata("design:paramtypes", [Object]),
|
|
81
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
73
82
|
__metadata("design:returntype", Promise)
|
|
74
83
|
], MeetingNotesWorkflow.prototype, "confirm", null);
|
|
75
84
|
exports.MeetingNotesWorkflow = MeetingNotesWorkflow = __decorate([
|
|
76
|
-
(0,
|
|
77
|
-
|
|
85
|
+
(0, common_2.Workflow)({
|
|
86
|
+
title: 'Human-in-the-loop Demo (Meeting Notes Optimizer)',
|
|
87
|
+
description: 'A demo workflow to demonstrate how to use AI to structure meeting notes.',
|
|
78
88
|
schema: zod_1.z.object({
|
|
79
89
|
inputText: zod_1.z
|
|
80
90
|
.string()
|
|
81
91
|
.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
92
|
}),
|
|
83
|
-
})
|
|
93
|
+
}),
|
|
94
|
+
__param(1, (0, common_1.Inject)(common_2.TEMPLATE_RENDERER)),
|
|
95
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateObjectTool, Function])
|
|
84
96
|
], MeetingNotesWorkflow);
|
|
85
97
|
//# 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":"
|
|
1
|
+
{"version":3,"file":"meeting-notes.workflow.js","sourceRoot":"","sources":["../src/meeting-notes.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,6BAAwB;AACxB,6BAAmC;AACnC,8CAA0F;AAG1F,wEAAuE;AACvE,+EAAsG;AACtG,mFAAmH;AAkB5G,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,qBAAsD;IAE3E;IAC2B;IAF9C,YACmB,iBAAwC,EACb,MAAwB;QAEpE,KAAK,EAAE,CAAC;QAHS,sBAAiB,GAAjB,iBAAiB,CAAuB;QACb,WAAM,GAAN,MAAM,CAAkB;IAGtE,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU,CAAC,KAAwB,EAAE,GAAqB;QAC9D,MAAM,IAAI,GAAG,GAAG,CAAC,IAA6B,CAAC;QAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,6CAAoB,EACpB,EAAE,IAAI,EAAE,0BAA0B,IAAI,CAAC,SAAS,EAAE,EAAE,EACpD,EAAE,EAAE,EAAE,OAAO,EAAE,CAChB,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAGK,AAAN,KAAK,CAAC,YAAY,CAChB,KAAwB,EACxB,OAAmD;QAEnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,6CAAoB,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7F,OAAO,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,OAAqD,EAAE,CAAC;IAClG,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa,CAAC,KAAwB;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAC9C;YACE,YAAY,EAAE,IAAA,kBAAY,EAAC,8DAAmC,CAA4B;YAC1F,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,6BAA6B,EAAE;gBAC7D,IAAI,EAAE,KAAK,CAAC,YAAY,EAAE,IAAI;aAC/B,CAAC;SACH,EACD,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAC/D,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,CAAC,IAA+B,CAAC;QAC5D,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,iDAAsB,EACtB,YAAY,CAAC,IAA2D,EACxE;YACE,EAAE,EAAE,OAAO;YACX,QAAQ,EAAE,MAAM;SACjB,CACF,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CACX,KAAwB,EACxB,OAA4D;QAE5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,iDAAsB,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,OAA8D,EAAE,CAAC;IACnG,CAAC;CACF,CAAA;AA5DY,oDAAoB;AASzB;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,sBAAsB,EAAE,CAAC;;;;sDAS1C;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,mDAA0B,EAAE,CAAC;;;;wDAOrH;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC;;;;yDAsBhE;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,8DAAmC,EAAE,CAAC;;;;mDAO3G;+BA3DU,oBAAoB;IAXhC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,kDAAkD;QACzD,WAAW,EAAE,0EAA0E;QACvF,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,SAAS,EAAE,OAAC;iBACT,MAAM,EAAE;iBACR,OAAO,CACN,2IAA2I,CAC5I;SACJ,CAAC;KACH,CAAC;IAIG,WAAA,IAAA,eAAM,EAAC,0BAAiB,CAAC,CAAA;qCADU,2CAAqB;GAFhD,oBAAoB,CA4DhC"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"summary",
|
|
10
10
|
"workflow"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.23.0",
|
|
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.0",
|
|
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,21 @@
|
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { toJSONSchema } from 'zod';
|
|
3
|
-
import { BaseWorkflow,
|
|
4
|
+
import { BaseWorkflow, TEMPLATE_RENDERER, Transition, Workflow } from '@loopstack/common';
|
|
5
|
+
import type { LoopstackContext, TemplateRenderFn } from '@loopstack/common';
|
|
4
6
|
import type { LlmGenerateObjectResult } from '@loopstack/llm-provider-module';
|
|
5
7
|
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
6
8
|
import { MeetingNotesDocument, MeetingNotesDocumentSchema } from './documents/meeting-notes-document';
|
|
7
9
|
import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './documents/optimized-notes-document';
|
|
8
10
|
|
|
11
|
+
interface MeetingNotesState {
|
|
12
|
+
meetingNotes?: z.infer<typeof MeetingNotesDocumentSchema>;
|
|
13
|
+
optimizedNotes?: z.infer<typeof OptimizedMeetingNotesDocumentSchema>;
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
@Workflow({
|
|
10
|
-
|
|
17
|
+
title: 'Human-in-the-loop Demo (Meeting Notes Optimizer)',
|
|
18
|
+
description: 'A demo workflow to demonstrate how to use AI to structure meeting notes.',
|
|
11
19
|
schema: z.object({
|
|
12
20
|
inputText: z
|
|
13
21
|
.string()
|
|
@@ -16,37 +24,48 @@ import { OptimizedMeetingNotesDocumentSchema, OptimizedNotesDocument } from './d
|
|
|
16
24
|
),
|
|
17
25
|
}),
|
|
18
26
|
})
|
|
19
|
-
export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }, MeetingNotesState> {
|
|
28
|
+
constructor(
|
|
29
|
+
private readonly llmGenerateObject: LlmGenerateObjectTool,
|
|
30
|
+
@Inject(TEMPLATE_RENDERER) private readonly render: TemplateRenderFn,
|
|
31
|
+
) {
|
|
32
|
+
super();
|
|
33
|
+
}
|
|
25
34
|
|
|
26
|
-
@
|
|
27
|
-
async createForm(
|
|
28
|
-
|
|
35
|
+
@Transition({ to: 'waiting_for_response' })
|
|
36
|
+
async createForm(state: MeetingNotesState, ctx: LoopstackContext): Promise<MeetingNotesState> {
|
|
37
|
+
const args = ctx.args as { inputText: string };
|
|
38
|
+
await this.documentStore.save(
|
|
29
39
|
MeetingNotesDocument,
|
|
30
40
|
{ text: `Unstructured Notes:\n\n${args.inputText}` },
|
|
31
41
|
{ id: 'input' },
|
|
32
42
|
);
|
|
43
|
+
return state;
|
|
33
44
|
}
|
|
34
45
|
|
|
35
46
|
@Transition({ from: 'waiting_for_response', to: 'response_received', wait: true, schema: MeetingNotesDocumentSchema })
|
|
36
|
-
async userResponse(
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
async userResponse(
|
|
48
|
+
state: MeetingNotesState,
|
|
49
|
+
payload: z.infer<typeof MeetingNotesDocumentSchema>,
|
|
50
|
+
): Promise<MeetingNotesState> {
|
|
51
|
+
const result = await this.documentStore.save(MeetingNotesDocument, payload, { id: 'input' });
|
|
52
|
+
return { ...state, meetingNotes: result.content as z.infer<typeof MeetingNotesDocumentSchema> };
|
|
39
53
|
}
|
|
40
54
|
|
|
41
55
|
@Transition({ from: 'response_received', to: 'notes_optimized' })
|
|
42
|
-
async optimizeNotes() {
|
|
43
|
-
const result = await this.llmGenerateObject.call(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
async optimizeNotes(state: MeetingNotesState): Promise<MeetingNotesState> {
|
|
57
|
+
const result = await this.llmGenerateObject.call(
|
|
58
|
+
{
|
|
59
|
+
outputSchema: toJSONSchema(OptimizedMeetingNotesDocumentSchema) as Record<string, unknown>,
|
|
60
|
+
prompt: this.render(__dirname + '/templates/extract-notes.md', {
|
|
61
|
+
text: state.meetingNotes?.text,
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
65
|
+
);
|
|
47
66
|
|
|
48
67
|
const objectResult = result.data as LlmGenerateObjectResult;
|
|
49
|
-
await this.
|
|
68
|
+
await this.documentStore.save(
|
|
50
69
|
OptimizedNotesDocument,
|
|
51
70
|
objectResult.data as z.infer<typeof OptimizedMeetingNotesDocumentSchema>,
|
|
52
71
|
{
|
|
@@ -54,11 +73,15 @@ export class MeetingNotesWorkflow extends BaseWorkflow<{ inputText: string }> {
|
|
|
54
73
|
validate: 'skip',
|
|
55
74
|
},
|
|
56
75
|
);
|
|
76
|
+
return state;
|
|
57
77
|
}
|
|
58
78
|
|
|
59
|
-
@
|
|
60
|
-
async confirm(
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
@Transition({ from: 'notes_optimized', to: 'end', wait: true, schema: OptimizedMeetingNotesDocumentSchema })
|
|
80
|
+
async confirm(
|
|
81
|
+
state: MeetingNotesState,
|
|
82
|
+
payload: z.infer<typeof OptimizedMeetingNotesDocumentSchema>,
|
|
83
|
+
): Promise<unknown> {
|
|
84
|
+
const result = await this.documentStore.save(OptimizedNotesDocument, payload, { id: 'final' });
|
|
85
|
+
return { optimizedNotes: result.content as z.infer<typeof OptimizedMeetingNotesDocumentSchema> };
|
|
63
86
|
}
|
|
64
87
|
}
|