@loopstack/delegate-error-example-workflow 0.22.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/delegate-error.ui.yaml +6 -22
- package/dist/delegate-error.workflow.d.ts +21 -14
- package/dist/delegate-error.workflow.d.ts.map +1 -1
- package/dist/delegate-error.workflow.js +89 -88
- package/dist/delegate-error.workflow.js.map +1 -1
- package/dist/tools/failing-sub-workflow.tool.d.ts +9 -3
- package/dist/tools/failing-sub-workflow.tool.d.ts.map +1 -1
- package/dist/tools/failing-sub-workflow.tool.js +11 -11
- package/dist/tools/failing-sub-workflow.tool.js.map +1 -1
- package/dist/tools/runtime-error.tool.d.ts +7 -3
- package/dist/tools/runtime-error.tool.d.ts.map +1 -1
- package/dist/tools/runtime-error.tool.js +4 -5
- package/dist/tools/runtime-error.tool.js.map +1 -1
- package/dist/tools/strict-schema.tool.d.ts +7 -3
- package/dist/tools/strict-schema.tool.d.ts.map +1 -1
- package/dist/tools/strict-schema.tool.js +3 -4
- package/dist/tools/strict-schema.tool.js.map +1 -1
- package/dist/workflows/failing.workflow.d.ts +1 -1
- package/dist/workflows/failing.workflow.d.ts.map +1 -1
- package/dist/workflows/failing.workflow.js +4 -4
- package/dist/workflows/failing.workflow.js.map +1 -1
- package/package.json +4 -5
- package/src/__tests__/delegate-error.workflow.spec.ts +9 -9
- package/src/delegate-error.ui.yaml +6 -22
- package/src/delegate-error.workflow.ts +77 -63
- package/src/tools/failing-sub-workflow.tool.ts +18 -10
- package/src/tools/runtime-error.tool.ts +12 -7
- package/src/tools/strict-schema.tool.ts +7 -5
- package/src/workflows/failing.workflow.ts +4 -4
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @loopstack/delegate-error-example-workflow
|
|
2
|
+
|
|
3
|
+
Demonstrates how delegate tool-call loops handle different tool failure modes and feed structured error results back to the LLM for recovery.
|
|
4
|
+
|
|
5
|
+
## By using this example you'll get...
|
|
6
|
+
|
|
7
|
+
- A multi-turn LLM workflow using `LlmGenerateTextTool` + `LlmDelegateToolCallsTool`
|
|
8
|
+
- Three failure types in one flow: schema validation error, runtime error, and failing sub-workflow
|
|
9
|
+
- Error propagation back into the conversation via `LlmUpdateToolResultTool`
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @loopstack/delegate-error-example-workflow
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This example uses `@loopstack/claude-module` through `@loopstack/llm-provider-module`, so configure Claude credentials before running.
|
|
18
|
+
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
1. The workflow seeds an instruction asking the model to intentionally trigger tool failures first.
|
|
22
|
+
2. The LLM generates tool calls (`strict_schema`, `runtime_error`, `failing_sub_workflow`).
|
|
23
|
+
3. Delegate execution runs tools and callback updates merge results into pending delegate state.
|
|
24
|
+
4. Completed tool results are posted back as `tool_result` blocks so the LLM can self-correct.
|
|
25
|
+
5. The workflow ends when the model reaches `end_turn` and stores the final message.
|
|
26
|
+
|
|
27
|
+
## Public API
|
|
28
|
+
|
|
29
|
+
- `DelegateErrorExampleModule`
|
|
30
|
+
- `DelegateErrorWorkflow`
|
|
31
|
+
|
|
32
|
+
## Dependencies
|
|
33
|
+
|
|
34
|
+
- `@loopstack/common`
|
|
35
|
+
- `@loopstack/llm-provider-module`
|
|
36
|
+
- `@loopstack/claude-module`
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
The workflow instructs the LLM to:
|
|
8
|
-
1. Call strictSchema with wrong args (triggers Zod validation error)
|
|
9
|
-
2. Observe the error and retry with correct args
|
|
10
|
-
3. Call runtimeError with shouldFail: true (triggers runtime error)
|
|
11
|
-
4. Observe the error and retry with shouldFail: false
|
|
12
|
-
5. Call failingSubWorkflow (launches a sub-workflow that fails)
|
|
13
|
-
6. Observe the sub-workflow error and summarize
|
|
14
|
-
|
|
15
|
-
ui:
|
|
16
|
-
widgets:
|
|
17
|
-
- widget: button
|
|
18
|
-
showWhen:
|
|
19
|
-
- awaiting_tools
|
|
20
|
-
options:
|
|
21
|
-
transition: cancelPendingTools
|
|
22
|
-
label: Cancel pending tools
|
|
1
|
+
widget: button
|
|
2
|
+
showWhen:
|
|
3
|
+
- awaiting_tools
|
|
4
|
+
options:
|
|
5
|
+
transition: cancelPendingTools
|
|
6
|
+
label: Cancel pending tools
|
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
import { BaseWorkflow } from '@loopstack/common';
|
|
2
|
+
import type { LoopstackContext, TemplateRenderFn, WorkflowOrchestrator } from '@loopstack/common';
|
|
2
3
|
import type { LlmDelegateResult, LlmGenerateTextResult, LlmResultMeta } from '@loopstack/llm-provider-module';
|
|
3
4
|
import { LlmDelegateToolCallsTool, LlmGenerateTextTool, LlmUpdateToolResultTool } from '@loopstack/llm-provider-module';
|
|
4
5
|
import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
|
|
5
6
|
import { RuntimeErrorTool } from './tools/runtime-error.tool';
|
|
6
7
|
import { StrictSchemaTool } from './tools/strict-schema.tool';
|
|
7
|
-
|
|
8
|
-
llmGenerateText: LlmGenerateTextTool;
|
|
9
|
-
llmDelegateToolCalls: LlmDelegateToolCallsTool;
|
|
10
|
-
llmUpdateToolResult: LlmUpdateToolResultTool;
|
|
11
|
-
strictSchema: StrictSchemaTool;
|
|
12
|
-
runtimeError: RuntimeErrorTool;
|
|
13
|
-
failingSubWorkflow: FailingSubWorkflowTool;
|
|
8
|
+
interface DelegateErrorState {
|
|
14
9
|
llmResult?: LlmGenerateTextResult;
|
|
15
10
|
llmMeta?: LlmResultMeta;
|
|
16
11
|
delegateResult?: LlmDelegateResult;
|
|
17
12
|
turnCount: number;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
}
|
|
14
|
+
export declare class DelegateErrorWorkflow extends BaseWorkflow<Record<string, unknown>, DelegateErrorState> {
|
|
15
|
+
private readonly llmGenerateText;
|
|
16
|
+
private readonly llmDelegateToolCalls;
|
|
17
|
+
private readonly llmUpdateToolResult;
|
|
18
|
+
private readonly strictSchema;
|
|
19
|
+
private readonly runtimeError;
|
|
20
|
+
private readonly failingSubWorkflow;
|
|
21
|
+
private readonly render;
|
|
22
|
+
private readonly orchestrator;
|
|
23
|
+
constructor(llmGenerateText: LlmGenerateTextTool, llmDelegateToolCalls: LlmDelegateToolCallsTool, llmUpdateToolResult: LlmUpdateToolResultTool, strictSchema: StrictSchemaTool, runtimeError: RuntimeErrorTool, failingSubWorkflow: FailingSubWorkflowTool, render: TemplateRenderFn, orchestrator: WorkflowOrchestrator);
|
|
24
|
+
setup(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
25
|
+
llmTurn(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
26
|
+
executeToolCalls(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
27
|
+
toolResultReceived(state: DelegateErrorState, payload: unknown): Promise<DelegateErrorState>;
|
|
28
|
+
toolsComplete(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
29
|
+
cancelPendingTools(state: DelegateErrorState, ctx: LoopstackContext): Promise<DelegateErrorState>;
|
|
30
|
+
respond(state: DelegateErrorState): Promise<unknown>;
|
|
25
31
|
private hasToolCalls;
|
|
26
32
|
private allToolsComplete;
|
|
27
33
|
private isEndTurn;
|
|
28
34
|
}
|
|
35
|
+
export {};
|
|
29
36
|
//# sourceMappingURL=delegate-error.workflow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate-error.workflow.d.ts","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"delegate-error.workflow.d.ts","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EAOb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC9G,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EAEnB,uBAAuB,EACxB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD,qBAMa,qBAAsB,SAAQ,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAEhG,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACR,OAAO,CAAC,QAAQ,CAAC,MAAM;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAP3C,eAAe,EAAE,mBAAmB,EACpC,oBAAoB,EAAE,wBAAwB,EAC9C,mBAAmB,EAAE,uBAAuB,EAC5C,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE,gBAAgB,EAC9B,kBAAkB,EAAE,sBAAsB,EACf,MAAM,EAAE,gBAAgB,EACpB,YAAY,EAAE,oBAAoB;IAM9E,KAAK,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmB7D,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAsB/D,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAaxE,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAa5F,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAcrE,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAOjG,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1D,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,SAAS;CAGlB"}
|
|
@@ -8,174 +8,175 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.DelegateErrorWorkflow = void 0;
|
|
13
|
-
const common_1 = require("@
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const common_2 = require("@loopstack/common");
|
|
14
18
|
const llm_provider_module_1 = require("@loopstack/llm-provider-module");
|
|
15
19
|
const failing_sub_workflow_tool_1 = require("./tools/failing-sub-workflow.tool");
|
|
16
20
|
const runtime_error_tool_1 = require("./tools/runtime-error.tool");
|
|
17
21
|
const strict_schema_tool_1 = require("./tools/strict-schema.tool");
|
|
18
|
-
let DelegateErrorWorkflow = class DelegateErrorWorkflow extends
|
|
22
|
+
let DelegateErrorWorkflow = class DelegateErrorWorkflow extends common_2.BaseWorkflow {
|
|
19
23
|
llmGenerateText;
|
|
20
24
|
llmDelegateToolCalls;
|
|
21
25
|
llmUpdateToolResult;
|
|
22
26
|
strictSchema;
|
|
23
27
|
runtimeError;
|
|
24
28
|
failingSubWorkflow;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.
|
|
31
|
-
|
|
29
|
+
render;
|
|
30
|
+
orchestrator;
|
|
31
|
+
constructor(llmGenerateText, llmDelegateToolCalls, llmUpdateToolResult, strictSchema, runtimeError, failingSubWorkflow, render, orchestrator) {
|
|
32
|
+
super();
|
|
33
|
+
this.llmGenerateText = llmGenerateText;
|
|
34
|
+
this.llmDelegateToolCalls = llmDelegateToolCalls;
|
|
35
|
+
this.llmUpdateToolResult = llmUpdateToolResult;
|
|
36
|
+
this.strictSchema = strictSchema;
|
|
37
|
+
this.runtimeError = runtimeError;
|
|
38
|
+
this.failingSubWorkflow = failingSubWorkflow;
|
|
39
|
+
this.render = render;
|
|
40
|
+
this.orchestrator = orchestrator;
|
|
41
|
+
}
|
|
42
|
+
async setup(state) {
|
|
43
|
+
await this.documentStore.save(common_2.MessageDocument, {
|
|
32
44
|
role: 'assistant',
|
|
33
45
|
content: '# Delegate Error Handling Example\n\n' +
|
|
34
46
|
'This workflow tests how tool errors are handled and fed back to the LLM.\n\n' +
|
|
35
47
|
'The LLM will deliberately trigger errors, then self-correct.',
|
|
36
48
|
});
|
|
37
|
-
await this.
|
|
49
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
38
50
|
role: 'user',
|
|
39
51
|
content: 'Follow the instructions in your system prompt exactly. ' +
|
|
40
52
|
'Start with step 1: call strictSchema with no arguments.',
|
|
41
53
|
});
|
|
54
|
+
return { ...state, turnCount: 0 };
|
|
42
55
|
}
|
|
43
|
-
async llmTurn() {
|
|
44
|
-
this.turnCount++;
|
|
56
|
+
async llmTurn(state) {
|
|
45
57
|
const result = await this.llmGenerateText.call({}, {
|
|
46
58
|
config: {
|
|
59
|
+
provider: 'claude',
|
|
60
|
+
model: 'claude-sonnet-4-6',
|
|
47
61
|
system: this.render(__dirname + '/templates/system.md'),
|
|
62
|
+
tools: ['strict_schema', 'runtime_error', 'failing_sub_workflow'],
|
|
48
63
|
},
|
|
49
64
|
});
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
return {
|
|
66
|
+
...state,
|
|
67
|
+
turnCount: state.turnCount + 1,
|
|
68
|
+
llmResult: result.data,
|
|
69
|
+
llmMeta: result.metadata,
|
|
70
|
+
};
|
|
52
71
|
}
|
|
53
|
-
async executeToolCalls() {
|
|
54
|
-
await this.
|
|
55
|
-
meta: { response:
|
|
72
|
+
async executeToolCalls(state) {
|
|
73
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, state.llmResult.message, {
|
|
74
|
+
meta: { response: state.llmResult.response, provider: state.llmMeta.provider },
|
|
56
75
|
});
|
|
57
76
|
const result = await this.llmDelegateToolCalls.call({
|
|
58
|
-
message:
|
|
77
|
+
message: state.llmResult.message,
|
|
59
78
|
callback: { transition: 'toolResultReceived' },
|
|
60
79
|
});
|
|
61
|
-
|
|
80
|
+
return { ...state, delegateResult: result.data };
|
|
62
81
|
}
|
|
63
|
-
async toolResultReceived(payload) {
|
|
82
|
+
async toolResultReceived(state, payload) {
|
|
64
83
|
const result = await this.llmUpdateToolResult.call({
|
|
65
|
-
delegateResult:
|
|
84
|
+
delegateResult: state.delegateResult,
|
|
66
85
|
completedTool: payload,
|
|
67
|
-
});
|
|
68
|
-
|
|
86
|
+
}, { config: { provider: 'claude' } });
|
|
87
|
+
return { ...state, delegateResult: result.data };
|
|
69
88
|
}
|
|
70
|
-
async toolsComplete() {
|
|
71
|
-
await this.
|
|
89
|
+
async toolsComplete(state) {
|
|
90
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
72
91
|
role: 'user',
|
|
73
|
-
content:
|
|
92
|
+
content: state.delegateResult.toolResults.map((tr) => ({
|
|
74
93
|
type: 'tool_result',
|
|
75
94
|
toolCallId: tr.toolCallId,
|
|
76
95
|
content: tr.content ?? '',
|
|
77
96
|
isError: tr.isError ?? false,
|
|
78
97
|
})),
|
|
79
98
|
});
|
|
99
|
+
return state;
|
|
80
100
|
}
|
|
81
|
-
async cancelPendingTools() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await this.orchestrator.cancelChildren(workflowId);
|
|
85
|
-
}
|
|
101
|
+
async cancelPendingTools(state, ctx) {
|
|
102
|
+
await this.orchestrator.cancelChildren(ctx.workflowId);
|
|
103
|
+
return state;
|
|
86
104
|
}
|
|
87
|
-
async respond() {
|
|
88
|
-
await this.
|
|
89
|
-
meta: { response:
|
|
105
|
+
async respond(state) {
|
|
106
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, state.llmResult.message, {
|
|
107
|
+
meta: { response: state.llmResult.response, provider: state.llmMeta.provider },
|
|
90
108
|
});
|
|
109
|
+
return {};
|
|
91
110
|
}
|
|
92
|
-
hasToolCalls() {
|
|
93
|
-
return
|
|
111
|
+
hasToolCalls(state) {
|
|
112
|
+
return state.llmResult?.message.stopReason === 'tool_use';
|
|
94
113
|
}
|
|
95
|
-
allToolsComplete() {
|
|
96
|
-
return !!
|
|
114
|
+
allToolsComplete(state) {
|
|
115
|
+
return !!state.delegateResult?.allCompleted;
|
|
97
116
|
}
|
|
98
|
-
isEndTurn() {
|
|
99
|
-
return
|
|
117
|
+
isEndTurn(state) {
|
|
118
|
+
return state.llmResult?.message.stopReason === 'end_turn';
|
|
100
119
|
}
|
|
101
120
|
};
|
|
102
121
|
exports.DelegateErrorWorkflow = DelegateErrorWorkflow;
|
|
103
122
|
__decorate([
|
|
104
|
-
(0,
|
|
105
|
-
provider: 'claude',
|
|
106
|
-
model: 'claude-sonnet-4-6',
|
|
107
|
-
tools: ['strictSchema', 'runtimeError', 'failingSubWorkflow'],
|
|
108
|
-
}),
|
|
109
|
-
__metadata("design:type", llm_provider_module_1.LlmGenerateTextTool)
|
|
110
|
-
], DelegateErrorWorkflow.prototype, "llmGenerateText", void 0);
|
|
111
|
-
__decorate([
|
|
112
|
-
(0, common_1.InjectTool)({ provider: 'claude' }),
|
|
113
|
-
__metadata("design:type", llm_provider_module_1.LlmDelegateToolCallsTool)
|
|
114
|
-
], DelegateErrorWorkflow.prototype, "llmDelegateToolCalls", void 0);
|
|
115
|
-
__decorate([
|
|
116
|
-
(0, common_1.InjectTool)({ provider: 'claude' }),
|
|
117
|
-
__metadata("design:type", llm_provider_module_1.LlmUpdateToolResultTool)
|
|
118
|
-
], DelegateErrorWorkflow.prototype, "llmUpdateToolResult", void 0);
|
|
119
|
-
__decorate([
|
|
120
|
-
(0, common_1.InjectTool)(),
|
|
121
|
-
__metadata("design:type", strict_schema_tool_1.StrictSchemaTool)
|
|
122
|
-
], DelegateErrorWorkflow.prototype, "strictSchema", void 0);
|
|
123
|
-
__decorate([
|
|
124
|
-
(0, common_1.InjectTool)(),
|
|
125
|
-
__metadata("design:type", runtime_error_tool_1.RuntimeErrorTool)
|
|
126
|
-
], DelegateErrorWorkflow.prototype, "runtimeError", void 0);
|
|
127
|
-
__decorate([
|
|
128
|
-
(0, common_1.InjectTool)(),
|
|
129
|
-
__metadata("design:type", failing_sub_workflow_tool_1.FailingSubWorkflowTool)
|
|
130
|
-
], DelegateErrorWorkflow.prototype, "failingSubWorkflow", void 0);
|
|
131
|
-
__decorate([
|
|
132
|
-
(0, common_1.Initial)({ to: 'ready' }),
|
|
123
|
+
(0, common_2.Transition)({ to: 'ready' }),
|
|
133
124
|
__metadata("design:type", Function),
|
|
134
|
-
__metadata("design:paramtypes", []),
|
|
125
|
+
__metadata("design:paramtypes", [Object]),
|
|
135
126
|
__metadata("design:returntype", Promise)
|
|
136
127
|
], DelegateErrorWorkflow.prototype, "setup", null);
|
|
137
128
|
__decorate([
|
|
138
|
-
(0,
|
|
129
|
+
(0, common_2.Transition)({ from: 'ready', to: 'prompt_executed' }),
|
|
139
130
|
__metadata("design:type", Function),
|
|
140
|
-
__metadata("design:paramtypes", []),
|
|
131
|
+
__metadata("design:paramtypes", [Object]),
|
|
141
132
|
__metadata("design:returntype", Promise)
|
|
142
133
|
], DelegateErrorWorkflow.prototype, "llmTurn", null);
|
|
143
134
|
__decorate([
|
|
144
|
-
(0,
|
|
145
|
-
(0,
|
|
135
|
+
(0, common_2.Transition)({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 }),
|
|
136
|
+
(0, common_2.Guard)('hasToolCalls'),
|
|
146
137
|
__metadata("design:type", Function),
|
|
147
|
-
__metadata("design:paramtypes", []),
|
|
138
|
+
__metadata("design:paramtypes", [Object]),
|
|
148
139
|
__metadata("design:returntype", Promise)
|
|
149
140
|
], DelegateErrorWorkflow.prototype, "executeToolCalls", null);
|
|
150
141
|
__decorate([
|
|
151
|
-
(0,
|
|
142
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true }),
|
|
152
143
|
__metadata("design:type", Function),
|
|
153
|
-
__metadata("design:paramtypes", [Object]),
|
|
144
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
154
145
|
__metadata("design:returntype", Promise)
|
|
155
146
|
], DelegateErrorWorkflow.prototype, "toolResultReceived", null);
|
|
156
147
|
__decorate([
|
|
157
|
-
(0,
|
|
158
|
-
(0,
|
|
148
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'ready' }),
|
|
149
|
+
(0, common_2.Guard)('allToolsComplete'),
|
|
159
150
|
__metadata("design:type", Function),
|
|
160
|
-
__metadata("design:paramtypes", []),
|
|
151
|
+
__metadata("design:paramtypes", [Object]),
|
|
161
152
|
__metadata("design:returntype", Promise)
|
|
162
153
|
], DelegateErrorWorkflow.prototype, "toolsComplete", null);
|
|
163
154
|
__decorate([
|
|
164
|
-
(0,
|
|
155
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'ready', wait: true }),
|
|
165
156
|
__metadata("design:type", Function),
|
|
166
|
-
__metadata("design:paramtypes", []),
|
|
157
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
167
158
|
__metadata("design:returntype", Promise)
|
|
168
159
|
], DelegateErrorWorkflow.prototype, "cancelPendingTools", null);
|
|
169
160
|
__decorate([
|
|
170
|
-
(0,
|
|
171
|
-
(0,
|
|
161
|
+
(0, common_2.Transition)({ from: 'prompt_executed', to: 'end' }),
|
|
162
|
+
(0, common_2.Guard)('isEndTurn'),
|
|
172
163
|
__metadata("design:type", Function),
|
|
173
|
-
__metadata("design:paramtypes", []),
|
|
164
|
+
__metadata("design:paramtypes", [Object]),
|
|
174
165
|
__metadata("design:returntype", Promise)
|
|
175
166
|
], DelegateErrorWorkflow.prototype, "respond", null);
|
|
176
167
|
exports.DelegateErrorWorkflow = DelegateErrorWorkflow = __decorate([
|
|
177
|
-
(0,
|
|
178
|
-
|
|
179
|
-
|
|
168
|
+
(0, common_2.Workflow)({
|
|
169
|
+
title: 'Delegate Error Handling Example',
|
|
170
|
+
description: 'Demonstrates how tool errors (validation, runtime, and failed sub-workflows)\nare handled by DelegateToolCalls and fed back to the LLM for self-correction.\n\nThe workflow instructs the LLM to:\n1. Call strictSchema with wrong args (triggers Zod validation error)\n2. Observe the error and retry with correct args\n3. Call runtimeError with shouldFail: true (triggers runtime error)\n4. Observe the error and retry with shouldFail: false\n5. Call failingSubWorkflow (launches a sub-workflow that fails)\n6. Observe the sub-workflow error and summarize',
|
|
171
|
+
widget: __dirname + '/delegate-error.ui.yaml',
|
|
172
|
+
}),
|
|
173
|
+
__param(6, (0, common_1.Inject)(common_2.TEMPLATE_RENDERER)),
|
|
174
|
+
__param(7, (0, common_1.Inject)(common_2.WORKFLOW_ORCHESTRATOR)),
|
|
175
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool,
|
|
176
|
+
llm_provider_module_1.LlmDelegateToolCallsTool,
|
|
177
|
+
llm_provider_module_1.LlmUpdateToolResultTool,
|
|
178
|
+
strict_schema_tool_1.StrictSchemaTool,
|
|
179
|
+
runtime_error_tool_1.RuntimeErrorTool,
|
|
180
|
+
failing_sub_workflow_tool_1.FailingSubWorkflowTool, Function, Object])
|
|
180
181
|
], DelegateErrorWorkflow);
|
|
181
182
|
//# sourceMappingURL=delegate-error.workflow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegate-error.workflow.js","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"delegate-error.workflow.js","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BaseTool, ToolCallOptions, ToolResult } from '@loopstack/common';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
|
+
import { FailingWorkflow } from '../workflows/failing.workflow';
|
|
4
|
+
export type FailingSubWorkflowToolResult = {
|
|
5
|
+
workflowId: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class FailingSubWorkflowTool extends BaseTool<object, object, FailingSubWorkflowToolResult> {
|
|
8
|
+
private readonly failingWorkflow;
|
|
9
|
+
constructor(failingWorkflow: FailingWorkflow);
|
|
10
|
+
protected handle(_args: object, _ctx: LoopstackContext, options?: ToolCallOptions): Promise<ToolResult<FailingSubWorkflowToolResult>>;
|
|
5
11
|
}
|
|
6
12
|
//# sourceMappingURL=failing-sub-workflow.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failing-sub-workflow.tool.d.ts","sourceRoot":"","sources":["../../src/tools/failing-sub-workflow.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"failing-sub-workflow.tool.d.ts","sourceRoot":"","sources":["../../src/tools/failing-sub-workflow.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,MAAM,MAAM,4BAA4B,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,qBAOa,sBAAuB,SAAQ,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,4BAA4B,CAAC;IACpF,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAAf,eAAe,EAAE,eAAe;cAI7C,MAAM,CACpB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,gBAAgB,EACtB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC;CAQrD"}
|
|
@@ -15,8 +15,12 @@ const common_1 = require("@loopstack/common");
|
|
|
15
15
|
const failing_workflow_1 = require("../workflows/failing.workflow");
|
|
16
16
|
let FailingSubWorkflowTool = class FailingSubWorkflowTool extends common_1.BaseTool {
|
|
17
17
|
failingWorkflow;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
constructor(failingWorkflow) {
|
|
19
|
+
super();
|
|
20
|
+
this.failingWorkflow = failingWorkflow;
|
|
21
|
+
}
|
|
22
|
+
async handle(_args, _ctx, options) {
|
|
23
|
+
const result = await this.failingWorkflow.run({}, { callback: options?.callback });
|
|
20
24
|
return {
|
|
21
25
|
data: { workflowId: result.workflowId },
|
|
22
26
|
pending: { workflowId: result.workflowId },
|
|
@@ -24,17 +28,13 @@ let FailingSubWorkflowTool = class FailingSubWorkflowTool extends common_1.BaseT
|
|
|
24
28
|
}
|
|
25
29
|
};
|
|
26
30
|
exports.FailingSubWorkflowTool = FailingSubWorkflowTool;
|
|
27
|
-
__decorate([
|
|
28
|
-
(0, common_1.InjectWorkflow)(),
|
|
29
|
-
__metadata("design:type", failing_workflow_1.FailingWorkflow)
|
|
30
|
-
], FailingSubWorkflowTool.prototype, "failingWorkflow", void 0);
|
|
31
31
|
exports.FailingSubWorkflowTool = FailingSubWorkflowTool = __decorate([
|
|
32
32
|
(0, common_1.Tool)({
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
33
|
+
name: 'failing_sub_workflow',
|
|
34
|
+
description: 'Launch an async sub-workflow that always fails. ' +
|
|
35
|
+
'Used to test that failed sub-workflow errors propagate back to the parent.',
|
|
37
36
|
schema: zod_1.z.object({}),
|
|
38
|
-
})
|
|
37
|
+
}),
|
|
38
|
+
__metadata("design:paramtypes", [failing_workflow_1.FailingWorkflow])
|
|
39
39
|
], FailingSubWorkflowTool);
|
|
40
40
|
//# sourceMappingURL=failing-sub-workflow.tool.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failing-sub-workflow.tool.js","sourceRoot":"","sources":["../../src/tools/failing-sub-workflow.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,
|
|
1
|
+
{"version":3,"file":"failing-sub-workflow.tool.js","sourceRoot":"","sources":["../../src/tools/failing-sub-workflow.tool.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,8CAAgF;AAEhF,oEAAgE;AAWzD,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,iBAAsD;IACnE;IAA7B,YAA6B,eAAgC;QAC3D,KAAK,EAAE,CAAC;QADmB,oBAAe,GAAf,eAAe,CAAiB;IAE7D,CAAC;IAES,KAAK,CAAC,MAAM,CACpB,KAAa,EACb,IAAsB,EACtB,OAAyB;QAEzB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEnF,OAAO;YACL,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;YACvC,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE;SAC3C,CAAC;IACJ,CAAC;CACF,CAAA;AAjBY,wDAAsB;iCAAtB,sBAAsB;IAPlC,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EACT,kDAAkD;YAClD,4EAA4E;QAC9E,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,CAAC;KACrB,CAAC;qCAE8C,kCAAe;GADlD,sBAAsB,CAiBlC"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { BaseTool, ToolResult } from '@loopstack/common';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
|
+
export type RuntimeErrorToolResult = string;
|
|
4
|
+
export declare class RuntimeErrorTool extends BaseTool<{
|
|
5
|
+
shouldFail: boolean;
|
|
6
|
+
}, object, RuntimeErrorToolResult> {
|
|
7
|
+
protected handle(args: {
|
|
4
8
|
shouldFail: boolean;
|
|
5
|
-
}): Promise<ToolResult
|
|
9
|
+
}, _ctx: LoopstackContext): Promise<ToolResult<RuntimeErrorToolResult>>;
|
|
6
10
|
}
|
|
7
11
|
//# sourceMappingURL=runtime-error.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-error.tool.d.ts","sourceRoot":"","sources":["../../src/tools/runtime-error.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-error.tool.d.ts","sourceRoot":"","sources":["../../src/tools/runtime-error.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE5C,qBASa,gBAAiB,SAAQ,QAAQ,CAAC;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,EAAE,MAAM,EAAE,sBAAsB,CAAC;cACrF,MAAM,CACpB,IAAI,EAAE;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,EAC7B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;CAS/C"}
|
|
@@ -10,7 +10,7 @@ exports.RuntimeErrorTool = void 0;
|
|
|
10
10
|
const zod_1 = require("zod");
|
|
11
11
|
const common_1 = require("@loopstack/common");
|
|
12
12
|
let RuntimeErrorTool = class RuntimeErrorTool extends common_1.BaseTool {
|
|
13
|
-
|
|
13
|
+
async handle(args, _ctx) {
|
|
14
14
|
if (args.shouldFail) {
|
|
15
15
|
throw new Error('Simulated runtime error: external service unavailable.');
|
|
16
16
|
}
|
|
@@ -22,10 +22,9 @@ let RuntimeErrorTool = class RuntimeErrorTool extends common_1.BaseTool {
|
|
|
22
22
|
exports.RuntimeErrorTool = RuntimeErrorTool;
|
|
23
23
|
exports.RuntimeErrorTool = RuntimeErrorTool = __decorate([
|
|
24
24
|
(0, common_1.Tool)({
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
25
|
+
name: 'runtime_error',
|
|
26
|
+
description: 'Perform an action that may fail at runtime. ' +
|
|
27
|
+
'Pass shouldFail: true to simulate a runtime error, or false to succeed.',
|
|
29
28
|
schema: zod_1.z.object({
|
|
30
29
|
shouldFail: zod_1.z.boolean().describe('Whether the tool should simulate a runtime failure.'),
|
|
31
30
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-error.tool.js","sourceRoot":"","sources":["../../src/tools/runtime-error.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;
|
|
1
|
+
{"version":3,"file":"runtime-error.tool.js","sourceRoot":"","sources":["../../src/tools/runtime-error.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;AAcxD,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,iBAAiE;IAC3F,KAAK,CAAC,MAAM,CACpB,IAA6B,EAC7B,IAAsB;QAEtB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,gCAAgC;SACvC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAbY,4CAAgB;2BAAhB,gBAAgB;IAT5B,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,8CAA8C;YAC9C,yEAAyE;QAC3E,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,UAAU,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;SACxF,CAAC;KACH,CAAC;GACW,gBAAgB,CAa5B"}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { BaseTool, ToolResult } from '@loopstack/common';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
|
+
export type StrictSchemaToolResult = string;
|
|
4
|
+
export declare class StrictSchemaTool extends BaseTool<{
|
|
5
|
+
name: string;
|
|
6
|
+
}, object, StrictSchemaToolResult> {
|
|
7
|
+
protected handle(args: {
|
|
4
8
|
name: string;
|
|
5
|
-
}): Promise<ToolResult
|
|
9
|
+
}, _ctx: LoopstackContext): Promise<ToolResult<StrictSchemaToolResult>>;
|
|
6
10
|
}
|
|
7
11
|
//# sourceMappingURL=strict-schema.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strict-schema.tool.d.ts","sourceRoot":"","sources":["../../src/tools/strict-schema.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"strict-schema.tool.d.ts","sourceRoot":"","sources":["../../src/tools/strict-schema.tool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAQ,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE5C,qBASa,gBAAiB,SAAQ,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,sBAAsB,CAAC;cAC9E,MAAM,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;CAKpH"}
|
|
@@ -10,7 +10,7 @@ exports.StrictSchemaTool = void 0;
|
|
|
10
10
|
const zod_1 = require("zod");
|
|
11
11
|
const common_1 = require("@loopstack/common");
|
|
12
12
|
let StrictSchemaTool = class StrictSchemaTool extends common_1.BaseTool {
|
|
13
|
-
|
|
13
|
+
async handle(args, _ctx) {
|
|
14
14
|
return Promise.resolve({
|
|
15
15
|
data: `Hello, ${args.name}! Nice to meet you.`,
|
|
16
16
|
});
|
|
@@ -19,9 +19,8 @@ let StrictSchemaTool = class StrictSchemaTool extends common_1.BaseTool {
|
|
|
19
19
|
exports.StrictSchemaTool = StrictSchemaTool;
|
|
20
20
|
exports.StrictSchemaTool = StrictSchemaTool = __decorate([
|
|
21
21
|
(0, common_1.Tool)({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
22
|
+
name: 'strict_schema',
|
|
23
|
+
description: 'Greet a person by name. Requires a name argument. ' + 'Returns a greeting message.',
|
|
25
24
|
schema: zod_1.z
|
|
26
25
|
.object({
|
|
27
26
|
name: zod_1.z.string().describe('The name of the person to greet.'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strict-schema.tool.js","sourceRoot":"","sources":["../../src/tools/strict-schema.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;
|
|
1
|
+
{"version":3,"file":"strict-schema.tool.js","sourceRoot":"","sources":["../../src/tools/strict-schema.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAA+D;AAcxD,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,iBAA0D;IACpF,KAAK,CAAC,MAAM,CAAC,IAAsB,EAAE,IAAsB;QACnE,OAAO,OAAO,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,UAAU,IAAI,CAAC,IAAI,qBAAqB;SAC/C,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AANY,4CAAgB;2BAAhB,gBAAgB;IAT5B,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,oDAAoD,GAAG,6BAA6B;QACjG,MAAM,EAAE,OAAC;aACN,MAAM,CAAC;YACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;SAC9D,CAAC;aACD,MAAM,EAAE;KACZ,CAAC;GACW,gBAAgB,CAM5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failing.workflow.d.ts","sourceRoot":"","sources":["../../src/workflows/failing.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"failing.workflow.d.ts","sourceRoot":"","sources":["../../src/workflows/failing.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAwB,MAAM,mBAAmB,CAAC;AAMvE,qBACa,eAAgB,SAAQ,YAAY;IAEzC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAG/E"}
|
|
@@ -12,18 +12,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.FailingWorkflow = void 0;
|
|
13
13
|
const common_1 = require("@loopstack/common");
|
|
14
14
|
let FailingWorkflow = class FailingWorkflow extends common_1.BaseWorkflow {
|
|
15
|
-
start() {
|
|
15
|
+
async start(_state) {
|
|
16
16
|
return Promise.reject(new Error('Simulated sub-workflow failure.'));
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
19
|
exports.FailingWorkflow = FailingWorkflow;
|
|
20
20
|
__decorate([
|
|
21
|
-
(0, common_1.
|
|
21
|
+
(0, common_1.Transition)({ to: 'done' }),
|
|
22
22
|
__metadata("design:type", Function),
|
|
23
|
-
__metadata("design:paramtypes", []),
|
|
23
|
+
__metadata("design:paramtypes", [Object]),
|
|
24
24
|
__metadata("design:returntype", Promise)
|
|
25
25
|
], FailingWorkflow.prototype, "start", null);
|
|
26
26
|
exports.FailingWorkflow = FailingWorkflow = __decorate([
|
|
27
|
-
(0, common_1.Workflow)({})
|
|
27
|
+
(0, common_1.Workflow)({ title: 'Failing Workflow' })
|
|
28
28
|
], FailingWorkflow);
|
|
29
29
|
//# sourceMappingURL=failing.workflow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failing.workflow.js","sourceRoot":"","sources":["../../src/workflows/failing.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"failing.workflow.js","sourceRoot":"","sources":["../../src/workflows/failing.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuE;AAOhE,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,qBAAY;IAEzC,AAAN,KAAK,CAAC,KAAK,CAAC,MAA+B;QACzC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;IACtE,CAAC;CACF,CAAA;AALY,0CAAe;AAEpB;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;;;;4CAG1B;0BAJU,eAAe;IAD3B,IAAA,iBAAQ,EAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC;GAC3B,eAAe,CAK3B"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"example",
|
|
10
10
|
"workflow"
|
|
11
11
|
],
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.23.0",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Jakob Klippel",
|
|
@@ -30,10 +30,9 @@
|
|
|
30
30
|
"watch": "nest build --watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@loopstack/claude-module": "^0.
|
|
34
|
-
"@loopstack/llm-provider-module": "^0.
|
|
35
|
-
"@loopstack/common": "^0.
|
|
36
|
-
"@loopstack/core": "^0.31.0",
|
|
33
|
+
"@loopstack/claude-module": "^0.25.0",
|
|
34
|
+
"@loopstack/llm-provider-module": "^0.4.0",
|
|
35
|
+
"@loopstack/common": "^0.32.0",
|
|
37
36
|
"@nestjs/common": "^11.1.19",
|
|
38
37
|
"zod": "^4.3.6"
|
|
39
38
|
},
|
|
@@ -2,7 +2,7 @@ import { TestingModule } from '@nestjs/testing';
|
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
3
|
import { ClaudeModule } from '@loopstack/claude-module';
|
|
4
4
|
import { WorkflowProcessorService } from '@loopstack/core';
|
|
5
|
-
import { LlmGenerateTextTool } from '@loopstack/llm-provider-module';
|
|
5
|
+
import { LlmGenerateTextTool, LlmProviderModule } from '@loopstack/llm-provider-module';
|
|
6
6
|
import { ToolMock, createStatelessContext, createWorkflowTest } from '@loopstack/testing';
|
|
7
7
|
import { DelegateErrorWorkflow } from '../delegate-error.workflow';
|
|
8
8
|
import { FailingSubWorkflowTool } from '../tools/failing-sub-workflow.tool';
|
|
@@ -56,7 +56,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
56
56
|
beforeEach(async () => {
|
|
57
57
|
module = await createWorkflowTest()
|
|
58
58
|
.forWorkflow(DelegateErrorWorkflow)
|
|
59
|
-
.withImports(ClaudeModule)
|
|
59
|
+
.withImports(LlmProviderModule.forRoot({}), ClaudeModule)
|
|
60
60
|
.withToolOverride(LlmGenerateTextTool)
|
|
61
61
|
// Real tools — we want to test actual validation and runtime errors
|
|
62
62
|
.withProviders(StrictSchemaTool, RuntimeErrorTool, FailingSubWorkflowTool, FailingWorkflow)
|
|
@@ -78,7 +78,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
78
78
|
describe('validation error (bad schema args)', () => {
|
|
79
79
|
it('should capture validation error as isError tool result and loop back to ready', async () => {
|
|
80
80
|
mockLlm.call
|
|
81
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
81
|
+
.mockResolvedValueOnce(mockToolUseResponse('strict_schema', {}))
|
|
82
82
|
.mockResolvedValueOnce(mockEndTurnResponse('Done.'));
|
|
83
83
|
|
|
84
84
|
const context = createStatelessContext();
|
|
@@ -100,7 +100,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
100
100
|
describe('runtime error (tool throws)', () => {
|
|
101
101
|
it('should capture runtime error as isError tool result and loop back to ready', async () => {
|
|
102
102
|
mockLlm.call
|
|
103
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
103
|
+
.mockResolvedValueOnce(mockToolUseResponse('runtime_error', { shouldFail: true }))
|
|
104
104
|
.mockResolvedValueOnce(mockEndTurnResponse('Done.'));
|
|
105
105
|
|
|
106
106
|
const context = createStatelessContext();
|
|
@@ -122,7 +122,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
122
122
|
describe('successful tool call', () => {
|
|
123
123
|
it('should process successful tool call without errors', async () => {
|
|
124
124
|
mockLlm.call
|
|
125
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
125
|
+
.mockResolvedValueOnce(mockToolUseResponse('strict_schema', { name: 'World' }))
|
|
126
126
|
.mockResolvedValueOnce(mockEndTurnResponse('Done.'));
|
|
127
127
|
|
|
128
128
|
const context = createStatelessContext();
|
|
@@ -144,7 +144,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
144
144
|
describe('error metadata in tool result documents', () => {
|
|
145
145
|
it('should include validation error message in isError tool result', async () => {
|
|
146
146
|
mockLlm.call
|
|
147
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
147
|
+
.mockResolvedValueOnce(mockToolUseResponse('strict_schema', {}))
|
|
148
148
|
.mockResolvedValueOnce(mockEndTurnResponse('Done.'));
|
|
149
149
|
|
|
150
150
|
const context = createStatelessContext();
|
|
@@ -168,7 +168,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
168
168
|
|
|
169
169
|
it('should include runtime error message in isError tool result', async () => {
|
|
170
170
|
mockLlm.call
|
|
171
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
171
|
+
.mockResolvedValueOnce(mockToolUseResponse('runtime_error', { shouldFail: true }))
|
|
172
172
|
.mockResolvedValueOnce(mockEndTurnResponse('Done.'));
|
|
173
173
|
|
|
174
174
|
const context = createStatelessContext();
|
|
@@ -193,7 +193,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
193
193
|
describe('validation and runtime errors produce identical structure', () => {
|
|
194
194
|
it('should produce the same isError tool result shape for both error types', async () => {
|
|
195
195
|
mockLlm.call
|
|
196
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
196
|
+
.mockResolvedValueOnce(mockToolUseResponse('strict_schema', {}))
|
|
197
197
|
.mockResolvedValueOnce(mockEndTurnResponse('Recovered.'));
|
|
198
198
|
const context1 = createStatelessContext();
|
|
199
199
|
const result1 = await processor.process(workflow, {}, context1);
|
|
@@ -208,7 +208,7 @@ describe('DelegateErrorWorkflow', () => {
|
|
|
208
208
|
);
|
|
209
209
|
|
|
210
210
|
mockLlm.call
|
|
211
|
-
.mockResolvedValueOnce(mockToolUseResponse('
|
|
211
|
+
.mockResolvedValueOnce(mockToolUseResponse('runtime_error', { shouldFail: true }))
|
|
212
212
|
.mockResolvedValueOnce(mockEndTurnResponse('Recovered.'));
|
|
213
213
|
const context2 = createStatelessContext();
|
|
214
214
|
const result2 = await processor.process(workflow, {}, context2);
|
|
@@ -1,22 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
The workflow instructs the LLM to:
|
|
8
|
-
1. Call strictSchema with wrong args (triggers Zod validation error)
|
|
9
|
-
2. Observe the error and retry with correct args
|
|
10
|
-
3. Call runtimeError with shouldFail: true (triggers runtime error)
|
|
11
|
-
4. Observe the error and retry with shouldFail: false
|
|
12
|
-
5. Call failingSubWorkflow (launches a sub-workflow that fails)
|
|
13
|
-
6. Observe the sub-workflow error and summarize
|
|
14
|
-
|
|
15
|
-
ui:
|
|
16
|
-
widgets:
|
|
17
|
-
- widget: button
|
|
18
|
-
showWhen:
|
|
19
|
-
- awaiting_tools
|
|
20
|
-
options:
|
|
21
|
-
transition: cancelPendingTools
|
|
22
|
-
label: Cancel pending tools
|
|
1
|
+
widget: button
|
|
2
|
+
showWhen:
|
|
3
|
+
- awaiting_tools
|
|
4
|
+
options:
|
|
5
|
+
transition: cancelPendingTools
|
|
6
|
+
label: Cancel pending tools
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
1
2
|
import {
|
|
2
3
|
BaseWorkflow,
|
|
3
|
-
Final,
|
|
4
4
|
Guard,
|
|
5
|
-
Initial,
|
|
6
|
-
InjectTool,
|
|
7
5
|
MessageDocument,
|
|
8
|
-
|
|
6
|
+
TEMPLATE_RENDERER,
|
|
9
7
|
Transition,
|
|
8
|
+
WORKFLOW_ORCHESTRATOR,
|
|
10
9
|
Workflow,
|
|
11
10
|
} from '@loopstack/common';
|
|
11
|
+
import type { LoopstackContext, TemplateRenderFn, WorkflowOrchestrator } from '@loopstack/common';
|
|
12
12
|
import type { LlmDelegateResult, LlmGenerateTextResult, LlmResultMeta } from '@loopstack/llm-provider-module';
|
|
13
13
|
import {
|
|
14
14
|
LlmDelegateToolCallsTool,
|
|
@@ -20,6 +20,13 @@ import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
|
|
|
20
20
|
import { RuntimeErrorTool } from './tools/runtime-error.tool';
|
|
21
21
|
import { StrictSchemaTool } from './tools/strict-schema.tool';
|
|
22
22
|
|
|
23
|
+
interface DelegateErrorState {
|
|
24
|
+
llmResult?: LlmGenerateTextResult;
|
|
25
|
+
llmMeta?: LlmResultMeta;
|
|
26
|
+
delegateResult?: LlmDelegateResult;
|
|
27
|
+
turnCount: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
* Demonstrates how tool errors (validation, runtime, and failed sub-workflows)
|
|
25
32
|
* are handled by DelegateToolCalls and fed back to the LLM for self-correction.
|
|
@@ -29,31 +36,28 @@ import { StrictSchemaTool } from './tools/strict-schema.tool';
|
|
|
29
36
|
* and that the LLM agent loop handles them correctly.
|
|
30
37
|
*/
|
|
31
38
|
@Workflow({
|
|
32
|
-
|
|
39
|
+
title: 'Delegate Error Handling Example',
|
|
40
|
+
description:
|
|
41
|
+
'Demonstrates how tool errors (validation, runtime, and failed sub-workflows)\nare handled by DelegateToolCalls and fed back to the LLM for self-correction.\n\nThe workflow instructs the LLM to:\n1. Call strictSchema with wrong args (triggers Zod validation error)\n2. Observe the error and retry with correct args\n3. Call runtimeError with shouldFail: true (triggers runtime error)\n4. Observe the error and retry with shouldFail: false\n5. Call failingSubWorkflow (launches a sub-workflow that fails)\n6. Observe the sub-workflow error and summarize',
|
|
42
|
+
widget: __dirname + '/delegate-error.ui.yaml',
|
|
33
43
|
})
|
|
34
|
-
export class DelegateErrorWorkflow extends BaseWorkflow {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
llmResult?: LlmGenerateTextResult;
|
|
48
|
-
llmMeta?: LlmResultMeta;
|
|
49
|
-
delegateResult?: LlmDelegateResult;
|
|
50
|
-
turnCount!: number;
|
|
51
|
-
|
|
52
|
-
@Initial({ to: 'ready' })
|
|
53
|
-
async setup() {
|
|
54
|
-
this.turnCount = 0;
|
|
44
|
+
export class DelegateErrorWorkflow extends BaseWorkflow<Record<string, unknown>, DelegateErrorState> {
|
|
45
|
+
constructor(
|
|
46
|
+
private readonly llmGenerateText: LlmGenerateTextTool,
|
|
47
|
+
private readonly llmDelegateToolCalls: LlmDelegateToolCallsTool,
|
|
48
|
+
private readonly llmUpdateToolResult: LlmUpdateToolResultTool,
|
|
49
|
+
private readonly strictSchema: StrictSchemaTool,
|
|
50
|
+
private readonly runtimeError: RuntimeErrorTool,
|
|
51
|
+
private readonly failingSubWorkflow: FailingSubWorkflowTool,
|
|
52
|
+
@Inject(TEMPLATE_RENDERER) private readonly render: TemplateRenderFn,
|
|
53
|
+
@Inject(WORKFLOW_ORCHESTRATOR) private readonly orchestrator: WorkflowOrchestrator,
|
|
54
|
+
) {
|
|
55
|
+
super();
|
|
56
|
+
}
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
@Transition({ to: 'ready' })
|
|
59
|
+
async setup(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
60
|
+
await this.documentStore.save(MessageDocument, {
|
|
57
61
|
role: 'assistant',
|
|
58
62
|
content:
|
|
59
63
|
'# Delegate Error Handling Example\n\n' +
|
|
@@ -61,91 +65,101 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
|
|
|
61
65
|
'The LLM will deliberately trigger errors, then self-correct.',
|
|
62
66
|
});
|
|
63
67
|
|
|
64
|
-
await this.
|
|
68
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
65
69
|
role: 'user',
|
|
66
70
|
content:
|
|
67
71
|
'Follow the instructions in your system prompt exactly. ' +
|
|
68
72
|
'Start with step 1: call strictSchema with no arguments.',
|
|
69
73
|
});
|
|
74
|
+
return { ...state, turnCount: 0 };
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
@Transition({ from: 'ready', to: 'prompt_executed' })
|
|
73
|
-
async llmTurn() {
|
|
74
|
-
this.
|
|
75
|
-
const result: ToolResult<LlmGenerateTextResult, LlmResultMeta> = await this.llmGenerateText.call(
|
|
78
|
+
async llmTurn(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
79
|
+
const result = await this.llmGenerateText.call(
|
|
76
80
|
{},
|
|
77
81
|
{
|
|
78
82
|
config: {
|
|
83
|
+
provider: 'claude',
|
|
84
|
+
model: 'claude-sonnet-4-6',
|
|
79
85
|
system: this.render(__dirname + '/templates/system.md'),
|
|
86
|
+
tools: ['strict_schema', 'runtime_error', 'failing_sub_workflow'],
|
|
80
87
|
},
|
|
81
88
|
},
|
|
82
89
|
);
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
return {
|
|
91
|
+
...state,
|
|
92
|
+
turnCount: state.turnCount + 1,
|
|
93
|
+
llmResult: result.data,
|
|
94
|
+
llmMeta: result.metadata as LlmResultMeta | undefined,
|
|
95
|
+
};
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
@Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
|
|
88
99
|
@Guard('hasToolCalls')
|
|
89
|
-
async executeToolCalls() {
|
|
90
|
-
await this.
|
|
91
|
-
meta: { response:
|
|
100
|
+
async executeToolCalls(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
101
|
+
await this.documentStore.save(LlmMessageDocument, state.llmResult!.message, {
|
|
102
|
+
meta: { response: state.llmResult!.response, provider: state.llmMeta!.provider },
|
|
92
103
|
});
|
|
93
104
|
|
|
94
|
-
const result
|
|
95
|
-
message:
|
|
105
|
+
const result = await this.llmDelegateToolCalls.call({
|
|
106
|
+
message: state.llmResult!.message,
|
|
96
107
|
callback: { transition: 'toolResultReceived' },
|
|
97
108
|
});
|
|
98
|
-
|
|
109
|
+
return { ...state, delegateResult: result.data };
|
|
99
110
|
}
|
|
100
111
|
|
|
101
112
|
@Transition({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true })
|
|
102
|
-
async toolResultReceived(payload: unknown) {
|
|
103
|
-
const result = await this.llmUpdateToolResult.call(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
async toolResultReceived(state: DelegateErrorState, payload: unknown): Promise<DelegateErrorState> {
|
|
114
|
+
const result = await this.llmUpdateToolResult.call(
|
|
115
|
+
{
|
|
116
|
+
delegateResult: state.delegateResult!,
|
|
117
|
+
completedTool: payload,
|
|
118
|
+
},
|
|
119
|
+
{ config: { provider: 'claude' } },
|
|
120
|
+
);
|
|
121
|
+
return { ...state, delegateResult: result.data as LlmDelegateResult };
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
@Transition({ from: 'awaiting_tools', to: 'ready' })
|
|
111
125
|
@Guard('allToolsComplete')
|
|
112
|
-
async toolsComplete() {
|
|
113
|
-
await this.
|
|
126
|
+
async toolsComplete(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
127
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
114
128
|
role: 'user',
|
|
115
|
-
content:
|
|
129
|
+
content: state.delegateResult!.toolResults.map((tr) => ({
|
|
116
130
|
type: 'tool_result' as const,
|
|
117
131
|
toolCallId: tr.toolCallId,
|
|
118
132
|
content: tr.content ?? '',
|
|
119
133
|
isError: tr.isError ?? false,
|
|
120
134
|
})),
|
|
121
135
|
});
|
|
136
|
+
return state;
|
|
122
137
|
}
|
|
123
138
|
|
|
124
139
|
@Transition({ from: 'awaiting_tools', to: 'ready', wait: true })
|
|
125
|
-
async cancelPendingTools() {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
await this.orchestrator.cancelChildren(workflowId);
|
|
129
|
-
}
|
|
140
|
+
async cancelPendingTools(state: DelegateErrorState, ctx: LoopstackContext): Promise<DelegateErrorState> {
|
|
141
|
+
await this.orchestrator.cancelChildren(ctx.workflowId);
|
|
142
|
+
return state;
|
|
130
143
|
}
|
|
131
144
|
|
|
132
|
-
@
|
|
145
|
+
@Transition({ from: 'prompt_executed', to: 'end' })
|
|
133
146
|
@Guard('isEndTurn')
|
|
134
|
-
async respond() {
|
|
135
|
-
await this.
|
|
136
|
-
meta: { response:
|
|
147
|
+
async respond(state: DelegateErrorState): Promise<unknown> {
|
|
148
|
+
await this.documentStore.save(LlmMessageDocument, state.llmResult!.message, {
|
|
149
|
+
meta: { response: state.llmResult!.response, provider: state.llmMeta!.provider },
|
|
137
150
|
});
|
|
151
|
+
return {};
|
|
138
152
|
}
|
|
139
153
|
|
|
140
|
-
private hasToolCalls(): boolean {
|
|
141
|
-
return
|
|
154
|
+
private hasToolCalls(state: DelegateErrorState): boolean {
|
|
155
|
+
return state.llmResult?.message.stopReason === 'tool_use';
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
private allToolsComplete(): boolean {
|
|
145
|
-
return !!
|
|
158
|
+
private allToolsComplete(state: DelegateErrorState): boolean {
|
|
159
|
+
return !!state.delegateResult?.allCompleted;
|
|
146
160
|
}
|
|
147
161
|
|
|
148
|
-
private isEndTurn(): boolean {
|
|
149
|
-
return
|
|
162
|
+
private isEndTurn(state: DelegateErrorState): boolean {
|
|
163
|
+
return state.llmResult?.message.stopReason === 'end_turn';
|
|
150
164
|
}
|
|
151
165
|
}
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { BaseTool,
|
|
2
|
+
import { BaseTool, Tool, ToolCallOptions, ToolResult } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
3
4
|
import { FailingWorkflow } from '../workflows/failing.workflow';
|
|
4
5
|
|
|
6
|
+
export type FailingSubWorkflowToolResult = { workflowId: string };
|
|
7
|
+
|
|
5
8
|
@Tool({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
},
|
|
9
|
+
name: 'failing_sub_workflow',
|
|
10
|
+
description:
|
|
11
|
+
'Launch an async sub-workflow that always fails. ' +
|
|
12
|
+
'Used to test that failed sub-workflow errors propagate back to the parent.',
|
|
11
13
|
schema: z.object({}),
|
|
12
14
|
})
|
|
13
|
-
export class FailingSubWorkflowTool extends BaseTool {
|
|
14
|
-
|
|
15
|
+
export class FailingSubWorkflowTool extends BaseTool<object, object, FailingSubWorkflowToolResult> {
|
|
16
|
+
constructor(private readonly failingWorkflow: FailingWorkflow) {
|
|
17
|
+
super();
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
async
|
|
17
|
-
|
|
20
|
+
protected async handle(
|
|
21
|
+
_args: object,
|
|
22
|
+
_ctx: LoopstackContext,
|
|
23
|
+
options?: ToolCallOptions,
|
|
24
|
+
): Promise<ToolResult<FailingSubWorkflowToolResult>> {
|
|
25
|
+
const result = await this.failingWorkflow.run({}, { callback: options?.callback });
|
|
18
26
|
|
|
19
27
|
return {
|
|
20
28
|
data: { workflowId: result.workflowId },
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseTool, Tool, ToolResult } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
4
|
+
|
|
5
|
+
export type RuntimeErrorToolResult = string;
|
|
3
6
|
|
|
4
7
|
@Tool({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
},
|
|
8
|
+
name: 'runtime_error',
|
|
9
|
+
description:
|
|
10
|
+
'Perform an action that may fail at runtime. ' +
|
|
11
|
+
'Pass shouldFail: true to simulate a runtime error, or false to succeed.',
|
|
10
12
|
schema: z.object({
|
|
11
13
|
shouldFail: z.boolean().describe('Whether the tool should simulate a runtime failure.'),
|
|
12
14
|
}),
|
|
13
15
|
})
|
|
14
|
-
export class RuntimeErrorTool extends BaseTool {
|
|
15
|
-
|
|
16
|
+
export class RuntimeErrorTool extends BaseTool<{ shouldFail: boolean }, object, RuntimeErrorToolResult> {
|
|
17
|
+
protected async handle(
|
|
18
|
+
args: { shouldFail: boolean },
|
|
19
|
+
_ctx: LoopstackContext,
|
|
20
|
+
): Promise<ToolResult<RuntimeErrorToolResult>> {
|
|
16
21
|
if (args.shouldFail) {
|
|
17
22
|
throw new Error('Simulated runtime error: external service unavailable.');
|
|
18
23
|
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { BaseTool, Tool, ToolResult } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext } from '@loopstack/common';
|
|
4
|
+
|
|
5
|
+
export type StrictSchemaToolResult = string;
|
|
3
6
|
|
|
4
7
|
@Tool({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
},
|
|
8
|
+
name: 'strict_schema',
|
|
9
|
+
description: 'Greet a person by name. Requires a name argument. ' + 'Returns a greeting message.',
|
|
8
10
|
schema: z
|
|
9
11
|
.object({
|
|
10
12
|
name: z.string().describe('The name of the person to greet.'),
|
|
11
13
|
})
|
|
12
14
|
.strict(),
|
|
13
15
|
})
|
|
14
|
-
export class StrictSchemaTool extends BaseTool {
|
|
15
|
-
|
|
16
|
+
export class StrictSchemaTool extends BaseTool<{ name: string }, object, StrictSchemaToolResult> {
|
|
17
|
+
protected async handle(args: { name: string }, _ctx: LoopstackContext): Promise<ToolResult<StrictSchemaToolResult>> {
|
|
16
18
|
return Promise.resolve({
|
|
17
19
|
data: `Hello, ${args.name}! Nice to meet you.`,
|
|
18
20
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { BaseWorkflow,
|
|
1
|
+
import { BaseWorkflow, Transition, Workflow } from '@loopstack/common';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A minimal sub-workflow that always fails on its initial transition.
|
|
5
5
|
* Used to verify that failed sub-workflow callbacks propagate errors to the parent.
|
|
6
6
|
*/
|
|
7
|
-
@Workflow({})
|
|
7
|
+
@Workflow({ title: 'Failing Workflow' })
|
|
8
8
|
export class FailingWorkflow extends BaseWorkflow {
|
|
9
|
-
@
|
|
10
|
-
start(): Promise<unknown
|
|
9
|
+
@Transition({ to: 'done' })
|
|
10
|
+
async start(_state: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
11
11
|
return Promise.reject(new Error('Simulated sub-workflow failure.'));
|
|
12
12
|
}
|
|
13
13
|
}
|