@loopstack/delegate-error-example-workflow 0.22.1 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/delegate-error.ui.yaml +6 -22
- package/dist/delegate-error.workflow.d.ts +20 -14
- package/dist/delegate-error.workflow.d.ts.map +1 -1
- package/dist/delegate-error.workflow.js +86 -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 +75 -70
- 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,35 @@
|
|
|
1
1
|
import { BaseWorkflow } from '@loopstack/common';
|
|
2
|
+
import type { LoopstackContext, 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 orchestrator;
|
|
22
|
+
constructor(llmGenerateText: LlmGenerateTextTool, llmDelegateToolCalls: LlmDelegateToolCallsTool, llmUpdateToolResult: LlmUpdateToolResultTool, strictSchema: StrictSchemaTool, runtimeError: RuntimeErrorTool, failingSubWorkflow: FailingSubWorkflowTool, orchestrator: WorkflowOrchestrator);
|
|
23
|
+
setup(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
24
|
+
llmTurn(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
25
|
+
executeToolCalls(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
26
|
+
toolResultReceived(state: DelegateErrorState, payload: unknown): Promise<DelegateErrorState>;
|
|
27
|
+
toolsComplete(state: DelegateErrorState): Promise<DelegateErrorState>;
|
|
28
|
+
cancelPendingTools(state: DelegateErrorState, ctx: LoopstackContext): Promise<DelegateErrorState>;
|
|
29
|
+
respond(state: DelegateErrorState): Promise<unknown>;
|
|
25
30
|
private hasToolCalls;
|
|
26
31
|
private allToolsComplete;
|
|
27
32
|
private isEndTurn;
|
|
28
33
|
}
|
|
34
|
+
export {};
|
|
29
35
|
//# 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,EAAE,YAAY,EAAuE,MAAM,mBAAmB,CAAC;AACtH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAChF,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;IACJ,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAN3C,eAAe,EAAE,mBAAmB,EACpC,oBAAoB,EAAE,wBAAwB,EAC9C,mBAAmB,EAAE,uBAAuB,EAC5C,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE,gBAAgB,EAC9B,kBAAkB,EAAE,sBAAsB,EACX,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,172 @@ 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
|
+
orchestrator;
|
|
30
|
+
constructor(llmGenerateText, llmDelegateToolCalls, llmUpdateToolResult, strictSchema, runtimeError, failingSubWorkflow, orchestrator) {
|
|
31
|
+
super();
|
|
32
|
+
this.llmGenerateText = llmGenerateText;
|
|
33
|
+
this.llmDelegateToolCalls = llmDelegateToolCalls;
|
|
34
|
+
this.llmUpdateToolResult = llmUpdateToolResult;
|
|
35
|
+
this.strictSchema = strictSchema;
|
|
36
|
+
this.runtimeError = runtimeError;
|
|
37
|
+
this.failingSubWorkflow = failingSubWorkflow;
|
|
38
|
+
this.orchestrator = orchestrator;
|
|
39
|
+
}
|
|
40
|
+
async setup(state) {
|
|
41
|
+
await this.documentStore.save(common_2.MessageDocument, {
|
|
32
42
|
role: 'assistant',
|
|
33
43
|
content: '# Delegate Error Handling Example\n\n' +
|
|
34
44
|
'This workflow tests how tool errors are handled and fed back to the LLM.\n\n' +
|
|
35
45
|
'The LLM will deliberately trigger errors, then self-correct.',
|
|
36
46
|
});
|
|
37
|
-
await this.
|
|
47
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
38
48
|
role: 'user',
|
|
39
49
|
content: 'Follow the instructions in your system prompt exactly. ' +
|
|
40
50
|
'Start with step 1: call strictSchema with no arguments.',
|
|
41
51
|
});
|
|
52
|
+
return { ...state, turnCount: 0 };
|
|
42
53
|
}
|
|
43
|
-
async llmTurn() {
|
|
44
|
-
this.turnCount++;
|
|
54
|
+
async llmTurn(state) {
|
|
45
55
|
const result = await this.llmGenerateText.call({}, {
|
|
46
56
|
config: {
|
|
57
|
+
provider: 'claude',
|
|
58
|
+
model: 'claude-sonnet-4-6',
|
|
47
59
|
system: this.render(__dirname + '/templates/system.md'),
|
|
60
|
+
tools: ['strict_schema', 'runtime_error', 'failing_sub_workflow'],
|
|
48
61
|
},
|
|
49
62
|
});
|
|
50
|
-
|
|
51
|
-
|
|
63
|
+
return {
|
|
64
|
+
...state,
|
|
65
|
+
turnCount: state.turnCount + 1,
|
|
66
|
+
llmResult: result.data,
|
|
67
|
+
llmMeta: result.metadata,
|
|
68
|
+
};
|
|
52
69
|
}
|
|
53
|
-
async executeToolCalls() {
|
|
54
|
-
await this.
|
|
55
|
-
meta: { response:
|
|
70
|
+
async executeToolCalls(state) {
|
|
71
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, state.llmResult.message, {
|
|
72
|
+
meta: { response: state.llmResult.response, provider: state.llmMeta.provider },
|
|
56
73
|
});
|
|
57
74
|
const result = await this.llmDelegateToolCalls.call({
|
|
58
|
-
message:
|
|
75
|
+
message: state.llmResult.message,
|
|
59
76
|
callback: { transition: 'toolResultReceived' },
|
|
60
77
|
});
|
|
61
|
-
|
|
78
|
+
return { ...state, delegateResult: result.data };
|
|
62
79
|
}
|
|
63
|
-
async toolResultReceived(payload) {
|
|
80
|
+
async toolResultReceived(state, payload) {
|
|
64
81
|
const result = await this.llmUpdateToolResult.call({
|
|
65
|
-
delegateResult:
|
|
82
|
+
delegateResult: state.delegateResult,
|
|
66
83
|
completedTool: payload,
|
|
67
|
-
});
|
|
68
|
-
|
|
84
|
+
}, { config: { provider: 'claude' } });
|
|
85
|
+
return { ...state, delegateResult: result.data };
|
|
69
86
|
}
|
|
70
|
-
async toolsComplete() {
|
|
71
|
-
await this.
|
|
87
|
+
async toolsComplete(state) {
|
|
88
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, {
|
|
72
89
|
role: 'user',
|
|
73
|
-
content:
|
|
90
|
+
content: state.delegateResult.toolResults.map((tr) => ({
|
|
74
91
|
type: 'tool_result',
|
|
75
92
|
toolCallId: tr.toolCallId,
|
|
76
93
|
content: tr.content ?? '',
|
|
77
94
|
isError: tr.isError ?? false,
|
|
78
95
|
})),
|
|
79
96
|
});
|
|
97
|
+
return state;
|
|
80
98
|
}
|
|
81
|
-
async cancelPendingTools() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await this.orchestrator.cancelChildren(workflowId);
|
|
85
|
-
}
|
|
99
|
+
async cancelPendingTools(state, ctx) {
|
|
100
|
+
await this.orchestrator.cancelChildren(ctx.workflowId);
|
|
101
|
+
return state;
|
|
86
102
|
}
|
|
87
|
-
async respond() {
|
|
88
|
-
await this.
|
|
89
|
-
meta: { response:
|
|
103
|
+
async respond(state) {
|
|
104
|
+
await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, state.llmResult.message, {
|
|
105
|
+
meta: { response: state.llmResult.response, provider: state.llmMeta.provider },
|
|
90
106
|
});
|
|
107
|
+
return {};
|
|
91
108
|
}
|
|
92
|
-
hasToolCalls() {
|
|
93
|
-
return
|
|
109
|
+
hasToolCalls(state) {
|
|
110
|
+
return state.llmResult?.message.stopReason === 'tool_use';
|
|
94
111
|
}
|
|
95
|
-
allToolsComplete() {
|
|
96
|
-
return !!
|
|
112
|
+
allToolsComplete(state) {
|
|
113
|
+
return !!state.delegateResult?.allCompleted;
|
|
97
114
|
}
|
|
98
|
-
isEndTurn() {
|
|
99
|
-
return
|
|
115
|
+
isEndTurn(state) {
|
|
116
|
+
return state.llmResult?.message.stopReason === 'end_turn';
|
|
100
117
|
}
|
|
101
118
|
};
|
|
102
119
|
exports.DelegateErrorWorkflow = DelegateErrorWorkflow;
|
|
103
120
|
__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' }),
|
|
121
|
+
(0, common_2.Transition)({ to: 'ready' }),
|
|
133
122
|
__metadata("design:type", Function),
|
|
134
|
-
__metadata("design:paramtypes", []),
|
|
123
|
+
__metadata("design:paramtypes", [Object]),
|
|
135
124
|
__metadata("design:returntype", Promise)
|
|
136
125
|
], DelegateErrorWorkflow.prototype, "setup", null);
|
|
137
126
|
__decorate([
|
|
138
|
-
(0,
|
|
127
|
+
(0, common_2.Transition)({ from: 'ready', to: 'prompt_executed' }),
|
|
139
128
|
__metadata("design:type", Function),
|
|
140
|
-
__metadata("design:paramtypes", []),
|
|
129
|
+
__metadata("design:paramtypes", [Object]),
|
|
141
130
|
__metadata("design:returntype", Promise)
|
|
142
131
|
], DelegateErrorWorkflow.prototype, "llmTurn", null);
|
|
143
132
|
__decorate([
|
|
144
|
-
(0,
|
|
145
|
-
(0,
|
|
133
|
+
(0, common_2.Transition)({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 }),
|
|
134
|
+
(0, common_2.Guard)('hasToolCalls'),
|
|
146
135
|
__metadata("design:type", Function),
|
|
147
|
-
__metadata("design:paramtypes", []),
|
|
136
|
+
__metadata("design:paramtypes", [Object]),
|
|
148
137
|
__metadata("design:returntype", Promise)
|
|
149
138
|
], DelegateErrorWorkflow.prototype, "executeToolCalls", null);
|
|
150
139
|
__decorate([
|
|
151
|
-
(0,
|
|
140
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true }),
|
|
152
141
|
__metadata("design:type", Function),
|
|
153
|
-
__metadata("design:paramtypes", [Object]),
|
|
142
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
154
143
|
__metadata("design:returntype", Promise)
|
|
155
144
|
], DelegateErrorWorkflow.prototype, "toolResultReceived", null);
|
|
156
145
|
__decorate([
|
|
157
|
-
(0,
|
|
158
|
-
(0,
|
|
146
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'ready' }),
|
|
147
|
+
(0, common_2.Guard)('allToolsComplete'),
|
|
159
148
|
__metadata("design:type", Function),
|
|
160
|
-
__metadata("design:paramtypes", []),
|
|
149
|
+
__metadata("design:paramtypes", [Object]),
|
|
161
150
|
__metadata("design:returntype", Promise)
|
|
162
151
|
], DelegateErrorWorkflow.prototype, "toolsComplete", null);
|
|
163
152
|
__decorate([
|
|
164
|
-
(0,
|
|
153
|
+
(0, common_2.Transition)({ from: 'awaiting_tools', to: 'ready', wait: true }),
|
|
165
154
|
__metadata("design:type", Function),
|
|
166
|
-
__metadata("design:paramtypes", []),
|
|
155
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
167
156
|
__metadata("design:returntype", Promise)
|
|
168
157
|
], DelegateErrorWorkflow.prototype, "cancelPendingTools", null);
|
|
169
158
|
__decorate([
|
|
170
|
-
(0,
|
|
171
|
-
(0,
|
|
159
|
+
(0, common_2.Transition)({ from: 'prompt_executed', to: 'end' }),
|
|
160
|
+
(0, common_2.Guard)('isEndTurn'),
|
|
172
161
|
__metadata("design:type", Function),
|
|
173
|
-
__metadata("design:paramtypes", []),
|
|
162
|
+
__metadata("design:paramtypes", [Object]),
|
|
174
163
|
__metadata("design:returntype", Promise)
|
|
175
164
|
], DelegateErrorWorkflow.prototype, "respond", null);
|
|
176
165
|
exports.DelegateErrorWorkflow = DelegateErrorWorkflow = __decorate([
|
|
177
|
-
(0,
|
|
178
|
-
|
|
179
|
-
|
|
166
|
+
(0, common_2.Workflow)({
|
|
167
|
+
title: 'Delegate Error Handling Example',
|
|
168
|
+
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',
|
|
169
|
+
widget: __dirname + '/delegate-error.ui.yaml',
|
|
170
|
+
}),
|
|
171
|
+
__param(6, (0, common_1.Inject)(common_2.WORKFLOW_ORCHESTRATOR)),
|
|
172
|
+
__metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool,
|
|
173
|
+
llm_provider_module_1.LlmDelegateToolCallsTool,
|
|
174
|
+
llm_provider_module_1.LlmUpdateToolResultTool,
|
|
175
|
+
strict_schema_tool_1.StrictSchemaTool,
|
|
176
|
+
runtime_error_tool_1.RuntimeErrorTool,
|
|
177
|
+
failing_sub_workflow_tool_1.FailingSubWorkflowTool, Object])
|
|
180
178
|
], DelegateErrorWorkflow);
|
|
181
179
|
//# 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.1",
|
|
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.1",
|
|
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,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Guard,
|
|
5
|
-
Initial,
|
|
6
|
-
InjectTool,
|
|
7
|
-
MessageDocument,
|
|
8
|
-
ToolResult,
|
|
9
|
-
Transition,
|
|
10
|
-
Workflow,
|
|
11
|
-
} from '@loopstack/common';
|
|
1
|
+
import { Inject } from '@nestjs/common';
|
|
2
|
+
import { BaseWorkflow, Guard, MessageDocument, Transition, WORKFLOW_ORCHESTRATOR, Workflow } from '@loopstack/common';
|
|
3
|
+
import type { LoopstackContext, WorkflowOrchestrator } from '@loopstack/common';
|
|
12
4
|
import type { LlmDelegateResult, LlmGenerateTextResult, LlmResultMeta } from '@loopstack/llm-provider-module';
|
|
13
5
|
import {
|
|
14
6
|
LlmDelegateToolCallsTool,
|
|
@@ -20,6 +12,13 @@ import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
|
|
|
20
12
|
import { RuntimeErrorTool } from './tools/runtime-error.tool';
|
|
21
13
|
import { StrictSchemaTool } from './tools/strict-schema.tool';
|
|
22
14
|
|
|
15
|
+
interface DelegateErrorState {
|
|
16
|
+
llmResult?: LlmGenerateTextResult;
|
|
17
|
+
llmMeta?: LlmResultMeta;
|
|
18
|
+
delegateResult?: LlmDelegateResult;
|
|
19
|
+
turnCount: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
23
22
|
/**
|
|
24
23
|
* Demonstrates how tool errors (validation, runtime, and failed sub-workflows)
|
|
25
24
|
* are handled by DelegateToolCalls and fed back to the LLM for self-correction.
|
|
@@ -29,31 +28,27 @@ import { StrictSchemaTool } from './tools/strict-schema.tool';
|
|
|
29
28
|
* and that the LLM agent loop handles them correctly.
|
|
30
29
|
*/
|
|
31
30
|
@Workflow({
|
|
32
|
-
|
|
31
|
+
title: 'Delegate Error Handling Example',
|
|
32
|
+
description:
|
|
33
|
+
'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',
|
|
34
|
+
widget: __dirname + '/delegate-error.ui.yaml',
|
|
33
35
|
})
|
|
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;
|
|
36
|
+
export class DelegateErrorWorkflow extends BaseWorkflow<Record<string, unknown>, DelegateErrorState> {
|
|
37
|
+
constructor(
|
|
38
|
+
private readonly llmGenerateText: LlmGenerateTextTool,
|
|
39
|
+
private readonly llmDelegateToolCalls: LlmDelegateToolCallsTool,
|
|
40
|
+
private readonly llmUpdateToolResult: LlmUpdateToolResultTool,
|
|
41
|
+
private readonly strictSchema: StrictSchemaTool,
|
|
42
|
+
private readonly runtimeError: RuntimeErrorTool,
|
|
43
|
+
private readonly failingSubWorkflow: FailingSubWorkflowTool,
|
|
44
|
+
@Inject(WORKFLOW_ORCHESTRATOR) private readonly orchestrator: WorkflowOrchestrator,
|
|
45
|
+
) {
|
|
46
|
+
super();
|
|
47
|
+
}
|
|
55
48
|
|
|
56
|
-
|
|
49
|
+
@Transition({ to: 'ready' })
|
|
50
|
+
async setup(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
51
|
+
await this.documentStore.save(MessageDocument, {
|
|
57
52
|
role: 'assistant',
|
|
58
53
|
content:
|
|
59
54
|
'# Delegate Error Handling Example\n\n' +
|
|
@@ -61,91 +56,101 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
|
|
|
61
56
|
'The LLM will deliberately trigger errors, then self-correct.',
|
|
62
57
|
});
|
|
63
58
|
|
|
64
|
-
await this.
|
|
59
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
65
60
|
role: 'user',
|
|
66
61
|
content:
|
|
67
62
|
'Follow the instructions in your system prompt exactly. ' +
|
|
68
63
|
'Start with step 1: call strictSchema with no arguments.',
|
|
69
64
|
});
|
|
65
|
+
return { ...state, turnCount: 0 };
|
|
70
66
|
}
|
|
71
67
|
|
|
72
68
|
@Transition({ from: 'ready', to: 'prompt_executed' })
|
|
73
|
-
async llmTurn() {
|
|
74
|
-
this.
|
|
75
|
-
const result: ToolResult<LlmGenerateTextResult, LlmResultMeta> = await this.llmGenerateText.call(
|
|
69
|
+
async llmTurn(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
70
|
+
const result = await this.llmGenerateText.call(
|
|
76
71
|
{},
|
|
77
72
|
{
|
|
78
73
|
config: {
|
|
74
|
+
provider: 'claude',
|
|
75
|
+
model: 'claude-sonnet-4-6',
|
|
79
76
|
system: this.render(__dirname + '/templates/system.md'),
|
|
77
|
+
tools: ['strict_schema', 'runtime_error', 'failing_sub_workflow'],
|
|
80
78
|
},
|
|
81
79
|
},
|
|
82
80
|
);
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
return {
|
|
82
|
+
...state,
|
|
83
|
+
turnCount: state.turnCount + 1,
|
|
84
|
+
llmResult: result.data,
|
|
85
|
+
llmMeta: result.metadata as LlmResultMeta | undefined,
|
|
86
|
+
};
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
@Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
|
|
88
90
|
@Guard('hasToolCalls')
|
|
89
|
-
async executeToolCalls() {
|
|
90
|
-
await this.
|
|
91
|
-
meta: { response:
|
|
91
|
+
async executeToolCalls(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
92
|
+
await this.documentStore.save(LlmMessageDocument, state.llmResult!.message, {
|
|
93
|
+
meta: { response: state.llmResult!.response, provider: state.llmMeta!.provider },
|
|
92
94
|
});
|
|
93
95
|
|
|
94
|
-
const result
|
|
95
|
-
message:
|
|
96
|
+
const result = await this.llmDelegateToolCalls.call({
|
|
97
|
+
message: state.llmResult!.message,
|
|
96
98
|
callback: { transition: 'toolResultReceived' },
|
|
97
99
|
});
|
|
98
|
-
|
|
100
|
+
return { ...state, delegateResult: result.data };
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
@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
|
-
|
|
104
|
+
async toolResultReceived(state: DelegateErrorState, payload: unknown): Promise<DelegateErrorState> {
|
|
105
|
+
const result = await this.llmUpdateToolResult.call(
|
|
106
|
+
{
|
|
107
|
+
delegateResult: state.delegateResult!,
|
|
108
|
+
completedTool: payload,
|
|
109
|
+
},
|
|
110
|
+
{ config: { provider: 'claude' } },
|
|
111
|
+
);
|
|
112
|
+
return { ...state, delegateResult: result.data as LlmDelegateResult };
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
@Transition({ from: 'awaiting_tools', to: 'ready' })
|
|
111
116
|
@Guard('allToolsComplete')
|
|
112
|
-
async toolsComplete() {
|
|
113
|
-
await this.
|
|
117
|
+
async toolsComplete(state: DelegateErrorState): Promise<DelegateErrorState> {
|
|
118
|
+
await this.documentStore.save(LlmMessageDocument, {
|
|
114
119
|
role: 'user',
|
|
115
|
-
content:
|
|
120
|
+
content: state.delegateResult!.toolResults.map((tr) => ({
|
|
116
121
|
type: 'tool_result' as const,
|
|
117
122
|
toolCallId: tr.toolCallId,
|
|
118
123
|
content: tr.content ?? '',
|
|
119
124
|
isError: tr.isError ?? false,
|
|
120
125
|
})),
|
|
121
126
|
});
|
|
127
|
+
return state;
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
@Transition({ from: 'awaiting_tools', to: 'ready', wait: true })
|
|
125
|
-
async cancelPendingTools() {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
await this.orchestrator.cancelChildren(workflowId);
|
|
129
|
-
}
|
|
131
|
+
async cancelPendingTools(state: DelegateErrorState, ctx: LoopstackContext): Promise<DelegateErrorState> {
|
|
132
|
+
await this.orchestrator.cancelChildren(ctx.workflowId);
|
|
133
|
+
return state;
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
@
|
|
136
|
+
@Transition({ from: 'prompt_executed', to: 'end' })
|
|
133
137
|
@Guard('isEndTurn')
|
|
134
|
-
async respond() {
|
|
135
|
-
await this.
|
|
136
|
-
meta: { response:
|
|
138
|
+
async respond(state: DelegateErrorState): Promise<unknown> {
|
|
139
|
+
await this.documentStore.save(LlmMessageDocument, state.llmResult!.message, {
|
|
140
|
+
meta: { response: state.llmResult!.response, provider: state.llmMeta!.provider },
|
|
137
141
|
});
|
|
142
|
+
return {};
|
|
138
143
|
}
|
|
139
144
|
|
|
140
|
-
private hasToolCalls(): boolean {
|
|
141
|
-
return
|
|
145
|
+
private hasToolCalls(state: DelegateErrorState): boolean {
|
|
146
|
+
return state.llmResult?.message.stopReason === 'tool_use';
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
private allToolsComplete(): boolean {
|
|
145
|
-
return !!
|
|
149
|
+
private allToolsComplete(state: DelegateErrorState): boolean {
|
|
150
|
+
return !!state.delegateResult?.allCompleted;
|
|
146
151
|
}
|
|
147
152
|
|
|
148
|
-
private isEndTurn(): boolean {
|
|
149
|
-
return
|
|
153
|
+
private isEndTurn(state: DelegateErrorState): boolean {
|
|
154
|
+
return state.llmResult?.message.stopReason === 'end_turn';
|
|
150
155
|
}
|
|
151
156
|
}
|
|
@@ -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
|
}
|