@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.
- package/README.md +24 -0
- package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.d.ts +1 -1
- package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.d.ts.map +1 -1
- package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.js +2 -2
- package/dist/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.js.map +1 -1
- package/dist/workflows/agent-error-handling/agent-error-handling.workflow.d.ts +4 -4
- package/dist/workflows/agent-error-handling/agent-error-handling.workflow.d.ts.map +1 -1
- package/dist/workflows/agent-error-handling/agent-error-handling.workflow.js +8 -8
- package/dist/workflows/agent-error-handling/agent-error-handling.workflow.js.map +1 -1
- package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.d.ts +4 -0
- package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.d.ts.map +1 -1
- package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.js +4 -1
- package/dist/workflows/agent-error-handling/tools/failing-sub-workflow.tool.js.map +1 -1
- package/dist/workflows/agent-error-handling/tools/runtime-error.tool.d.ts +2 -0
- package/dist/workflows/agent-error-handling/tools/runtime-error.tool.d.ts.map +1 -1
- package/dist/workflows/agent-error-handling/tools/runtime-error.tool.js +4 -1
- package/dist/workflows/agent-error-handling/tools/runtime-error.tool.js.map +1 -1
- package/dist/workflows/agent-error-handling/tools/strict-schema.tool.d.ts +2 -0
- package/dist/workflows/agent-error-handling/tools/strict-schema.tool.d.ts.map +1 -1
- package/dist/workflows/agent-error-handling/tools/strict-schema.tool.js +4 -1
- package/dist/workflows/agent-error-handling/tools/strict-schema.tool.js.map +1 -1
- package/dist/workflows/custom-tool/custom-tool-example.workflow.d.ts +1 -1
- package/dist/workflows/custom-tool/custom-tool-example.workflow.d.ts.map +1 -1
- package/dist/workflows/custom-tool/custom-tool-example.workflow.js +2 -2
- package/dist/workflows/custom-tool/custom-tool-example.workflow.js.map +1 -1
- package/dist/workflows/custom-tool/tools/counter.tool.d.ts +2 -0
- package/dist/workflows/custom-tool/tools/counter.tool.d.ts.map +1 -1
- package/dist/workflows/custom-tool/tools/counter.tool.js +5 -1
- package/dist/workflows/custom-tool/tools/counter.tool.js.map +1 -1
- package/dist/workflows/custom-tool/tools/math-sum.tool.d.ts +1 -0
- package/dist/workflows/custom-tool/tools/math-sum.tool.d.ts.map +1 -1
- package/dist/workflows/custom-tool/tools/math-sum.tool.js +4 -1
- package/dist/workflows/custom-tool/tools/math-sum.tool.js.map +1 -1
- package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.d.ts +7 -7
- package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.d.ts.map +1 -1
- package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.js +15 -15
- package/dist/workflows/dynamic-routing/dynamic-routing-example.workflow.js.map +1 -1
- package/dist/workflows/error-retry/error-retry-example.workflow.d.ts +15 -15
- package/dist/workflows/error-retry/error-retry-example.workflow.d.ts.map +1 -1
- package/dist/workflows/error-retry/error-retry-example.workflow.js +30 -30
- package/dist/workflows/error-retry/error-retry-example.workflow.js.map +1 -1
- package/dist/workflows/error-retry/failing-child.workflow.d.ts +1 -1
- package/dist/workflows/error-retry/failing-child.workflow.d.ts.map +1 -1
- package/dist/workflows/error-retry/failing-child.workflow.js +2 -2
- package/dist/workflows/error-retry/failing-child.workflow.js.map +1 -1
- package/dist/workflows/error-retry/tools/slow.tool.d.ts +2 -0
- package/dist/workflows/error-retry/tools/slow.tool.d.ts.map +1 -1
- package/dist/workflows/error-retry/tools/slow.tool.js +5 -1
- package/dist/workflows/error-retry/tools/slow.tool.js.map +1 -1
- package/dist/workflows/error-retry/tools/step1.tool.d.ts +2 -0
- package/dist/workflows/error-retry/tools/step1.tool.d.ts.map +1 -1
- package/dist/workflows/error-retry/tools/step1.tool.js +5 -1
- package/dist/workflows/error-retry/tools/step1.tool.js.map +1 -1
- package/dist/workflows/error-retry/tools/step2.tool.d.ts +2 -0
- package/dist/workflows/error-retry/tools/step2.tool.d.ts.map +1 -1
- package/dist/workflows/error-retry/tools/step2.tool.js +5 -1
- package/dist/workflows/error-retry/tools/step2.tool.js.map +1 -1
- package/dist/workflows/fan-out/fan-out-example.workflow.d.ts +1 -1
- package/dist/workflows/fan-out/fan-out-example.workflow.d.ts.map +1 -1
- package/dist/workflows/fan-out/fan-out-example.workflow.js +2 -2
- package/dist/workflows/fan-out/fan-out-example.workflow.js.map +1 -1
- package/dist/workflows/module-config/consumers/default-greeting.workflow.d.ts +2 -2
- package/dist/workflows/module-config/consumers/default-greeting.workflow.d.ts.map +1 -1
- package/dist/workflows/module-config/consumers/default-greeting.workflow.js +4 -4
- package/dist/workflows/module-config/consumers/default-greeting.workflow.js.map +1 -1
- package/dist/workflows/module-config/consumers/french-greeting.workflow.d.ts +2 -2
- package/dist/workflows/module-config/consumers/french-greeting.workflow.d.ts.map +1 -1
- package/dist/workflows/module-config/consumers/french-greeting.workflow.js +4 -4
- package/dist/workflows/module-config/consumers/french-greeting.workflow.js.map +1 -1
- package/dist/workflows/module-config/consumers/german-greeting.workflow.d.ts +2 -2
- package/dist/workflows/module-config/consumers/german-greeting.workflow.d.ts.map +1 -1
- package/dist/workflows/module-config/consumers/german-greeting.workflow.js +4 -4
- package/dist/workflows/module-config/consumers/german-greeting.workflow.js.map +1 -1
- package/dist/workflows/module-config/consumers/nested-greeting.workflow.d.ts +2 -2
- package/dist/workflows/module-config/consumers/nested-greeting.workflow.d.ts.map +1 -1
- package/dist/workflows/module-config/consumers/nested-greeting.workflow.js +4 -4
- package/dist/workflows/module-config/consumers/nested-greeting.workflow.js.map +1 -1
- package/dist/workflows/module-config/greeter/greeter.tool.d.ts +5 -0
- package/dist/workflows/module-config/greeter/greeter.tool.d.ts.map +1 -1
- package/dist/workflows/module-config/greeter/greeter.tool.js +8 -1
- package/dist/workflows/module-config/greeter/greeter.tool.js.map +1 -1
- package/dist/workflows/sequence/sequence-example.workflow.d.ts +1 -1
- package/dist/workflows/sequence/sequence-example.workflow.d.ts.map +1 -1
- package/dist/workflows/sequence/sequence-example.workflow.js +2 -2
- package/dist/workflows/sequence/sequence-example.workflow.js.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.d.ts +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.d.ts.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.js +2 -2
- package/dist/workflows/sub-workflow/sub-workflow-error-handling.workflow.js.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.d.ts +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.d.ts.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.js +2 -2
- package/dist/workflows/sub-workflow/sub-workflow-failing-sub.workflow.js.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.d.ts +2 -2
- package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.d.ts.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.js +4 -4
- package/dist/workflows/sub-workflow/sub-workflow-parent.workflow.js.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.d.ts +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.d.ts.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.js +2 -2
- package/dist/workflows/sub-workflow/sub-workflow-show-modes.workflow.js.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.d.ts +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.d.ts.map +1 -1
- package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.js +2 -2
- package/dist/workflows/sub-workflow/sub-workflow-sub.workflow.js.map +1 -1
- package/dist/workflows/ui-documents/ui-documents-example.workflow.d.ts +2 -2
- package/dist/workflows/ui-documents/ui-documents-example.workflow.d.ts.map +1 -1
- package/dist/workflows/ui-documents/ui-documents-example.workflow.js +4 -4
- package/dist/workflows/ui-documents/ui-documents-example.workflow.js.map +1 -1
- package/dist/workflows/workflow-state/tool-results-example.workflow.d.ts +1 -1
- package/dist/workflows/workflow-state/tool-results-example.workflow.d.ts.map +1 -1
- package/dist/workflows/workflow-state/tool-results-example.workflow.js +2 -2
- package/dist/workflows/workflow-state/tool-results-example.workflow.js.map +1 -1
- package/dist/workflows/workflow-state/workflow-state-example.workflow.d.ts +1 -1
- package/dist/workflows/workflow-state/workflow-state-example.workflow.d.ts.map +1 -1
- package/dist/workflows/workflow-state/workflow-state-example.workflow.js +2 -2
- package/dist/workflows/workflow-state/workflow-state-example.workflow.js.map +1 -1
- package/package.json +2 -2
- package/src/workflows/agent-error-handling/agent-error-handling-failing-sub.workflow.ts +1 -1
- package/src/workflows/agent-error-handling/agent-error-handling.workflow.ts +5 -5
- package/src/workflows/agent-error-handling/tools/failing-sub-workflow.tool.ts +4 -0
- package/src/workflows/agent-error-handling/tools/runtime-error.tool.ts +4 -0
- package/src/workflows/agent-error-handling/tools/strict-schema.tool.ts +4 -0
- package/src/workflows/custom-tool/__tests__/custom-tool-facade.spec.ts +142 -0
- package/src/workflows/custom-tool/__tests__/trace-consumers.spec.ts +123 -0
- package/src/workflows/custom-tool/custom-tool-example.workflow.ts +1 -1
- package/src/workflows/custom-tool/tools/counter.tool.ts +5 -0
- package/src/workflows/custom-tool/tools/math-sum.tool.ts +4 -0
- package/src/workflows/dynamic-routing/dynamic-routing-example.workflow.ts +8 -8
- package/src/workflows/error-retry/error-retry-example.workflow.ts +15 -15
- package/src/workflows/error-retry/failing-child.workflow.ts +1 -1
- package/src/workflows/error-retry/tools/slow.tool.ts +5 -0
- package/src/workflows/error-retry/tools/step1.tool.ts +5 -0
- package/src/workflows/error-retry/tools/step2.tool.ts +5 -0
- package/src/workflows/fan-out/fan-out-example.workflow.ts +1 -1
- package/src/workflows/module-config/consumers/default-greeting.workflow.ts +2 -2
- package/src/workflows/module-config/consumers/french-greeting.workflow.ts +2 -2
- package/src/workflows/module-config/consumers/german-greeting.workflow.ts +2 -2
- package/src/workflows/module-config/consumers/nested-greeting.workflow.ts +2 -2
- package/src/workflows/module-config/greeter/greeter.tool.ts +8 -0
- package/src/workflows/sequence/sequence-example.workflow.ts +1 -1
- package/src/workflows/sub-workflow/__tests__/sub-workflow-stateless.spec.ts +80 -0
- package/src/workflows/sub-workflow/sub-workflow-error-handling.workflow.ts +1 -1
- package/src/workflows/sub-workflow/sub-workflow-failing-sub.workflow.ts +1 -1
- package/src/workflows/sub-workflow/sub-workflow-parent.workflow.ts +2 -2
- package/src/workflows/sub-workflow/sub-workflow-show-modes.workflow.ts +1 -1
- package/src/workflows/sub-workflow/sub-workflow-sub.workflow.ts +1 -1
- package/src/workflows/ui-documents/ui-documents-example.workflow.ts +2 -2
- package/src/workflows/workflow-state/tool-results-example.workflow.ts +1 -1
- 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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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>> {
|
|
@@ -11,7 +11,7 @@ export class DefaultGreetingWorkflow extends BaseWorkflow {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
@Transition({ to: 'done' })
|
|
14
|
-
async greet(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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;
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
13
|
+
createSomeData() {
|
|
14
14
|
this.assignState({ message: 'Hello :)' });
|
|
15
15
|
}
|
|
16
16
|
|