@loopstack/llm-examples 0.1.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 +204 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-examples.module.d.ts +3 -0
- package/dist/llm-examples.module.d.ts.map +1 -0
- package/dist/llm-examples.module.js +51 -0
- package/dist/llm-examples.module.js.map +1 -0
- package/dist/workflows/multi-provider/multi-provider-example.workflow.d.ts +20 -0
- package/dist/workflows/multi-provider/multi-provider-example.workflow.d.ts.map +1 -0
- package/dist/workflows/multi-provider/multi-provider-example.workflow.js +85 -0
- package/dist/workflows/multi-provider/multi-provider-example.workflow.js.map +1 -0
- package/dist/workflows/multi-provider/multi-provider.ui.yaml +4 -0
- package/dist/workflows/prompt/prompt-example.workflow.d.ts +15 -0
- package/dist/workflows/prompt/prompt-example.workflow.d.ts.map +1 -0
- package/dist/workflows/prompt/prompt-example.workflow.js +47 -0
- package/dist/workflows/prompt/prompt-example.workflow.js.map +1 -0
- package/dist/workflows/prompt/templates/prompt.md +1 -0
- package/dist/workflows/structured-output/documents/file-document.d.ts +13 -0
- package/dist/workflows/structured-output/documents/file-document.d.ts.map +1 -0
- package/dist/workflows/structured-output/documents/file-document.js +31 -0
- package/dist/workflows/structured-output/documents/file-document.js.map +1 -0
- package/dist/workflows/structured-output/documents/file-document.yaml +16 -0
- package/dist/workflows/structured-output/structured-output-example.workflow.d.ts +30 -0
- package/dist/workflows/structured-output/structured-output-example.workflow.d.ts.map +1 -0
- package/dist/workflows/structured-output/structured-output-example.workflow.js +70 -0
- package/dist/workflows/structured-output/structured-output-example.workflow.js.map +1 -0
- package/dist/workflows/structured-output/templates/prompt.md +2 -0
- package/dist/workflows/web-fetch/web-fetch-example.workflow.d.ts +22 -0
- package/dist/workflows/web-fetch/web-fetch-example.workflow.d.ts.map +1 -0
- package/dist/workflows/web-fetch/web-fetch-example.workflow.js +74 -0
- package/dist/workflows/web-fetch/web-fetch-example.workflow.js.map +1 -0
- package/package.json +53 -0
- package/src/index.ts +5 -0
- package/src/llm-examples.module.ts +38 -0
- package/src/workflows/multi-provider/multi-provider-example.workflow.ts +73 -0
- package/src/workflows/multi-provider/multi-provider.ui.yaml +4 -0
- package/src/workflows/prompt/prompt-example.workflow.ts +32 -0
- package/src/workflows/prompt/templates/prompt.md +1 -0
- package/src/workflows/structured-output/documents/file-document.ts +22 -0
- package/src/workflows/structured-output/documents/file-document.yaml +16 -0
- package/src/workflows/structured-output/structured-output-example.workflow.ts +62 -0
- package/src/workflows/structured-output/templates/prompt.md +2 -0
- package/src/workflows/web-fetch/web-fetch-example.workflow.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: LLM Examples
|
|
3
|
+
description: Workflow examples for LLM integration in Loopstack — simple prompts, structured output with Zod schemas, multi-provider comparison, web fetch with summarization
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @loopstack/llm-examples
|
|
7
|
+
|
|
8
|
+
> LLM workflow examples for the [Loopstack](https://loopstack.ai) automation framework.
|
|
9
|
+
|
|
10
|
+
A collection of workflow examples that demonstrate how to integrate LLMs into Loopstack workflows. Use these as starting points for prompts, structured output, multi-provider setups, and fetching web content.
|
|
11
|
+
|
|
12
|
+
## Install as Source (Recommended)
|
|
13
|
+
|
|
14
|
+
Examples are meant to be read, copied, and adapted. Pull the source straight into your project with [giget](https://github.com/unjs/giget):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx giget@latest gh:loopstack-ai/loopstack/registry/examples/llm-examples src/llm-examples
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This copies the full `src/` tree into `src/llm-examples/` so you can read the workflow files, edit prompts, swap providers, and ship them as your own. Drop or keep individual workflows as you like.
|
|
21
|
+
|
|
22
|
+
After copying, register the module in your app:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { Module } from '@nestjs/common';
|
|
26
|
+
import { LoopstackModule } from '@loopstack/loopstack-module';
|
|
27
|
+
import { LlmExamplesModule } from './llm-examples/llm-examples.module';
|
|
28
|
+
|
|
29
|
+
@Module({
|
|
30
|
+
imports: [LoopstackModule.forRoot(), LlmExamplesModule],
|
|
31
|
+
})
|
|
32
|
+
export class AppModule {}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Install as a Dependency
|
|
36
|
+
|
|
37
|
+
If you just want to run the examples as-is without modifying source:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install @loopstack/llm-examples
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { LlmExamplesModule } from '@loopstack/llm-examples';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Environment
|
|
48
|
+
|
|
49
|
+
Set provider API keys for the workflows you want to run:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ANTHROPIC_API_KEY=sk-ant-... # required for Claude examples
|
|
53
|
+
OPENAI_API_KEY=sk-... # required for the multi-provider example
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Examples
|
|
57
|
+
|
|
58
|
+
| Example | Studio title | Description |
|
|
59
|
+
| --------------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------- |
|
|
60
|
+
| [Prompt](#prompt) | `LLM - Prompt Example (Write a haiku)` | Single-shot LLM call with a Handlebars-rendered prompt template |
|
|
61
|
+
| [Structured Output](#structured-output) | `LLM - Structured Output Example (Hello World Script)` | Generate Zod-validated structured output with a custom document widget |
|
|
62
|
+
| [Multi-Provider](#multi-provider) | `LLM - Multi-Provider Example` | Run the same prompt through Claude and OpenAI side by side |
|
|
63
|
+
| [Web Fetch](#web-fetch) | `LLM - Web Fetch Example` | Fetch a URL, convert HTML to Markdown, summarize with Claude |
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Prompt
|
|
68
|
+
|
|
69
|
+
Single-shot LLM call using a Handlebars-rendered prompt template. Generates a haiku about a user-provided subject.
|
|
70
|
+
|
|
71
|
+
### What it demonstrates
|
|
72
|
+
|
|
73
|
+
- Defining workflow input arguments with a Zod schema and default values
|
|
74
|
+
- Using the `prompt` parameter for a simple LLM call
|
|
75
|
+
- Rendering Handlebars templates with `this.render(path, vars)`
|
|
76
|
+
- Automatic assistant message persistence via `LlmGenerateTextTool`
|
|
77
|
+
|
|
78
|
+
### Key code
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
@Transition({ to: 'end' })
|
|
82
|
+
async prompt(state, ctx: RunContext<PromptExampleArgs>) {
|
|
83
|
+
await this.llmGenerateText.call(
|
|
84
|
+
{ prompt: this.render(join(__dirname, 'templates', 'prompt.md'), { subject: ctx.args.subject }) },
|
|
85
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`LlmGenerateTextTool` saves the assistant message to the document store automatically — no manual `documentStore.save()` needed. Pass `config: { save: false }` to opt out.
|
|
91
|
+
|
|
92
|
+
### Files
|
|
93
|
+
|
|
94
|
+
- `prompt-example.workflow.ts` — workflow class
|
|
95
|
+
- `templates/prompt.md` — Handlebars prompt template
|
|
96
|
+
|
|
97
|
+
## Structured Output
|
|
98
|
+
|
|
99
|
+
Generates a Zod-validated object (a `FileDocument` with `filename`, `description`, `code`) using `LlmGenerateObjectTool`. Renders in Studio via a custom widget.
|
|
100
|
+
|
|
101
|
+
### What it demonstrates
|
|
102
|
+
|
|
103
|
+
- Defining a `@Document` class with a Zod schema and a YAML widget
|
|
104
|
+
- Calling `LlmGenerateObjectTool` with `outputSchema` for Zod-validated JSON output
|
|
105
|
+
- Persisting the structured result via `this.documentStore.save(FileDocument, result.data.data)`
|
|
106
|
+
- Multi-transition state flow: `start` → `ready` → `prompt_executed` → `end`
|
|
107
|
+
|
|
108
|
+
### Key code
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const result = await this.llmGenerateObject.call(
|
|
112
|
+
{
|
|
113
|
+
outputSchema: FileDocumentSchema,
|
|
114
|
+
prompt: this.render(join(__dirname, 'templates', 'prompt.md'), { language: state.language }),
|
|
115
|
+
},
|
|
116
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const llmResult = await this.documentStore.save(FileDocument, result.data.data as FileDocumentType);
|
|
120
|
+
this.assignState({ llmResult });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Files
|
|
124
|
+
|
|
125
|
+
- `structured-output-example.workflow.ts` — workflow class
|
|
126
|
+
- `documents/file-document.ts` — `@Document` class + Zod schema
|
|
127
|
+
- `documents/file-document.yaml` — Studio widget definition
|
|
128
|
+
- `templates/prompt.md` — Handlebars prompt template
|
|
129
|
+
|
|
130
|
+
## Multi-Provider
|
|
131
|
+
|
|
132
|
+
Sends the same prompt to Claude and OpenAI and renders responses side by side for comparison.
|
|
133
|
+
|
|
134
|
+
### What it demonstrates
|
|
135
|
+
|
|
136
|
+
- Using the same tool class (`LlmGenerateTextTool`) for multiple providers
|
|
137
|
+
- Selecting provider and model at call time via `{ config: { provider, model } }`
|
|
138
|
+
- Opting out of auto-save with `config: { save: false }` to control message formatting
|
|
139
|
+
- Custom start-form widget via `widget: './multi-provider.ui.yaml'`
|
|
140
|
+
|
|
141
|
+
### Key code
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const result = await this.llmGenerateText.call(
|
|
145
|
+
{ prompt: ctx.args.prompt },
|
|
146
|
+
{
|
|
147
|
+
config: {
|
|
148
|
+
save: false,
|
|
149
|
+
provider: 'claude',
|
|
150
|
+
model: 'claude-sonnet-4-6',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
156
|
+
role: 'assistant',
|
|
157
|
+
text: `**Claude:** ${result.data.message.text}`,
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The `save: false` opt-out lets us prefix each response with the provider name so the comparison is clear in the Studio chat view.
|
|
162
|
+
|
|
163
|
+
### Files
|
|
164
|
+
|
|
165
|
+
- `multi-provider-example.workflow.ts` — workflow class
|
|
166
|
+
- `multi-provider.ui.yaml` — Studio start-form widget
|
|
167
|
+
|
|
168
|
+
## Web Fetch
|
|
169
|
+
|
|
170
|
+
Fetches a URL, converts HTML to Markdown, and optionally summarizes it against a user-provided prompt using a small Claude model.
|
|
171
|
+
|
|
172
|
+
### What it demonstrates
|
|
173
|
+
|
|
174
|
+
- Using `WebFetchTool` from `@loopstack/web-module`
|
|
175
|
+
- HTML → Markdown conversion with size caps and same-origin redirect handling
|
|
176
|
+
- Optional prompt-based summarization built into the tool
|
|
177
|
+
|
|
178
|
+
### Key code
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const result = await this.webFetch.call({
|
|
182
|
+
url: ctx.args.url,
|
|
183
|
+
prompt: ctx.args.prompt,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
this.assignState({ summary: result.data.result });
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
When `prompt` is omitted, `WebFetchTool` returns the raw Markdown (truncated if very long). When provided, the tool summarizes the content with a small Claude model.
|
|
190
|
+
|
|
191
|
+
### Files
|
|
192
|
+
|
|
193
|
+
- `web-fetch-example.workflow.ts` — workflow class
|
|
194
|
+
|
|
195
|
+
### Related modules
|
|
196
|
+
|
|
197
|
+
- `@loopstack/web-module` — fetch + Markdown conversion + summarization
|
|
198
|
+
- `@loopstack/claude-tools-module` — Claude server-side web search (alternative when you want the LLM to search rather than fetch a specific URL)
|
|
199
|
+
|
|
200
|
+
## About
|
|
201
|
+
|
|
202
|
+
Author: [Jakob Klippel](https://www.linkedin.com/in/jakob-klippel/)
|
|
203
|
+
|
|
204
|
+
License: MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './llm-examples.module';
|
|
2
|
+
export * from './workflows/prompt/prompt-example.workflow';
|
|
3
|
+
export * from './workflows/structured-output/structured-output-example.workflow';
|
|
4
|
+
export * from './workflows/multi-provider/multi-provider-example.workflow';
|
|
5
|
+
export * from './workflows/web-fetch/web-fetch-example.workflow';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,kEAAkE,CAAC;AACjF,cAAc,4DAA4D,CAAC;AAC3E,cAAc,kDAAkD,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./llm-examples.module"), exports);
|
|
18
|
+
__exportStar(require("./workflows/prompt/prompt-example.workflow"), exports);
|
|
19
|
+
__exportStar(require("./workflows/structured-output/structured-output-example.workflow"), exports);
|
|
20
|
+
__exportStar(require("./workflows/multi-provider/multi-provider-example.workflow"), exports);
|
|
21
|
+
__exportStar(require("./workflows/web-fetch/web-fetch-example.workflow"), exports);
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,6EAA2D;AAC3D,mGAAiF;AACjF,6FAA2E;AAC3E,mFAAiE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-examples.module.d.ts","sourceRoot":"","sources":["../src/llm-examples.module.ts"],"names":[],"mappings":"AAYA,qBAyBa,iBAAiB;CAAG"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LlmExamplesModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const claude_module_1 = require("@loopstack/claude-module");
|
|
12
|
+
const claude_tools_module_1 = require("@loopstack/claude-tools-module");
|
|
13
|
+
const common_2 = require("@loopstack/common");
|
|
14
|
+
const openai_module_1 = require("@loopstack/openai-module");
|
|
15
|
+
const web_module_1 = require("@loopstack/web-module");
|
|
16
|
+
const multi_provider_example_workflow_1 = require("./workflows/multi-provider/multi-provider-example.workflow");
|
|
17
|
+
const prompt_example_workflow_1 = require("./workflows/prompt/prompt-example.workflow");
|
|
18
|
+
const file_document_1 = require("./workflows/structured-output/documents/file-document");
|
|
19
|
+
const structured_output_example_workflow_1 = require("./workflows/structured-output/structured-output-example.workflow");
|
|
20
|
+
const web_fetch_example_workflow_1 = require("./workflows/web-fetch/web-fetch-example.workflow");
|
|
21
|
+
let LlmExamplesModule = class LlmExamplesModule {
|
|
22
|
+
};
|
|
23
|
+
exports.LlmExamplesModule = LlmExamplesModule;
|
|
24
|
+
exports.LlmExamplesModule = LlmExamplesModule = __decorate([
|
|
25
|
+
(0, common_2.StudioApp)({
|
|
26
|
+
title: 'LLM Examples',
|
|
27
|
+
workflows: [
|
|
28
|
+
prompt_example_workflow_1.PromptExampleWorkflow,
|
|
29
|
+
structured_output_example_workflow_1.StructuredOutputExampleWorkflow,
|
|
30
|
+
multi_provider_example_workflow_1.MultiProviderExampleWorkflow,
|
|
31
|
+
web_fetch_example_workflow_1.WebFetchExampleWorkflow,
|
|
32
|
+
],
|
|
33
|
+
}),
|
|
34
|
+
(0, common_1.Module)({
|
|
35
|
+
imports: [claude_module_1.ClaudeModule, claude_tools_module_1.ClaudeToolsModule, openai_module_1.OpenAiModule, web_module_1.WebModule],
|
|
36
|
+
providers: [
|
|
37
|
+
file_document_1.FileDocument,
|
|
38
|
+
prompt_example_workflow_1.PromptExampleWorkflow,
|
|
39
|
+
structured_output_example_workflow_1.StructuredOutputExampleWorkflow,
|
|
40
|
+
multi_provider_example_workflow_1.MultiProviderExampleWorkflow,
|
|
41
|
+
web_fetch_example_workflow_1.WebFetchExampleWorkflow,
|
|
42
|
+
],
|
|
43
|
+
exports: [
|
|
44
|
+
prompt_example_workflow_1.PromptExampleWorkflow,
|
|
45
|
+
structured_output_example_workflow_1.StructuredOutputExampleWorkflow,
|
|
46
|
+
multi_provider_example_workflow_1.MultiProviderExampleWorkflow,
|
|
47
|
+
web_fetch_example_workflow_1.WebFetchExampleWorkflow,
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
], LlmExamplesModule);
|
|
51
|
+
//# sourceMappingURL=llm-examples.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-examples.module.js","sourceRoot":"","sources":["../src/llm-examples.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD,wEAAmE;AACnE,8CAA8C;AAC9C,4DAAwD;AACxD,sDAAkD;AAClD,gHAA0G;AAC1G,wFAAmF;AACnF,yFAAqF;AACrF,yHAAmH;AACnH,iGAA2F;AA2BpF,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;CAAG,CAAA;AAApB,8CAAiB;4BAAjB,iBAAiB;IAzB7B,IAAA,kBAAS,EAAC;QACT,KAAK,EAAE,cAAc;QACrB,SAAS,EAAE;YACT,+CAAqB;YACrB,oEAA+B;YAC/B,8DAA4B;YAC5B,oDAAuB;SACxB;KACF,CAAC;IACD,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,uCAAiB,EAAE,4BAAY,EAAE,sBAAS,CAAC;QACnE,SAAS,EAAE;YACT,4BAAY;YACZ,+CAAqB;YACrB,oEAA+B;YAC/B,8DAA4B;YAC5B,oDAAuB;SACxB;QACD,OAAO,EAAE;YACP,+CAAqB;YACrB,oEAA+B;YAC/B,8DAA4B;YAC5B,oDAAuB;SACxB;KACF,CAAC;GACW,iBAAiB,CAAG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { LlmGenerateTextTool } from '@loopstack/llm-provider-module';
|
|
5
|
+
interface MultiProviderState {
|
|
6
|
+
prompt: string;
|
|
7
|
+
}
|
|
8
|
+
declare const MultiProviderArgsSchema: z.ZodObject<{
|
|
9
|
+
prompt: z.ZodDefault<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
type MultiProviderArgs = z.infer<typeof MultiProviderArgsSchema>;
|
|
12
|
+
export declare class MultiProviderExampleWorkflow extends BaseWorkflow<MultiProviderArgs> {
|
|
13
|
+
private readonly llmGenerateText;
|
|
14
|
+
constructor(llmGenerateText: LlmGenerateTextTool);
|
|
15
|
+
askClaude(state: MultiProviderState, ctx: RunContext<MultiProviderArgs>): Promise<void>;
|
|
16
|
+
askOpenAi(state: MultiProviderState): Promise<void>;
|
|
17
|
+
done(_state: MultiProviderState): void;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=multi-provider-example.workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-provider-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/multi-provider/multi-provider-example.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAsB,MAAM,gCAAgC,CAAC;AAEzF,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,uBAAuB;;iBAE3B,CAAC;AAEH,KAAK,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAEjE,qBAOa,4BAA6B,SAAQ,YAAY,CAAC,iBAAiB,CAAC;IACnE,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAAf,eAAe,EAAE,mBAAmB;IAK3D,SAAS,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,CAAC,iBAAiB,CAAC;IAuBvE,SAAS,CAAC,KAAK,EAAE,kBAAkB;IAoBzC,IAAI,CAAC,MAAM,EAAE,kBAAkB;CAChC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MultiProviderExampleWorkflow = void 0;
|
|
13
|
+
const zod_1 = require("zod");
|
|
14
|
+
const common_1 = require("@loopstack/common");
|
|
15
|
+
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
16
|
+
const MultiProviderArgsSchema = zod_1.z.object({
|
|
17
|
+
prompt: zod_1.z.string().default('What is the meaning of life? Answer in one sentence.'),
|
|
18
|
+
});
|
|
19
|
+
let MultiProviderExampleWorkflow = class MultiProviderExampleWorkflow extends common_1.BaseWorkflow {
|
|
20
|
+
llmGenerateText;
|
|
21
|
+
constructor(llmGenerateText) {
|
|
22
|
+
super();
|
|
23
|
+
this.llmGenerateText = llmGenerateText;
|
|
24
|
+
}
|
|
25
|
+
async askClaude(state, ctx) {
|
|
26
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'user', text: ctx.args.prompt });
|
|
27
|
+
const result = await this.llmGenerateText.call({ prompt: ctx.args.prompt }, {
|
|
28
|
+
config: {
|
|
29
|
+
save: false,
|
|
30
|
+
provider: 'claude',
|
|
31
|
+
model: 'claude-sonnet-4-6',
|
|
32
|
+
system: 'You are a helpful assistant. Keep your response brief.',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
36
|
+
role: 'assistant',
|
|
37
|
+
text: `**Claude:** ${result.data.message.text}`,
|
|
38
|
+
});
|
|
39
|
+
this.assignState({ prompt: ctx.args.prompt });
|
|
40
|
+
}
|
|
41
|
+
async askOpenAi(state) {
|
|
42
|
+
const result = await this.llmGenerateText.call({ prompt: state.prompt }, {
|
|
43
|
+
config: {
|
|
44
|
+
save: false,
|
|
45
|
+
provider: 'openai',
|
|
46
|
+
model: 'gpt-4o-mini',
|
|
47
|
+
system: 'You are a helpful assistant. Keep your response brief.',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
51
|
+
role: 'assistant',
|
|
52
|
+
text: `**OpenAI:** ${result.data.message.text}`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
done(_state) { }
|
|
56
|
+
};
|
|
57
|
+
exports.MultiProviderExampleWorkflow = MultiProviderExampleWorkflow;
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, common_1.Transition)({ to: 'claude_done' }),
|
|
60
|
+
__metadata("design:type", Function),
|
|
61
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
62
|
+
__metadata("design:returntype", Promise)
|
|
63
|
+
], MultiProviderExampleWorkflow.prototype, "askClaude", null);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, common_1.Transition)({ from: 'claude_done', to: 'openai_done' }),
|
|
66
|
+
__metadata("design:type", Function),
|
|
67
|
+
__metadata("design:paramtypes", [Object]),
|
|
68
|
+
__metadata("design:returntype", Promise)
|
|
69
|
+
], MultiProviderExampleWorkflow.prototype, "askOpenAi", null);
|
|
70
|
+
__decorate([
|
|
71
|
+
(0, common_1.Transition)({ from: 'openai_done', to: 'end' }),
|
|
72
|
+
__metadata("design:type", Function),
|
|
73
|
+
__metadata("design:paramtypes", [Object]),
|
|
74
|
+
__metadata("design:returntype", void 0)
|
|
75
|
+
], MultiProviderExampleWorkflow.prototype, "done", null);
|
|
76
|
+
exports.MultiProviderExampleWorkflow = MultiProviderExampleWorkflow = __decorate([
|
|
77
|
+
(0, common_1.Workflow)({
|
|
78
|
+
title: 'LLM - Multi-Provider Example',
|
|
79
|
+
description: 'Runs the same prompt through Claude and OpenAI side by side. Demonstrates that the same tool class (LlmGenerateTextTool) works with any registered provider by passing provider/model via config at call time.',
|
|
80
|
+
widget: './multi-provider.ui.yaml',
|
|
81
|
+
schema: MultiProviderArgsSchema,
|
|
82
|
+
}),
|
|
83
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool])
|
|
84
|
+
], MultiProviderExampleWorkflow);
|
|
85
|
+
//# sourceMappingURL=multi-provider-example.workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-provider-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/multi-provider/multi-provider-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,8CAAuE;AAEvE,wEAAyF;AAMzF,MAAM,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,sDAAsD,CAAC;CACnF,CAAC,CAAC;AAWI,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,qBAA+B;IAClD;IAA7B,YAA6B,eAAoC;QAC/D,KAAK,EAAE,CAAC;QADmB,oBAAe,GAAf,eAAe,CAAqB;IAEjE,CAAC;IAGK,AAAN,KAAK,CAAC,SAAS,CAAC,KAAyB,EAAE,GAAkC;QAC3E,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wCAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAE3F,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAC5C,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,EAC3B;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,mBAAmB;gBAC1B,MAAM,EAAE,wDAAwD;aACjE;SACF,CACF,CAAC;QAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wCAAkB,EAAE;YAChD,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,eAAe,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;SAChD,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,CAAC;IAGK,AAAN,KAAK,CAAC,SAAS,CAAC,KAAyB;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAC5C,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EACxB;YACE,MAAM,EAAE;gBACN,IAAI,EAAE,KAAK;gBACX,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,aAAa;gBACpB,MAAM,EAAE,wDAAwD;aACjE;SACF,CACF,CAAC;QAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wCAAkB,EAAE;YAChD,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,eAAe,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;SAChD,CAAC,CAAC;IACL,CAAC;IAGD,IAAI,CAAC,MAA0B,IAAG,CAAC;CACpC,CAAA;AAlDY,oEAA4B;AAMjC;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC;;;;6DAqBjC;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC;;;;6DAkBtD;AAGD;IADC,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;wDACZ;uCAjDxB,4BAA4B;IAPxC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,gNAAgN;QAClN,MAAM,EAAE,0BAA0B;QAClC,MAAM,EAAE,uBAAuB;KAChC,CAAC;qCAE8C,yCAAmB;GADtD,4BAA4B,CAkDxC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { LlmGenerateTextTool } from '@loopstack/llm-provider-module';
|
|
5
|
+
declare const PromptExampleSchema: z.ZodObject<{
|
|
6
|
+
subject: z.ZodDefault<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
type PromptExampleArgs = z.infer<typeof PromptExampleSchema>;
|
|
9
|
+
export declare class PromptExampleWorkflow extends BaseWorkflow<PromptExampleArgs> {
|
|
10
|
+
private readonly llmGenerateText;
|
|
11
|
+
constructor(llmGenerateText: LlmGenerateTextTool);
|
|
12
|
+
prompt(state: Record<string, unknown>, ctx: RunContext<PromptExampleArgs>): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=prompt-example.workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/prompt/prompt-example.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,QAAA,MAAM,mBAAmB;;iBAEvB,CAAC;AACH,KAAK,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAE7D,qBAMa,qBAAsB,SAAQ,YAAY,CAAC,iBAAiB,CAAC;IAC5D,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAAf,eAAe,EAAE,mBAAmB;IAK3D,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,iBAAiB,CAAC;CAQhF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PromptExampleWorkflow = void 0;
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const zod_1 = require("zod");
|
|
15
|
+
const common_1 = require("@loopstack/common");
|
|
16
|
+
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
17
|
+
const PromptExampleSchema = zod_1.z.object({
|
|
18
|
+
subject: zod_1.z.string().default('coffee'),
|
|
19
|
+
});
|
|
20
|
+
let PromptExampleWorkflow = class PromptExampleWorkflow extends common_1.BaseWorkflow {
|
|
21
|
+
llmGenerateText;
|
|
22
|
+
constructor(llmGenerateText) {
|
|
23
|
+
super();
|
|
24
|
+
this.llmGenerateText = llmGenerateText;
|
|
25
|
+
}
|
|
26
|
+
async prompt(state, ctx) {
|
|
27
|
+
await this.llmGenerateText.call({
|
|
28
|
+
prompt: this.render((0, node_path_1.join)(__dirname, 'templates', 'prompt.md'), { subject: ctx.args.subject }),
|
|
29
|
+
}, { config: { provider: 'claude', model: 'claude-sonnet-4-6' } });
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.PromptExampleWorkflow = PromptExampleWorkflow;
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, common_1.Transition)({ to: 'end' }),
|
|
35
|
+
__metadata("design:type", Function),
|
|
36
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
37
|
+
__metadata("design:returntype", Promise)
|
|
38
|
+
], PromptExampleWorkflow.prototype, "prompt", null);
|
|
39
|
+
exports.PromptExampleWorkflow = PromptExampleWorkflow = __decorate([
|
|
40
|
+
(0, common_1.Workflow)({
|
|
41
|
+
title: 'LLM - Prompt Example (Write a haiku)',
|
|
42
|
+
description: 'Demonstrates the simplest LLM call pattern: a single prompt rendered from a Handlebars template, generating a haiku about a user-provided subject.',
|
|
43
|
+
schema: PromptExampleSchema,
|
|
44
|
+
}),
|
|
45
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool])
|
|
46
|
+
], PromptExampleWorkflow);
|
|
47
|
+
//# sourceMappingURL=prompt-example.workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/prompt/prompt-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yCAAiC;AACjC,6BAAwB;AACxB,8CAAuE;AAEvE,wEAAqE;AAErE,MAAM,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;CACtC,CAAC,CAAC;AASI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,qBAA+B;IAC3C;IAA7B,YAA6B,eAAoC;QAC/D,KAAK,EAAE,CAAC;QADmB,oBAAe,GAAf,eAAe,CAAqB;IAEjE,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAC,KAA8B,EAAE,GAAkC;QAC7E,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAC7B;YACE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;SAC9F,EACD,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAC/D,CAAC;IACJ,CAAC;CACF,CAAA;AAdY,sDAAqB;AAM1B;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;mDAQzB;gCAbU,qBAAqB;IANjC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,sCAAsC;QAC7C,WAAW,EACT,oJAAoJ;QACtJ,MAAM,EAAE,mBAAmB;KAC5B,CAAC;qCAE8C,yCAAmB;GADtD,qBAAqB,CAcjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write a haiku about {{ subject }}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const FileDocumentSchema: z.ZodObject<{
|
|
3
|
+
filename: z.ZodString;
|
|
4
|
+
description: z.ZodString;
|
|
5
|
+
code: z.ZodString;
|
|
6
|
+
}, z.core.$strict>;
|
|
7
|
+
export type FileDocumentType = z.infer<typeof FileDocumentSchema>;
|
|
8
|
+
export declare class FileDocument {
|
|
9
|
+
filename: string;
|
|
10
|
+
description: string;
|
|
11
|
+
code: string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=file-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-document.d.ts","sourceRoot":"","sources":["../../../../src/workflows/structured-output/documents/file-document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,kBAAkB;;;;kBAMpB,CAAC;AAEZ,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAElE,qBAIa,YAAY;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.FileDocument = exports.FileDocumentSchema = void 0;
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const common_1 = require("@loopstack/common");
|
|
12
|
+
exports.FileDocumentSchema = zod_1.z
|
|
13
|
+
.object({
|
|
14
|
+
filename: zod_1.z.string(),
|
|
15
|
+
description: zod_1.z.string(),
|
|
16
|
+
code: zod_1.z.string(),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
let FileDocument = class FileDocument {
|
|
20
|
+
filename;
|
|
21
|
+
description;
|
|
22
|
+
code;
|
|
23
|
+
};
|
|
24
|
+
exports.FileDocument = FileDocument;
|
|
25
|
+
exports.FileDocument = FileDocument = __decorate([
|
|
26
|
+
(0, common_1.Document)({
|
|
27
|
+
schema: exports.FileDocumentSchema,
|
|
28
|
+
widget: './file-document.yaml',
|
|
29
|
+
})
|
|
30
|
+
], FileDocument);
|
|
31
|
+
//# sourceMappingURL=file-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-document.js","sourceRoot":"","sources":["../../../../src/workflows/structured-output/documents/file-document.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA6C;AAEhC,QAAA,kBAAkB,GAAG,OAAC;KAChC,MAAM,CAAC;IACN,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE;IACpB,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC;KACD,MAAM,EAAE,CAAC;AAQL,IAAM,YAAY,GAAlB,MAAM,YAAY;IACvB,QAAQ,CAAS;IACjB,WAAW,CAAS;IACpB,IAAI,CAAS;CACd,CAAA;AAJY,oCAAY;uBAAZ,YAAY;IAJxB,IAAA,iBAAQ,EAAC;QACR,MAAM,EAAE,0BAAkB;QAC1B,MAAM,EAAE,sBAAsB;KAC/B,CAAC;GACW,YAAY,CAIxB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow, DocumentEntity } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { LlmGenerateObjectTool } from '@loopstack/llm-provider-module';
|
|
5
|
+
import { FileDocumentType } from './documents/file-document';
|
|
6
|
+
interface StructuredOutputState {
|
|
7
|
+
language?: string;
|
|
8
|
+
llmResult?: DocumentEntity<FileDocumentType>;
|
|
9
|
+
}
|
|
10
|
+
declare const StructuredOutputArgsSchema: z.ZodObject<{
|
|
11
|
+
language: z.ZodDefault<z.ZodEnum<{
|
|
12
|
+
python: "python";
|
|
13
|
+
javascript: "javascript";
|
|
14
|
+
java: "java";
|
|
15
|
+
cpp: "cpp";
|
|
16
|
+
ruby: "ruby";
|
|
17
|
+
go: "go";
|
|
18
|
+
php: "php";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type StructuredOutputArgs = z.infer<typeof StructuredOutputArgsSchema>;
|
|
22
|
+
export declare class StructuredOutputExampleWorkflow extends BaseWorkflow<StructuredOutputArgs> {
|
|
23
|
+
private readonly llmGenerateObject;
|
|
24
|
+
constructor(llmGenerateObject: LlmGenerateObjectTool);
|
|
25
|
+
greeting(state: StructuredOutputState, ctx: RunContext<StructuredOutputArgs>): Promise<void>;
|
|
26
|
+
prompt(state: StructuredOutputState): Promise<void>;
|
|
27
|
+
respond(state: StructuredOutputState): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=structured-output-example.workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/structured-output/structured-output-example.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAwB,MAAM,mBAAmB,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAsB,MAAM,gCAAgC,CAAC;AAC3F,OAAO,EAAoC,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE/F,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC;CAC9C;AAED,QAAA,MAAM,0BAA0B;;;;;;;;;;iBAE9B,CAAC;AAEH,KAAK,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEvE,qBAMa,+BAAgC,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IACzE,OAAO,CAAC,QAAQ,CAAC,iBAAiB;gBAAjB,iBAAiB,EAAE,qBAAqB;IAK/D,QAAQ,CAAC,KAAK,EAAE,qBAAqB,EAAE,GAAG,EAAE,UAAU,CAAC,oBAAoB,CAAC;IAU5E,MAAM,CAAC,KAAK,EAAE,qBAAqB;IAcnC,OAAO,CAAC,KAAK,EAAE,qBAAqB;CAO3C"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.StructuredOutputExampleWorkflow = void 0;
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const zod_1 = require("zod");
|
|
15
|
+
const common_1 = require("@loopstack/common");
|
|
16
|
+
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
17
|
+
const file_document_1 = require("./documents/file-document");
|
|
18
|
+
const StructuredOutputArgsSchema = zod_1.z.object({
|
|
19
|
+
language: zod_1.z.enum(['python', 'javascript', 'java', 'cpp', 'ruby', 'go', 'php']).default('python'),
|
|
20
|
+
});
|
|
21
|
+
let StructuredOutputExampleWorkflow = class StructuredOutputExampleWorkflow extends common_1.BaseWorkflow {
|
|
22
|
+
llmGenerateObject;
|
|
23
|
+
constructor(llmGenerateObject) {
|
|
24
|
+
super();
|
|
25
|
+
this.llmGenerateObject = llmGenerateObject;
|
|
26
|
+
}
|
|
27
|
+
async greeting(state, ctx) {
|
|
28
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'assistant', text: `Creating a 'Hello, World!' script in ${ctx.args.language}...` }, { key: 'status' });
|
|
29
|
+
this.assignState({ language: ctx.args.language });
|
|
30
|
+
}
|
|
31
|
+
async prompt(state) {
|
|
32
|
+
const result = await this.llmGenerateObject.call({
|
|
33
|
+
outputSchema: file_document_1.FileDocumentSchema,
|
|
34
|
+
prompt: this.render((0, node_path_1.join)(__dirname, 'templates', 'prompt.md'), { language: state.language }),
|
|
35
|
+
}, { config: { provider: 'claude', model: 'claude-sonnet-4-6' } });
|
|
36
|
+
const llmResult = await this.documentStore.save(file_document_1.FileDocument, result.data.data);
|
|
37
|
+
this.assignState({ llmResult });
|
|
38
|
+
}
|
|
39
|
+
async respond(state) {
|
|
40
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'assistant', text: `Successfully generated: ${state.llmResult?.content?.description ?? ''}` }, { key: 'status' });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
exports.StructuredOutputExampleWorkflow = StructuredOutputExampleWorkflow;
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, common_1.Transition)({ to: 'ready' }),
|
|
46
|
+
__metadata("design:type", Function),
|
|
47
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
48
|
+
__metadata("design:returntype", Promise)
|
|
49
|
+
], StructuredOutputExampleWorkflow.prototype, "greeting", null);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, common_1.Transition)({ from: 'ready', to: 'prompt_executed' }),
|
|
52
|
+
__metadata("design:type", Function),
|
|
53
|
+
__metadata("design:paramtypes", [Object]),
|
|
54
|
+
__metadata("design:returntype", Promise)
|
|
55
|
+
], StructuredOutputExampleWorkflow.prototype, "prompt", null);
|
|
56
|
+
__decorate([
|
|
57
|
+
(0, common_1.Transition)({ from: 'prompt_executed', to: 'end' }),
|
|
58
|
+
__metadata("design:type", Function),
|
|
59
|
+
__metadata("design:paramtypes", [Object]),
|
|
60
|
+
__metadata("design:returntype", Promise)
|
|
61
|
+
], StructuredOutputExampleWorkflow.prototype, "respond", null);
|
|
62
|
+
exports.StructuredOutputExampleWorkflow = StructuredOutputExampleWorkflow = __decorate([
|
|
63
|
+
(0, common_1.Workflow)({
|
|
64
|
+
title: 'LLM - Structured Output Example (Hello World Script)',
|
|
65
|
+
description: 'Demonstrates generating structured LLM output using LlmGenerateObjectTool with a custom document schema. Generates a "Hello, World!" script in a chosen programming language.',
|
|
66
|
+
schema: StructuredOutputArgsSchema,
|
|
67
|
+
}),
|
|
68
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateObjectTool])
|
|
69
|
+
], StructuredOutputExampleWorkflow);
|
|
70
|
+
//# sourceMappingURL=structured-output-example.workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/structured-output/structured-output-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yCAAiC;AACjC,6BAAwB;AACxB,8CAAuF;AAEvF,wEAA2F;AAC3F,6DAA+F;AAO/F,MAAM,0BAA0B,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1C,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;CACjG,CAAC,CAAC;AAUI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,qBAAkC;IACxD;IAA7B,YAA6B,iBAAwC;QACnE,KAAK,EAAE,CAAC;QADmB,sBAAiB,GAAjB,iBAAiB,CAAuB;IAErE,CAAC;IAGK,AAAN,KAAK,CAAC,QAAQ,CAAC,KAA4B,EAAE,GAAqC;QAChF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,wCAAkB,EAClB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,wCAAwC,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,EAAE,EAC3F,EAAE,GAAG,EAAE,QAAQ,EAAE,CAClB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACpD,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAC,KAA4B;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAC9C;YACE,YAAY,EAAE,kCAAkB;YAChC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;SAC7F,EACD,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAC/D,CAAC;QAEF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,4BAAY,EAAE,MAAM,CAAC,IAAI,CAAC,IAAwB,CAAC,CAAC;QACpG,IAAI,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IAClC,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAC,KAA4B;QACxC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,wCAAkB,EAClB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,2BAA2B,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,IAAI,EAAE,EAAE,EAAE,EACrG,EAAE,GAAG,EAAE,QAAQ,EAAE,CAClB,CAAC;IACJ,CAAC;CACF,CAAA;AArCY,0EAA+B;AAMpC;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;;;;+DAQ3B;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC;;;;6DAYpD;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;8DAOlD;0CApCU,+BAA+B;IAN3C,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,sDAAsD;QAC7D,WAAW,EACT,+KAA+K;QACjL,MAAM,EAAE,0BAA0B;KACnC,CAAC;qCAEgD,2CAAqB;GAD1D,+BAA+B,CAqC3C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { WebFetchTool } from '@loopstack/web-module';
|
|
5
|
+
interface WebFetchState {
|
|
6
|
+
url?: string;
|
|
7
|
+
summary?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const WebFetchArgsSchema: z.ZodObject<{
|
|
10
|
+
url: z.ZodDefault<z.ZodURL>;
|
|
11
|
+
prompt: z.ZodDefault<z.ZodString>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
type WebFetchArgs = z.infer<typeof WebFetchArgsSchema>;
|
|
14
|
+
export declare class WebFetchExampleWorkflow extends BaseWorkflow<WebFetchArgs> {
|
|
15
|
+
private readonly webFetch;
|
|
16
|
+
constructor(webFetch: WebFetchTool);
|
|
17
|
+
announce(state: WebFetchState, ctx: RunContext<WebFetchArgs>): Promise<void>;
|
|
18
|
+
fetch(state: WebFetchState, ctx: RunContext<WebFetchArgs>): Promise<void>;
|
|
19
|
+
respond(state: WebFetchState): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=web-fetch-example.workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-fetch-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/web-fetch/web-fetch-example.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,QAAA,MAAM,kBAAkB;;;iBAMtB,CAAC;AAEH,KAAK,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEvD,qBAMa,uBAAwB,SAAQ,YAAY,CAAC,YAAY,CAAC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAK7C,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,UAAU,CAAC,YAAY,CAAC;IAS5D,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,UAAU,CAAC,YAAY,CAAC;IAUzD,OAAO,CAAC,KAAK,EAAE,aAAa;CAMnC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.WebFetchExampleWorkflow = void 0;
|
|
13
|
+
const zod_1 = require("zod");
|
|
14
|
+
const common_1 = require("@loopstack/common");
|
|
15
|
+
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
16
|
+
const web_module_1 = require("@loopstack/web-module");
|
|
17
|
+
const WebFetchArgsSchema = zod_1.z.object({
|
|
18
|
+
url: zod_1.z.url().default('https://loopstack.ai'),
|
|
19
|
+
prompt: zod_1.z
|
|
20
|
+
.string()
|
|
21
|
+
.default('Summarize this page in 3 bullet points.')
|
|
22
|
+
.describe('Optional instruction applied to the fetched content. Leave empty for raw Markdown.'),
|
|
23
|
+
});
|
|
24
|
+
let WebFetchExampleWorkflow = class WebFetchExampleWorkflow extends common_1.BaseWorkflow {
|
|
25
|
+
webFetch;
|
|
26
|
+
constructor(webFetch) {
|
|
27
|
+
super();
|
|
28
|
+
this.webFetch = webFetch;
|
|
29
|
+
}
|
|
30
|
+
async announce(state, ctx) {
|
|
31
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'assistant', text: `Fetching ${ctx.args.url}...` }, { key: 'status' });
|
|
32
|
+
}
|
|
33
|
+
async fetch(state, ctx) {
|
|
34
|
+
const result = await this.webFetch.call({
|
|
35
|
+
url: ctx.args.url,
|
|
36
|
+
prompt: ctx.args.prompt,
|
|
37
|
+
});
|
|
38
|
+
this.assignState({ url: ctx.args.url, summary: result.data.result });
|
|
39
|
+
}
|
|
40
|
+
async respond(state) {
|
|
41
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
42
|
+
role: 'assistant',
|
|
43
|
+
text: state.summary ?? '(no content)',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.WebFetchExampleWorkflow = WebFetchExampleWorkflow;
|
|
48
|
+
__decorate([
|
|
49
|
+
(0, common_1.Transition)({ to: 'fetching' }),
|
|
50
|
+
__metadata("design:type", Function),
|
|
51
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
52
|
+
__metadata("design:returntype", Promise)
|
|
53
|
+
], WebFetchExampleWorkflow.prototype, "announce", null);
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, common_1.Transition)({ from: 'fetching', to: 'fetched' }),
|
|
56
|
+
__metadata("design:type", Function),
|
|
57
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
58
|
+
__metadata("design:returntype", Promise)
|
|
59
|
+
], WebFetchExampleWorkflow.prototype, "fetch", null);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, common_1.Transition)({ from: 'fetched', to: 'end' }),
|
|
62
|
+
__metadata("design:type", Function),
|
|
63
|
+
__metadata("design:paramtypes", [Object]),
|
|
64
|
+
__metadata("design:returntype", Promise)
|
|
65
|
+
], WebFetchExampleWorkflow.prototype, "respond", null);
|
|
66
|
+
exports.WebFetchExampleWorkflow = WebFetchExampleWorkflow = __decorate([
|
|
67
|
+
(0, common_1.Workflow)({
|
|
68
|
+
title: 'LLM - Web Fetch Example',
|
|
69
|
+
description: 'Fetches a URL, converts HTML to Markdown, and summarizes it with Claude using a user-provided prompt. Demonstrates the WebFetchTool from @loopstack/web-module.',
|
|
70
|
+
schema: WebFetchArgsSchema,
|
|
71
|
+
}),
|
|
72
|
+
__metadata("design:paramtypes", [web_module_1.WebFetchTool])
|
|
73
|
+
], WebFetchExampleWorkflow);
|
|
74
|
+
//# sourceMappingURL=web-fetch-example.workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-fetch-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/web-fetch/web-fetch-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,8CAAuE;AAEvE,wEAAoE;AACpE,sDAAqD;AAOrD,MAAM,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IAClC,GAAG,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC;IAC5C,MAAM,EAAE,OAAC;SACN,MAAM,EAAE;SACR,OAAO,CAAC,yCAAyC,CAAC;SAClD,QAAQ,CAAC,oFAAoF,CAAC;CAClG,CAAC,CAAC;AAUI,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,qBAA0B;IACxC;IAA7B,YAA6B,QAAsB;QACjD,KAAK,EAAE,CAAC;QADmB,aAAQ,GAAR,QAAQ,CAAc;IAEnD,CAAC;IAGK,AAAN,KAAK,CAAC,QAAQ,CAAC,KAAoB,EAAE,GAA6B;QAChE,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,wCAAkB,EAClB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,EAC1D,EAAE,GAAG,EAAE,QAAQ,EAAE,CAClB,CAAC;IACJ,CAAC;IAGK,AAAN,KAAK,CAAC,KAAK,CAAC,KAAoB,EAAE,GAA6B;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACtC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG;YACjB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAC,KAAoB;QAChC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wCAAkB,EAAE;YAChD,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,KAAK,CAAC,OAAO,IAAI,cAAc;SACtC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AA/BY,0DAAuB;AAM5B;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;;;;uDAO9B;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;;;;oDAQ/C;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;sDAM1C;kCA9BU,uBAAuB;IANnC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,iKAAiK;QACnK,MAAM,EAAE,kBAAkB;KAC3B,CAAC;qCAEuC,yBAAY;GADxC,uBAAuB,CA+BnC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@loopstack/llm-examples",
|
|
3
|
+
"displayName": "Loopstack LLM Examples",
|
|
4
|
+
"description": "Workflow examples for LLM integration in Loopstack — simple prompts, structured output, multi-provider, and web fetch with summarization.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"loopstack",
|
|
7
|
+
"example",
|
|
8
|
+
"llm",
|
|
9
|
+
"prompt",
|
|
10
|
+
"claude",
|
|
11
|
+
"openai",
|
|
12
|
+
"web-fetch"
|
|
13
|
+
],
|
|
14
|
+
"version": "0.1.1",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Jakob Klippel",
|
|
18
|
+
"url": "https://www.linkedin.com/in/jakob-klippel/"
|
|
19
|
+
},
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": "./dist/index.js",
|
|
24
|
+
"./src/*": "./src/*"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "nest build",
|
|
28
|
+
"compile": "tsc --noEmit",
|
|
29
|
+
"format": "prettier --write .",
|
|
30
|
+
"lint": "eslint .",
|
|
31
|
+
"test": "vitest run --passWithNoTests",
|
|
32
|
+
"watch": "nest build --watch"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@loopstack/claude-module": "*",
|
|
36
|
+
"@loopstack/claude-tools-module": "*",
|
|
37
|
+
"@loopstack/common": "*",
|
|
38
|
+
"@loopstack/llm-provider-module": "*",
|
|
39
|
+
"@loopstack/openai-module": "*",
|
|
40
|
+
"@loopstack/web-module": "*",
|
|
41
|
+
"@nestjs/common": "^11.1.19",
|
|
42
|
+
"zod": "^4.3.6"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"src"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"vitest": "^4.1.6",
|
|
50
|
+
"@swc/core": "^1.15.33",
|
|
51
|
+
"unplugin-swc": "^1.5.9"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './llm-examples.module';
|
|
2
|
+
export * from './workflows/prompt/prompt-example.workflow';
|
|
3
|
+
export * from './workflows/structured-output/structured-output-example.workflow';
|
|
4
|
+
export * from './workflows/multi-provider/multi-provider-example.workflow';
|
|
5
|
+
export * from './workflows/web-fetch/web-fetch-example.workflow';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { ClaudeModule } from '@loopstack/claude-module';
|
|
3
|
+
import { ClaudeToolsModule } from '@loopstack/claude-tools-module';
|
|
4
|
+
import { StudioApp } from '@loopstack/common';
|
|
5
|
+
import { OpenAiModule } from '@loopstack/openai-module';
|
|
6
|
+
import { WebModule } from '@loopstack/web-module';
|
|
7
|
+
import { MultiProviderExampleWorkflow } from './workflows/multi-provider/multi-provider-example.workflow';
|
|
8
|
+
import { PromptExampleWorkflow } from './workflows/prompt/prompt-example.workflow';
|
|
9
|
+
import { FileDocument } from './workflows/structured-output/documents/file-document';
|
|
10
|
+
import { StructuredOutputExampleWorkflow } from './workflows/structured-output/structured-output-example.workflow';
|
|
11
|
+
import { WebFetchExampleWorkflow } from './workflows/web-fetch/web-fetch-example.workflow';
|
|
12
|
+
|
|
13
|
+
@StudioApp({
|
|
14
|
+
title: 'LLM Examples',
|
|
15
|
+
workflows: [
|
|
16
|
+
PromptExampleWorkflow,
|
|
17
|
+
StructuredOutputExampleWorkflow,
|
|
18
|
+
MultiProviderExampleWorkflow,
|
|
19
|
+
WebFetchExampleWorkflow,
|
|
20
|
+
],
|
|
21
|
+
})
|
|
22
|
+
@Module({
|
|
23
|
+
imports: [ClaudeModule, ClaudeToolsModule, OpenAiModule, WebModule],
|
|
24
|
+
providers: [
|
|
25
|
+
FileDocument,
|
|
26
|
+
PromptExampleWorkflow,
|
|
27
|
+
StructuredOutputExampleWorkflow,
|
|
28
|
+
MultiProviderExampleWorkflow,
|
|
29
|
+
WebFetchExampleWorkflow,
|
|
30
|
+
],
|
|
31
|
+
exports: [
|
|
32
|
+
PromptExampleWorkflow,
|
|
33
|
+
StructuredOutputExampleWorkflow,
|
|
34
|
+
MultiProviderExampleWorkflow,
|
|
35
|
+
WebFetchExampleWorkflow,
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
export class LlmExamplesModule {}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow, Transition, Workflow } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { LlmGenerateTextTool, LlmMessageDocument } from '@loopstack/llm-provider-module';
|
|
5
|
+
|
|
6
|
+
interface MultiProviderState {
|
|
7
|
+
prompt: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const MultiProviderArgsSchema = z.object({
|
|
11
|
+
prompt: z.string().default('What is the meaning of life? Answer in one sentence.'),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type MultiProviderArgs = z.infer<typeof MultiProviderArgsSchema>;
|
|
15
|
+
|
|
16
|
+
@Workflow({
|
|
17
|
+
title: 'LLM - Multi-Provider Example',
|
|
18
|
+
description:
|
|
19
|
+
'Runs the same prompt through Claude and OpenAI side by side. Demonstrates that the same tool class (LlmGenerateTextTool) works with any registered provider by passing provider/model via config at call time.',
|
|
20
|
+
widget: './multi-provider.ui.yaml',
|
|
21
|
+
schema: MultiProviderArgsSchema,
|
|
22
|
+
})
|
|
23
|
+
export class MultiProviderExampleWorkflow extends BaseWorkflow<MultiProviderArgs> {
|
|
24
|
+
constructor(private readonly llmGenerateText: LlmGenerateTextTool) {
|
|
25
|
+
super();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Transition({ to: 'claude_done' })
|
|
29
|
+
async askClaude(state: MultiProviderState, ctx: RunContext<MultiProviderArgs>) {
|
|
30
|
+
await this.documentStore.save(LlmMessageDocument, { role: 'user', text: ctx.args.prompt });
|
|
31
|
+
|
|
32
|
+
const result = await this.llmGenerateText.call(
|
|
33
|
+
{ prompt: ctx.args.prompt },
|
|
34
|
+
{
|
|
35
|
+
config: {
|
|
36
|
+
save: false,
|
|
37
|
+
provider: 'claude',
|
|
38
|
+
model: 'claude-sonnet-4-6',
|
|
39
|
+
system: 'You are a helpful assistant. Keep your response brief.',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
45
|
+
role: 'assistant',
|
|
46
|
+
text: `**Claude:** ${result.data.message.text}`,
|
|
47
|
+
});
|
|
48
|
+
this.assignState({ prompt: ctx.args.prompt });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Transition({ from: 'claude_done', to: 'openai_done' })
|
|
52
|
+
async askOpenAi(state: MultiProviderState) {
|
|
53
|
+
const result = await this.llmGenerateText.call(
|
|
54
|
+
{ prompt: state.prompt },
|
|
55
|
+
{
|
|
56
|
+
config: {
|
|
57
|
+
save: false,
|
|
58
|
+
provider: 'openai',
|
|
59
|
+
model: 'gpt-4o-mini',
|
|
60
|
+
system: 'You are a helpful assistant. Keep your response brief.',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
66
|
+
role: 'assistant',
|
|
67
|
+
text: `**OpenAI:** ${result.data.message.text}`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Transition({ from: 'openai_done', to: 'end' })
|
|
72
|
+
done(_state: MultiProviderState) {}
|
|
73
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { BaseWorkflow, Transition, Workflow } from '@loopstack/common';
|
|
4
|
+
import type { RunContext } from '@loopstack/common';
|
|
5
|
+
import { LlmGenerateTextTool } from '@loopstack/llm-provider-module';
|
|
6
|
+
|
|
7
|
+
const PromptExampleSchema = z.object({
|
|
8
|
+
subject: z.string().default('coffee'),
|
|
9
|
+
});
|
|
10
|
+
type PromptExampleArgs = z.infer<typeof PromptExampleSchema>;
|
|
11
|
+
|
|
12
|
+
@Workflow({
|
|
13
|
+
title: 'LLM - Prompt Example (Write a haiku)',
|
|
14
|
+
description:
|
|
15
|
+
'Demonstrates the simplest LLM call pattern: a single prompt rendered from a Handlebars template, generating a haiku about a user-provided subject.',
|
|
16
|
+
schema: PromptExampleSchema,
|
|
17
|
+
})
|
|
18
|
+
export class PromptExampleWorkflow extends BaseWorkflow<PromptExampleArgs> {
|
|
19
|
+
constructor(private readonly llmGenerateText: LlmGenerateTextTool) {
|
|
20
|
+
super();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Transition({ to: 'end' })
|
|
24
|
+
async prompt(state: Record<string, unknown>, ctx: RunContext<PromptExampleArgs>) {
|
|
25
|
+
await this.llmGenerateText.call(
|
|
26
|
+
{
|
|
27
|
+
prompt: this.render(join(__dirname, 'templates', 'prompt.md'), { subject: ctx.args.subject }),
|
|
28
|
+
},
|
|
29
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Write a haiku about {{ subject }}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Document } from '@loopstack/common';
|
|
3
|
+
|
|
4
|
+
export const FileDocumentSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
filename: z.string(),
|
|
7
|
+
description: z.string(),
|
|
8
|
+
code: z.string(),
|
|
9
|
+
})
|
|
10
|
+
.strict();
|
|
11
|
+
|
|
12
|
+
export type FileDocumentType = z.infer<typeof FileDocumentSchema>;
|
|
13
|
+
|
|
14
|
+
@Document({
|
|
15
|
+
schema: FileDocumentSchema,
|
|
16
|
+
widget: './file-document.yaml',
|
|
17
|
+
})
|
|
18
|
+
export class FileDocument {
|
|
19
|
+
filename: string;
|
|
20
|
+
description: string;
|
|
21
|
+
code: string;
|
|
22
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { BaseWorkflow, DocumentEntity, Transition, Workflow } from '@loopstack/common';
|
|
4
|
+
import type { RunContext } from '@loopstack/common';
|
|
5
|
+
import { LlmGenerateObjectTool, LlmMessageDocument } from '@loopstack/llm-provider-module';
|
|
6
|
+
import { FileDocument, FileDocumentSchema, FileDocumentType } from './documents/file-document';
|
|
7
|
+
|
|
8
|
+
interface StructuredOutputState {
|
|
9
|
+
language?: string;
|
|
10
|
+
llmResult?: DocumentEntity<FileDocumentType>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const StructuredOutputArgsSchema = z.object({
|
|
14
|
+
language: z.enum(['python', 'javascript', 'java', 'cpp', 'ruby', 'go', 'php']).default('python'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
type StructuredOutputArgs = z.infer<typeof StructuredOutputArgsSchema>;
|
|
18
|
+
|
|
19
|
+
@Workflow({
|
|
20
|
+
title: 'LLM - Structured Output Example (Hello World Script)',
|
|
21
|
+
description:
|
|
22
|
+
'Demonstrates generating structured LLM output using LlmGenerateObjectTool with a custom document schema. Generates a "Hello, World!" script in a chosen programming language.',
|
|
23
|
+
schema: StructuredOutputArgsSchema,
|
|
24
|
+
})
|
|
25
|
+
export class StructuredOutputExampleWorkflow extends BaseWorkflow<StructuredOutputArgs> {
|
|
26
|
+
constructor(private readonly llmGenerateObject: LlmGenerateObjectTool) {
|
|
27
|
+
super();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Transition({ to: 'ready' })
|
|
31
|
+
async greeting(state: StructuredOutputState, ctx: RunContext<StructuredOutputArgs>) {
|
|
32
|
+
await this.documentStore.save(
|
|
33
|
+
LlmMessageDocument,
|
|
34
|
+
{ role: 'assistant', text: `Creating a 'Hello, World!' script in ${ctx.args.language}...` },
|
|
35
|
+
{ key: 'status' },
|
|
36
|
+
);
|
|
37
|
+
this.assignState({ language: ctx.args.language });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Transition({ from: 'ready', to: 'prompt_executed' })
|
|
41
|
+
async prompt(state: StructuredOutputState) {
|
|
42
|
+
const result = await this.llmGenerateObject.call(
|
|
43
|
+
{
|
|
44
|
+
outputSchema: FileDocumentSchema,
|
|
45
|
+
prompt: this.render(join(__dirname, 'templates', 'prompt.md'), { language: state.language }),
|
|
46
|
+
},
|
|
47
|
+
{ config: { provider: 'claude', model: 'claude-sonnet-4-6' } },
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const llmResult = await this.documentStore.save(FileDocument, result.data.data as FileDocumentType);
|
|
51
|
+
this.assignState({ llmResult });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Transition({ from: 'prompt_executed', to: 'end' })
|
|
55
|
+
async respond(state: StructuredOutputState) {
|
|
56
|
+
await this.documentStore.save(
|
|
57
|
+
LlmMessageDocument,
|
|
58
|
+
{ role: 'assistant', text: `Successfully generated: ${state.llmResult?.content?.description ?? ''}` },
|
|
59
|
+
{ key: 'status' },
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { BaseWorkflow, Transition, Workflow } from '@loopstack/common';
|
|
3
|
+
import type { RunContext } from '@loopstack/common';
|
|
4
|
+
import { LlmMessageDocument } from '@loopstack/llm-provider-module';
|
|
5
|
+
import { WebFetchTool } from '@loopstack/web-module';
|
|
6
|
+
|
|
7
|
+
interface WebFetchState {
|
|
8
|
+
url?: string;
|
|
9
|
+
summary?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const WebFetchArgsSchema = z.object({
|
|
13
|
+
url: z.url().default('https://loopstack.ai'),
|
|
14
|
+
prompt: z
|
|
15
|
+
.string()
|
|
16
|
+
.default('Summarize this page in 3 bullet points.')
|
|
17
|
+
.describe('Optional instruction applied to the fetched content. Leave empty for raw Markdown.'),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type WebFetchArgs = z.infer<typeof WebFetchArgsSchema>;
|
|
21
|
+
|
|
22
|
+
@Workflow({
|
|
23
|
+
title: 'LLM - Web Fetch Example',
|
|
24
|
+
description:
|
|
25
|
+
'Fetches a URL, converts HTML to Markdown, and summarizes it with Claude using a user-provided prompt. Demonstrates the WebFetchTool from @loopstack/web-module.',
|
|
26
|
+
schema: WebFetchArgsSchema,
|
|
27
|
+
})
|
|
28
|
+
export class WebFetchExampleWorkflow extends BaseWorkflow<WebFetchArgs> {
|
|
29
|
+
constructor(private readonly webFetch: WebFetchTool) {
|
|
30
|
+
super();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Transition({ to: 'fetching' })
|
|
34
|
+
async announce(state: WebFetchState, ctx: RunContext<WebFetchArgs>) {
|
|
35
|
+
await this.documentStore.save(
|
|
36
|
+
LlmMessageDocument,
|
|
37
|
+
{ role: 'assistant', text: `Fetching ${ctx.args.url}...` },
|
|
38
|
+
{ key: 'status' },
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Transition({ from: 'fetching', to: 'fetched' })
|
|
43
|
+
async fetch(state: WebFetchState, ctx: RunContext<WebFetchArgs>) {
|
|
44
|
+
const result = await this.webFetch.call({
|
|
45
|
+
url: ctx.args.url,
|
|
46
|
+
prompt: ctx.args.prompt,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.assignState({ url: ctx.args.url, summary: result.data.result });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@Transition({ from: 'fetched', to: 'end' })
|
|
53
|
+
async respond(state: WebFetchState) {
|
|
54
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
55
|
+
role: 'assistant',
|
|
56
|
+
text: state.summary ?? '(no content)',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|