@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.
Files changed (45) hide show
  1. package/README.md +204 -0
  2. package/dist/index.d.ts +6 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +22 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm-examples.module.d.ts +3 -0
  7. package/dist/llm-examples.module.d.ts.map +1 -0
  8. package/dist/llm-examples.module.js +51 -0
  9. package/dist/llm-examples.module.js.map +1 -0
  10. package/dist/workflows/multi-provider/multi-provider-example.workflow.d.ts +20 -0
  11. package/dist/workflows/multi-provider/multi-provider-example.workflow.d.ts.map +1 -0
  12. package/dist/workflows/multi-provider/multi-provider-example.workflow.js +85 -0
  13. package/dist/workflows/multi-provider/multi-provider-example.workflow.js.map +1 -0
  14. package/dist/workflows/multi-provider/multi-provider.ui.yaml +4 -0
  15. package/dist/workflows/prompt/prompt-example.workflow.d.ts +15 -0
  16. package/dist/workflows/prompt/prompt-example.workflow.d.ts.map +1 -0
  17. package/dist/workflows/prompt/prompt-example.workflow.js +47 -0
  18. package/dist/workflows/prompt/prompt-example.workflow.js.map +1 -0
  19. package/dist/workflows/prompt/templates/prompt.md +1 -0
  20. package/dist/workflows/structured-output/documents/file-document.d.ts +13 -0
  21. package/dist/workflows/structured-output/documents/file-document.d.ts.map +1 -0
  22. package/dist/workflows/structured-output/documents/file-document.js +31 -0
  23. package/dist/workflows/structured-output/documents/file-document.js.map +1 -0
  24. package/dist/workflows/structured-output/documents/file-document.yaml +16 -0
  25. package/dist/workflows/structured-output/structured-output-example.workflow.d.ts +30 -0
  26. package/dist/workflows/structured-output/structured-output-example.workflow.d.ts.map +1 -0
  27. package/dist/workflows/structured-output/structured-output-example.workflow.js +70 -0
  28. package/dist/workflows/structured-output/structured-output-example.workflow.js.map +1 -0
  29. package/dist/workflows/structured-output/templates/prompt.md +2 -0
  30. package/dist/workflows/web-fetch/web-fetch-example.workflow.d.ts +22 -0
  31. package/dist/workflows/web-fetch/web-fetch-example.workflow.d.ts.map +1 -0
  32. package/dist/workflows/web-fetch/web-fetch-example.workflow.js +74 -0
  33. package/dist/workflows/web-fetch/web-fetch-example.workflow.js.map +1 -0
  34. package/package.json +53 -0
  35. package/src/index.ts +5 -0
  36. package/src/llm-examples.module.ts +38 -0
  37. package/src/workflows/multi-provider/multi-provider-example.workflow.ts +73 -0
  38. package/src/workflows/multi-provider/multi-provider.ui.yaml +4 -0
  39. package/src/workflows/prompt/prompt-example.workflow.ts +32 -0
  40. package/src/workflows/prompt/templates/prompt.md +1 -0
  41. package/src/workflows/structured-output/documents/file-document.ts +22 -0
  42. package/src/workflows/structured-output/documents/file-document.yaml +16 -0
  43. package/src/workflows/structured-output/structured-output-example.workflow.ts +62 -0
  44. package/src/workflows/structured-output/templates/prompt.md +2 -0
  45. 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
@@ -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,3 @@
1
+ export declare class LlmExamplesModule {
2
+ }
3
+ //# sourceMappingURL=llm-examples.module.d.ts.map
@@ -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,4 @@
1
+ widget: start-form
2
+ options:
3
+ title: Multi-Provider LLM
4
+ subtitle: Compare responses from different LLM providers.
@@ -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,16 @@
1
+ widget: form
2
+ options:
3
+ order:
4
+ - filename
5
+ - description
6
+ - code
7
+ properties:
8
+ filename:
9
+ title: File Name
10
+ readonly: true
11
+ description:
12
+ title: Description
13
+ readonly: true
14
+ code:
15
+ title: Code
16
+ widget: code-view
@@ -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,2 @@
1
+ Create a {{ language }} script that prints 'Hello, World!' to the console.
2
+ Wrap the code in triple-backticks including language identifier.
@@ -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,4 @@
1
+ widget: start-form
2
+ options:
3
+ title: Multi-Provider LLM
4
+ subtitle: Compare responses from different LLM providers.
@@ -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,16 @@
1
+ widget: form
2
+ options:
3
+ order:
4
+ - filename
5
+ - description
6
+ - code
7
+ properties:
8
+ filename:
9
+ title: File Name
10
+ readonly: true
11
+ description:
12
+ title: Description
13
+ readonly: true
14
+ code:
15
+ title: Code
16
+ widget: code-view
@@ -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,2 @@
1
+ Create a {{ language }} script that prints 'Hello, World!' to the console.
2
+ Wrap the code in triple-backticks including language identifier.
@@ -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
+ }