@loopstack/advanced-workflows-examples 0.1.1 → 0.1.3

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 (150) hide show
  1. package/README.md +24 -0
  2. package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.d.ts +1 -1
  3. package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.d.ts.map +1 -1
  4. package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.js +2 -2
  5. package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.js.map +1 -1
  6. package/dist/workflows/agent-error-handling/agent-error-handling.workflow.d.ts +4 -4
  7. package/dist/workflows/agent-error-handling/agent-error-handling.workflow.d.ts.map +1 -1
  8. package/dist/workflows/agent-error-handling/agent-error-handling.workflow.js +8 -8
  9. package/dist/workflows/agent-error-handling/agent-error-handling.workflow.js.map +1 -1
  10. package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.d.ts +4 -0
  11. package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.d.ts.map +1 -1
  12. package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.js +4 -1
  13. package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.js.map +1 -1
  14. package/dist/workflows/agent-error-handling/tools/runtime-error.tool.d.ts +2 -0
  15. package/dist/workflows/agent-error-handling/tools/runtime-error.tool.d.ts.map +1 -1
  16. package/dist/workflows/agent-error-handling/tools/runtime-error.tool.js +4 -1
  17. package/dist/workflows/agent-error-handling/tools/runtime-error.tool.js.map +1 -1
  18. package/dist/workflows/agent-error-handling/tools/strict-schema.tool.d.ts +2 -0
  19. package/dist/workflows/agent-error-handling/tools/strict-schema.tool.d.ts.map +1 -1
  20. package/dist/workflows/agent-error-handling/tools/strict-schema.tool.js +4 -1
  21. package/dist/workflows/agent-error-handling/tools/strict-schema.tool.js.map +1 -1
  22. package/dist/workflows/custom-tool/custom-tool-example.workflow.d.ts +1 -1
  23. package/dist/workflows/custom-tool/custom-tool-example.workflow.d.ts.map +1 -1
  24. package/dist/workflows/custom-tool/custom-tool-example.workflow.js +2 -2
  25. package/dist/workflows/custom-tool/custom-tool-example.workflow.js.map +1 -1
  26. package/dist/workflows/custom-tool/tools/counter.tool.d.ts +2 -0
  27. package/dist/workflows/custom-tool/tools/counter.tool.d.ts.map +1 -1
  28. package/dist/workflows/custom-tool/tools/counter.tool.js +5 -1
  29. package/dist/workflows/custom-tool/tools/counter.tool.js.map +1 -1
  30. package/dist/workflows/custom-tool/tools/math-sum.tool.d.ts +1 -0
  31. package/dist/workflows/custom-tool/tools/math-sum.tool.d.ts.map +1 -1
  32. package/dist/workflows/custom-tool/tools/math-sum.tool.js +4 -1
  33. package/dist/workflows/custom-tool/tools/math-sum.tool.js.map +1 -1
  34. package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.d.ts +7 -7
  35. package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.d.ts.map +1 -1
  36. package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.js +15 -15
  37. package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.js.map +1 -1
  38. package/dist/workflows/error-retry/error-retry-example.workflow.d.ts +15 -15
  39. package/dist/workflows/error-retry/error-retry-example.workflow.d.ts.map +1 -1
  40. package/dist/workflows/error-retry/error-retry-example.workflow.js +30 -30
  41. package/dist/workflows/error-retry/error-retry-example.workflow.js.map +1 -1
  42. package/dist/workflows/error-retry/failing-child.workflow.d.ts +1 -1
  43. package/dist/workflows/error-retry/failing-child.workflow.d.ts.map +1 -1
  44. package/dist/workflows/error-retry/failing-child.workflow.js +2 -2
  45. package/dist/workflows/error-retry/failing-child.workflow.js.map +1 -1
  46. package/dist/workflows/error-retry/tools/slow.tool.d.ts +2 -0
  47. package/dist/workflows/error-retry/tools/slow.tool.d.ts.map +1 -1
  48. package/dist/workflows/error-retry/tools/slow.tool.js +5 -1
  49. package/dist/workflows/error-retry/tools/slow.tool.js.map +1 -1
  50. package/dist/workflows/error-retry/tools/step1.tool.d.ts +2 -0
  51. package/dist/workflows/error-retry/tools/step1.tool.d.ts.map +1 -1
  52. package/dist/workflows/error-retry/tools/step1.tool.js +5 -1
  53. package/dist/workflows/error-retry/tools/step1.tool.js.map +1 -1
  54. package/dist/workflows/error-retry/tools/step2.tool.d.ts +2 -0
  55. package/dist/workflows/error-retry/tools/step2.tool.d.ts.map +1 -1
  56. package/dist/workflows/error-retry/tools/step2.tool.js +5 -1
  57. package/dist/workflows/error-retry/tools/step2.tool.js.map +1 -1
  58. package/dist/workflows/fan-out/fan-out-example.workflow.d.ts +1 -1
  59. package/dist/workflows/fan-out/fan-out-example.workflow.d.ts.map +1 -1
  60. package/dist/workflows/fan-out/fan-out-example.workflow.js +2 -2
  61. package/dist/workflows/fan-out/fan-out-example.workflow.js.map +1 -1
  62. package/dist/workflows/module-config/consumers/default-greeting.workflow.d.ts +2 -2
  63. package/dist/workflows/module-config/consumers/default-greeting.workflow.d.ts.map +1 -1
  64. package/dist/workflows/module-config/consumers/default-greeting.workflow.js +4 -4
  65. package/dist/workflows/module-config/consumers/default-greeting.workflow.js.map +1 -1
  66. package/dist/workflows/module-config/consumers/french-greeting.workflow.d.ts +2 -2
  67. package/dist/workflows/module-config/consumers/french-greeting.workflow.d.ts.map +1 -1
  68. package/dist/workflows/module-config/consumers/french-greeting.workflow.js +4 -4
  69. package/dist/workflows/module-config/consumers/french-greeting.workflow.js.map +1 -1
  70. package/dist/workflows/module-config/consumers/german-greeting.workflow.d.ts +2 -2
  71. package/dist/workflows/module-config/consumers/german-greeting.workflow.d.ts.map +1 -1
  72. package/dist/workflows/module-config/consumers/german-greeting.workflow.js +4 -4
  73. package/dist/workflows/module-config/consumers/german-greeting.workflow.js.map +1 -1
  74. package/dist/workflows/module-config/consumers/nested-greeting.workflow.d.ts +2 -2
  75. package/dist/workflows/module-config/consumers/nested-greeting.workflow.d.ts.map +1 -1
  76. package/dist/workflows/module-config/consumers/nested-greeting.workflow.js +4 -4
  77. package/dist/workflows/module-config/consumers/nested-greeting.workflow.js.map +1 -1
  78. package/dist/workflows/module-config/greeter/greeter.tool.d.ts +5 -0
  79. package/dist/workflows/module-config/greeter/greeter.tool.d.ts.map +1 -1
  80. package/dist/workflows/module-config/greeter/greeter.tool.js +8 -1
  81. package/dist/workflows/module-config/greeter/greeter.tool.js.map +1 -1
  82. package/dist/workflows/sequence/sequence-example.workflow.d.ts +1 -1
  83. package/dist/workflows/sequence/sequence-example.workflow.d.ts.map +1 -1
  84. package/dist/workflows/sequence/sequence-example.workflow.js +2 -2
  85. package/dist/workflows/sequence/sequence-example.workflow.js.map +1 -1
  86. package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.d.ts +1 -1
  87. package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.d.ts.map +1 -1
  88. package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.js +2 -2
  89. package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.js.map +1 -1
  90. package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.d.ts +1 -1
  91. package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.d.ts.map +1 -1
  92. package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.js +2 -2
  93. package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.js.map +1 -1
  94. package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.d.ts +2 -2
  95. package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.d.ts.map +1 -1
  96. package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.js +4 -4
  97. package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.js.map +1 -1
  98. package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.d.ts +1 -1
  99. package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.d.ts.map +1 -1
  100. package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.js +2 -2
  101. package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.js.map +1 -1
  102. package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.d.ts +1 -1
  103. package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.d.ts.map +1 -1
  104. package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.js +2 -2
  105. package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.js.map +1 -1
  106. package/dist/workflows/ui-documents/ui-documents-example.workflow.d.ts +2 -2
  107. package/dist/workflows/ui-documents/ui-documents-example.workflow.d.ts.map +1 -1
  108. package/dist/workflows/ui-documents/ui-documents-example.workflow.js +4 -4
  109. package/dist/workflows/ui-documents/ui-documents-example.workflow.js.map +1 -1
  110. package/dist/workflows/workflow-state/tool-results-example.workflow.d.ts +1 -1
  111. package/dist/workflows/workflow-state/tool-results-example.workflow.d.ts.map +1 -1
  112. package/dist/workflows/workflow-state/tool-results-example.workflow.js +2 -2
  113. package/dist/workflows/workflow-state/tool-results-example.workflow.js.map +1 -1
  114. package/dist/workflows/workflow-state/workflow-state-example.workflow.d.ts +1 -1
  115. package/dist/workflows/workflow-state/workflow-state-example.workflow.d.ts.map +1 -1
  116. package/dist/workflows/workflow-state/workflow-state-example.workflow.js +2 -2
  117. package/dist/workflows/workflow-state/workflow-state-example.workflow.js.map +1 -1
  118. package/package.json +2 -2
  119. package/src/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.ts +1 -1
  120. package/src/workflows/agent-error-handling/agent-error-handling.workflow.ts +5 -5
  121. package/src/workflows/agent-error-handling/tools/failing-sub-workflow.tool.ts +4 -0
  122. package/src/workflows/agent-error-handling/tools/runtime-error.tool.ts +4 -0
  123. package/src/workflows/agent-error-handling/tools/strict-schema.tool.ts +4 -0
  124. package/src/workflows/custom-tool/__tests__/custom-tool-facade.spec.ts +142 -0
  125. package/src/workflows/custom-tool/__tests__/trace-consumers.spec.ts +123 -0
  126. package/src/workflows/custom-tool/custom-tool-example.workflow.ts +1 -1
  127. package/src/workflows/custom-tool/tools/counter.tool.ts +5 -0
  128. package/src/workflows/custom-tool/tools/math-sum.tool.ts +4 -0
  129. package/src/workflows/dynamic-routing/dynamic-routing-example.workflow.ts +8 -8
  130. package/src/workflows/error-retry/error-retry-example.workflow.ts +15 -15
  131. package/src/workflows/error-retry/failing-child.workflow.ts +1 -1
  132. package/src/workflows/error-retry/tools/slow.tool.ts +5 -0
  133. package/src/workflows/error-retry/tools/step1.tool.ts +5 -0
  134. package/src/workflows/error-retry/tools/step2.tool.ts +5 -0
  135. package/src/workflows/fan-out/fan-out-example.workflow.ts +1 -1
  136. package/src/workflows/module-config/consumers/default-greeting.workflow.ts +2 -2
  137. package/src/workflows/module-config/consumers/french-greeting.workflow.ts +2 -2
  138. package/src/workflows/module-config/consumers/german-greeting.workflow.ts +2 -2
  139. package/src/workflows/module-config/consumers/nested-greeting.workflow.ts +2 -2
  140. package/src/workflows/module-config/greeter/greeter.tool.ts +8 -0
  141. package/src/workflows/sequence/sequence-example.workflow.ts +1 -1
  142. package/src/workflows/sub-workflow/__tests__/sub-workflow-stateless.spec.ts +80 -0
  143. package/src/workflows/sub-workflow/sub-workflow-error-handling.workflow.ts +1 -1
  144. package/src/workflows/sub-workflow/sub-workflow-failing-sub.workflow.ts +1 -1
  145. package/src/workflows/sub-workflow/sub-workflow-parent.workflow.ts +2 -2
  146. package/src/workflows/sub-workflow/sub-workflow-show-modes.workflow.ts +1 -1
  147. package/src/workflows/sub-workflow/sub-workflow-sub.workflow.ts +1 -1
  148. package/src/workflows/ui-documents/ui-documents-example.workflow.ts +2 -2
  149. package/src/workflows/workflow-state/tool-results-example.workflow.ts +1 -1
  150. package/src/workflows/workflow-state/workflow-state-example.workflow.ts +1 -1
@@ -45,7 +45,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
45
45
  }
46
46
 
47
47
  @Transition({ to: 'step1_done' })
48
- async setup(_state: ErrorRetryState) {
48
+ async setup() {
49
49
  await this.documentStore.save(MessageDocument, {
50
50
  role: 'assistant',
51
51
  text: '# Error Retry Example\n\nThis workflow tests seven retry/error modes in sequence.',
@@ -81,7 +81,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
81
81
 
82
82
  // -- Bridge: instructions for step 2 --
83
83
  @Transition({ from: 'step2_done', to: 'step2_ready' })
84
- async step2Instructions(_state: ErrorRetryState) {
84
+ async step2Instructions() {
85
85
  await this.documentStore.save(MessageDocument, {
86
86
  role: 'assistant',
87
87
  text:
@@ -105,7 +105,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
105
105
 
106
106
  // -- Bridge: instructions for step 3 --
107
107
  @Transition({ from: 'step3_done', to: 'step3_ready' })
108
- async step3Instructions(_state: ErrorRetryState) {
108
+ async step3Instructions() {
109
109
  await this.documentStore.save(MessageDocument, {
110
110
  role: 'assistant',
111
111
  text:
@@ -117,12 +117,12 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
117
117
 
118
118
  // -- Step 3: Custom error place --
119
119
  @Transition({ from: 'step3_ready', to: 'step4_done', errorPlace: 'error_custom' })
120
- async customErrorStep(_state: ErrorRetryState) {
120
+ async customErrorStep() {
121
121
  await this.step2Tool.call({ shouldFail: true });
122
122
  }
123
123
 
124
124
  @Transition({ from: 'error_custom', to: 'step4_done', wait: true })
125
- async handleCustomError(_state: ErrorRetryState) {
125
+ async handleCustomError() {
126
126
  await this.documentStore.save(MessageDocument, {
127
127
  role: 'assistant',
128
128
  text: 'Recovered via custom error handler!',
@@ -131,7 +131,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
131
131
 
132
132
  // -- Bridge: instructions for step 4 --
133
133
  @Transition({ from: 'step4_done', to: 'step4_ready' })
134
- async step4Instructions(_state: ErrorRetryState) {
134
+ async step4Instructions() {
135
135
  await this.documentStore.save(MessageDocument, {
136
136
  role: 'assistant',
137
137
  text:
@@ -156,7 +156,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
156
156
 
157
157
  // -- Bridge: instructions for step 5 --
158
158
  @Transition({ from: 'step5_done', to: 'step5_ready' })
159
- async step5Instructions(_state: ErrorRetryState) {
159
+ async step5Instructions() {
160
160
  await this.documentStore.save(MessageDocument, {
161
161
  role: 'assistant',
162
162
  text:
@@ -168,12 +168,12 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
168
168
 
169
169
  // -- Step 5: Hybrid --
170
170
  @Transition({ from: 'step5_ready', to: 'step6_done', retryAttempts: 1, errorPlace: 'error_hybrid' })
171
- async hybridStep(_state: ErrorRetryState) {
171
+ async hybridStep() {
172
172
  await this.step2Tool.call({ shouldFail: true });
173
173
  }
174
174
 
175
175
  @Transition({ from: 'error_hybrid', to: 'step6_done', wait: true })
176
- async handleHybridError(_state: ErrorRetryState) {
176
+ async handleHybridError() {
177
177
  await this.documentStore.save(MessageDocument, {
178
178
  role: 'assistant',
179
179
  text: 'Recovered via hybrid error handler!',
@@ -182,7 +182,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
182
182
 
183
183
  // -- Bridge: instructions for step 6 --
184
184
  @Transition({ from: 'step6_done', to: 'step6_ready' })
185
- async step6Instructions(_state: ErrorRetryState) {
185
+ async step6Instructions() {
186
186
  await this.documentStore.save(MessageDocument, {
187
187
  role: 'assistant',
188
188
  text:
@@ -228,7 +228,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
228
228
 
229
229
  // Reached only if retryTargetStep keeps failing past its budget.
230
230
  @Transition({ from: 'error_retry_target', to: 'step7_done', wait: true })
231
- async handleRetryTargetError(_state: ErrorRetryState) {
231
+ async handleRetryTargetError() {
232
232
  await this.documentStore.save(MessageDocument, {
233
233
  role: 'assistant',
234
234
  text: 'retryTarget budget exhausted — recovered via error handler.',
@@ -237,7 +237,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
237
237
 
238
238
  // -- Bridge: instructions for step 7 --
239
239
  @Transition({ from: 'step7_done', to: 'step7_ready' })
240
- async step7Instructions(_state: ErrorRetryState) {
240
+ async step7Instructions() {
241
241
  await this.documentStore.save(MessageDocument, {
242
242
  role: 'assistant',
243
243
  text: [
@@ -254,7 +254,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
254
254
 
255
255
  // -- Step 7: Sub-workflow + errorPlace --
256
256
  @Transition({ from: 'step7_ready', to: 'awaiting_child' })
257
- async spawnFailingChild(_state: ErrorRetryState) {
257
+ async spawnFailingChild() {
258
258
  await this.failingChild.run({}, { callback: { transition: 'childCompleted' } });
259
259
  }
260
260
 
@@ -269,7 +269,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
269
269
 
270
270
  // Failure recovery transition for the failing child.
271
271
  @Transition({ from: 'sub_failed', to: 'done', wait: true })
272
- async handleSubFailed(_state: ErrorRetryState) {
272
+ async handleSubFailed() {
273
273
  await this.documentStore.save(MessageDocument, {
274
274
  role: 'assistant',
275
275
  text: 'Recovered from sub-workflow failure via errorPlace routing.',
@@ -277,7 +277,7 @@ export class ErrorRetryWorkflow extends BaseWorkflow {
277
277
  }
278
278
 
279
279
  @Transition({ from: 'done', to: 'end' })
280
- async showResult(_state: ErrorRetryState) {
280
+ async showResult() {
281
281
  await this.documentStore.save(MessageDocument, {
282
282
  role: 'assistant',
283
283
  text: 'All seven retry modes completed successfully!',
@@ -10,7 +10,7 @@ import { BaseWorkflow, MessageDocument, Transition, Workflow } from '@loopstack/
10
10
  })
11
11
  export class ErrorRetryFailingChildWorkflow extends BaseWorkflow {
12
12
  @Transition({ to: 'end' })
13
- async fail(_state: Record<string, unknown>) {
13
+ async fail() {
14
14
  await this.documentStore.save(MessageDocument, {
15
15
  role: 'assistant',
16
16
  text: 'Failing child: about to throw.',
@@ -1,10 +1,15 @@
1
+ import { z } from 'zod';
1
2
  import { BaseTool, Tool, ToolEnvelope } from '@loopstack/common';
2
3
 
3
4
  export type SlowToolResult = string;
4
5
 
6
+ export const SlowToolResultSchema = z.string();
7
+
5
8
  @Tool({
6
9
  name: 'slow',
7
10
  description: 'A tool that takes a configurable amount of time to complete.',
11
+ resultSchema: SlowToolResultSchema,
12
+ effects: 'none',
8
13
  })
9
14
  export class SlowTool extends BaseTool<{ delayMs: number }, object, SlowToolResult> {
10
15
  protected async handle(args: { delayMs: number }): Promise<ToolEnvelope<SlowToolResult>> {
@@ -1,10 +1,15 @@
1
+ import { z } from 'zod';
1
2
  import { BaseTool, Tool, ToolEnvelope } from '@loopstack/common';
2
3
 
3
4
  export type Step1ToolResult = string;
4
5
 
6
+ export const Step1ToolResultSchema = z.string();
7
+
5
8
  @Tool({
6
9
  name: 'step1',
7
10
  description: 'A tool that always succeeds.',
11
+ resultSchema: Step1ToolResultSchema,
12
+ effects: 'none',
8
13
  })
9
14
  export class Step1Tool extends BaseTool<object, object, Step1ToolResult> {
10
15
  protected async handle(): Promise<ToolEnvelope<Step1ToolResult>> {
@@ -1,10 +1,15 @@
1
+ import { z } from 'zod';
1
2
  import { BaseTool, Tool, ToolEnvelope } from '@loopstack/common';
2
3
 
3
4
  export type Step2ToolResult = string;
4
5
 
6
+ export const Step2ToolResultSchema = z.string();
7
+
5
8
  @Tool({
6
9
  name: 'step2',
7
10
  description: 'A tool that fails when shouldFail is true.',
11
+ resultSchema: Step2ToolResultSchema,
12
+ effects: 'none',
8
13
  })
9
14
  export class Step2Tool extends BaseTool<{ shouldFail: boolean }, object, Step2ToolResult> {
10
15
  protected async handle(args: { shouldFail: boolean }): Promise<ToolEnvelope<Step2ToolResult>> {
@@ -19,7 +19,7 @@ export class RunSubWorkflowExampleFanOutWorkflow extends BaseWorkflow {
19
19
  }
20
20
 
21
21
  @Transition({ to: 'awaiting' })
22
- async launch(_state: Record<string, unknown>) {
22
+ async launch() {
23
23
  await this.fanOut.run(
24
24
  {
25
25
  items: {
@@ -11,7 +11,7 @@ export class DefaultGreetingWorkflow extends BaseWorkflow {
11
11
  }
12
12
 
13
13
  @Transition({ to: 'done' })
14
- async greet(_state: Record<string, unknown>) {
14
+ async greet() {
15
15
  const result = await this.greeter.call({ name: 'World' });
16
16
  await this.documentStore.save(MessageDocument, {
17
17
  role: 'assistant',
@@ -20,5 +20,5 @@ export class DefaultGreetingWorkflow extends BaseWorkflow {
20
20
  }
21
21
 
22
22
  @Transition({ from: 'done', to: 'end' })
23
- finish(_state: Record<string, unknown>) {}
23
+ finish() {}
24
24
  }
@@ -12,7 +12,7 @@ export class FrenchGreetingWorkflow extends BaseWorkflow {
12
12
  }
13
13
 
14
14
  @Transition({ to: 'done' })
15
- async greet(_state: Record<string, unknown>) {
15
+ async greet() {
16
16
  const result = await this.greeter.call({ name: 'Monde' });
17
17
  await this.documentStore.save(MessageDocument, {
18
18
  role: 'assistant',
@@ -21,5 +21,5 @@ export class FrenchGreetingWorkflow extends BaseWorkflow {
21
21
  }
22
22
 
23
23
  @Transition({ from: 'done', to: 'end' })
24
- finish(_state: Record<string, unknown>) {}
24
+ finish() {}
25
25
  }
@@ -11,7 +11,7 @@ export class GermanGreetingWorkflow extends BaseWorkflow {
11
11
  }
12
12
 
13
13
  @Transition({ to: 'done' })
14
- async greet(_state: Record<string, unknown>) {
14
+ async greet() {
15
15
  const result = await this.greeter.call({ name: 'Welt' });
16
16
  await this.documentStore.save(MessageDocument, {
17
17
  role: 'assistant',
@@ -20,5 +20,5 @@ export class GermanGreetingWorkflow extends BaseWorkflow {
20
20
  }
21
21
 
22
22
  @Transition({ from: 'done', to: 'end' })
23
- finish(_state: Record<string, unknown>) {}
23
+ finish() {}
24
24
  }
@@ -12,7 +12,7 @@ export class NestedGreetingWorkflow extends BaseWorkflow {
12
12
  }
13
13
 
14
14
  @Transition({ to: 'done' })
15
- async greet(_state: Record<string, unknown>) {
15
+ async greet() {
16
16
  const result = await this.greeter.call({ name: 'Mundo' });
17
17
  await this.documentStore.save(MessageDocument, {
18
18
  role: 'assistant',
@@ -21,5 +21,5 @@ export class NestedGreetingWorkflow extends BaseWorkflow {
21
21
  }
22
22
 
23
23
  @Transition({ from: 'done', to: 'end' })
24
- finish(_state: Record<string, unknown>) {}
24
+ finish() {}
25
25
  }
@@ -16,9 +16,17 @@ export interface GreetResult {
16
16
  greeting: string;
17
17
  }
18
18
 
19
+ export const GreetResultSchema = z.strictObject({
20
+ message: z.string(),
21
+ language: z.string(),
22
+ greeting: z.string(),
23
+ });
24
+
19
25
  @Tool({
20
26
  name: 'greeter',
21
27
  schema: GreeterArgsSchema,
28
+ resultSchema: GreetResultSchema,
29
+ effects: 'none',
22
30
  })
23
31
  export class GreeterTool extends BaseTool<GreeterArgs, object, GreetResult> {
24
32
  @Inject(GREETER_CONFIG) private readonly config: GreeterConfig;
@@ -19,7 +19,7 @@ export class RunSubWorkflowExampleSequenceWorkflow extends BaseWorkflow {
19
19
  }
20
20
 
21
21
  @Transition({ to: 'awaiting' })
22
- async launch(_state: Record<string, unknown>) {
22
+ async launch() {
23
23
  await this.sequence.run(
24
24
  {
25
25
  items: [
@@ -0,0 +1,80 @@
1
+ import { TestingModule } from '@nestjs/testing';
2
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
+ import { executedTransitions } from '@loopstack/contracts/types';
4
+ import { WorkflowProcessorService } from '@loopstack/core';
5
+ import { createStatelessContext, createWorkflowTest, runWorkflow } from '@loopstack/testing';
6
+ import { RunSubWorkflowExampleParentWorkflow } from '../sub-workflow-parent.workflow';
7
+ import { RunSubWorkflowExampleSubWorkflow } from '../sub-workflow-sub.workflow';
8
+
9
+ /**
10
+ * Advanced — the low-level processor API the facade wraps, shown for authors who need direct
11
+ * access to the stateless carrier (children, callbacks, trace). **Most workflow tests should
12
+ * use `runWorkflow` (second describe below)**, which exposes the same outcomes without the
13
+ * plumbing. Children run inline, callbacks are applied automatically, and the whole
14
+ * composition completes in a single `process()` call — no Redis, no Postgres.
15
+ */
16
+ describe('RunSubWorkflowExampleParentWorkflow — stateless inline children (low-level API)', () => {
17
+ let module: TestingModule;
18
+ let workflow: RunSubWorkflowExampleParentWorkflow;
19
+ let processor: WorkflowProcessorService;
20
+
21
+ beforeEach(async () => {
22
+ module = await createWorkflowTest()
23
+ .forWorkflow(RunSubWorkflowExampleParentWorkflow)
24
+ .withProvider(RunSubWorkflowExampleSubWorkflow)
25
+ .compile();
26
+
27
+ workflow = module.get(RunSubWorkflowExampleParentWorkflow);
28
+ processor = module.get(WorkflowProcessorService);
29
+ });
30
+
31
+ afterEach(async () => {
32
+ await module.close();
33
+ });
34
+
35
+ it('runs both children inline and completes in a single call', async () => {
36
+ const result = await processor.process(workflow, {}, createStatelessContext());
37
+
38
+ expect(result.hasError).toBe(false);
39
+ expect(result.status).toBe('completed');
40
+ expect(result.place).toBe('end');
41
+ expect(executedTransitions(result.trace).map((e) => e.transitionId)).toEqual([
42
+ 'runWorkflow',
43
+ 'subWorkflowCallback',
44
+ 'runWorkflow2',
45
+ 'subWorkflow2Callback',
46
+ ]);
47
+
48
+ // Parent documents carry the child results delivered via the callbacks
49
+ const texts = result.documents.map((d) => (d.content as { text?: string }).text);
50
+ expect(texts).toEqual(
51
+ expect.arrayContaining(['A message from sub workflow 1: Hi mom!', 'A message from sub workflow 2: Hi mom!']),
52
+ );
53
+
54
+ // Both inline children are recorded with their own results and documents
55
+ const children = result.statelessState?.children ?? [];
56
+ expect(children).toHaveLength(2);
57
+ for (const child of children) {
58
+ expect(child.status).toBe('completed');
59
+ expect(child.result).toEqual({ message: 'Hi mom!' });
60
+ expect(child.documents.length).toBeGreaterThan(0);
61
+ }
62
+
63
+ // All callbacks were drained
64
+ expect(result.statelessState?.callbacks).toBeUndefined();
65
+ });
66
+ });
67
+
68
+ describe('RunSubWorkflowExampleParentWorkflow — runWorkflow facade', () => {
69
+ it('completes the whole composition through the facade', async () => {
70
+ const run = await runWorkflow(RunSubWorkflowExampleParentWorkflow, undefined, {
71
+ providers: [RunSubWorkflowExampleSubWorkflow],
72
+ });
73
+
74
+ expect(run.error).toBeUndefined();
75
+ expect(run.status).toBe('completed');
76
+ expect(run.path).toEqual(['runWorkflow', 'subWorkflowCallback', 'runWorkflow2', 'subWorkflow2Callback']);
77
+ expect(run.children).toHaveLength(2);
78
+ expect(run.children.every((c) => c.status === 'completed')).toBe(true);
79
+ });
80
+ });
@@ -18,7 +18,7 @@ export class RunSubWorkflowExampleErrorHandlingWorkflow extends BaseWorkflow {
18
18
  }
19
19
 
20
20
  @Transition({ to: 'inline_awaiting' })
21
- async launchInline(_state: Record<string, unknown>) {
21
+ async launchInline() {
22
22
  await this.failingSub.run(
23
23
  {},
24
24
  { callback: { transition: 'onInlineFinished' }, show: 'inline', label: 'Failing sub-workflow (inline)' },
@@ -11,7 +11,7 @@ import { BaseWorkflow, MessageDocument, Transition, Workflow } from '@loopstack/
11
11
  })
12
12
  export class RunSubWorkflowExampleFailingSubWorkflow extends BaseWorkflow {
13
13
  @Transition({ to: 'end' })
14
- async fail(_state: Record<string, unknown>) {
14
+ async fail() {
15
15
  await this.documentStore.save(MessageDocument, {
16
16
  role: 'assistant',
17
17
  text: 'About to throw — this child always fails on purpose.',
@@ -15,7 +15,7 @@ export class RunSubWorkflowExampleParentWorkflow extends BaseWorkflow {
15
15
  }
16
16
 
17
17
  @Transition({ to: 'sub_workflow_started' })
18
- async runWorkflow(_state: Record<string, unknown>) {
18
+ async runWorkflow() {
19
19
  await this.subWorkflow.run(
20
20
  {},
21
21
  { callback: { transition: 'subWorkflowCallback' }, show: 'link', label: 'Sub-Workflow' },
@@ -36,7 +36,7 @@ export class RunSubWorkflowExampleParentWorkflow extends BaseWorkflow {
36
36
  }
37
37
 
38
38
  @Transition({ from: 'sub_workflow_ended', to: 'sub_workflow2_started' })
39
- async runWorkflow2(_state: Record<string, unknown>) {
39
+ async runWorkflow2() {
40
40
  await this.subWorkflow.run(
41
41
  {},
42
42
  { callback: { transition: 'subWorkflow2Callback' }, show: 'link', label: 'Sub-Workflow 2' },
@@ -23,7 +23,7 @@ export class RunSubWorkflowExampleShowModesWorkflow extends BaseWorkflow {
23
23
  }
24
24
 
25
25
  @Transition({ to: 'inline_started' })
26
- async runInline(_state: Record<string, unknown>) {
26
+ async runInline() {
27
27
  await this.sub.run(
28
28
  {},
29
29
  { callback: { transition: 'onInlineDone' }, show: 'inline', label: 'Inline embed (iframe)' },
@@ -6,7 +6,7 @@ import { BaseWorkflow, MessageDocument, Transition, Workflow } from '@loopstack/
6
6
  })
7
7
  export class RunSubWorkflowExampleSubWorkflow extends BaseWorkflow {
8
8
  @Transition({ to: 'end' })
9
- async message(_state: Record<string, unknown>) {
9
+ async message() {
10
10
  await this.documentStore.save(MessageDocument, {
11
11
  role: 'assistant',
12
12
  text: 'Sub workflow completed.',
@@ -15,7 +15,7 @@ import {
15
15
  })
16
16
  export class TestUiDocumentsWorkflow extends BaseWorkflow {
17
17
  @Transition({ to: 'rendered' })
18
- async renderAll(_state: Record<string, unknown>) {
18
+ async renderAll() {
19
19
  // Message
20
20
  await this.documentStore.save(MessageDocument, {
21
21
  role: 'assistant',
@@ -39,5 +39,5 @@ export class TestUiDocumentsWorkflow extends BaseWorkflow {
39
39
  }
40
40
 
41
41
  @Transition({ from: 'rendered', to: 'end' })
42
- done(_state: Record<string, unknown>) {}
42
+ done() {}
43
43
  }
@@ -10,7 +10,7 @@ interface ToolResultsState {
10
10
  })
11
11
  export class WorkflowToolResultsWorkflow extends BaseWorkflow {
12
12
  @Transition({ to: 'data_created' })
13
- async createSomeData(_state: ToolResultsState) {
13
+ async createSomeData() {
14
14
  await this.documentStore.save(MessageDocument, {
15
15
  role: 'assistant',
16
16
  text: `Stored in initial transition: Hello World.`,
@@ -10,7 +10,7 @@ interface WorkflowStateState {
10
10
  })
11
11
  export class WorkflowStateWorkflow extends BaseWorkflow {
12
12
  @Transition({ to: 'data_created' })
13
- createSomeData(_state: WorkflowStateState) {
13
+ createSomeData() {
14
14
  this.assignState({ message: 'Hello :)' });
15
15
  }
16
16