@loopstack/delegate-error-example-workflow 0.21.6 → 0.22.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.
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-error-example.module.d.ts","sourceRoot":"","sources":["../src/delegate-error-example.module.ts"],"names":[],"mappings":"AASA,qBAKa,0BAA0B;CAAG"}
1
+ {"version":3,"file":"delegate-error-example.module.d.ts","sourceRoot":"","sources":["../src/delegate-error-example.module.ts"],"names":[],"mappings":"AAQA,qBAKa,0BAA0B;CAAG"}
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.DelegateErrorExampleModule = void 0;
10
10
  const common_1 = require("@nestjs/common");
11
11
  const claude_module_1 = require("@loopstack/claude-module");
12
- const core_1 = require("@loopstack/core");
13
12
  const delegate_error_workflow_1 = require("./delegate-error.workflow");
14
13
  const failing_sub_workflow_tool_1 = require("./tools/failing-sub-workflow.tool");
15
14
  const runtime_error_tool_1 = require("./tools/runtime-error.tool");
@@ -20,7 +19,7 @@ let DelegateErrorExampleModule = class DelegateErrorExampleModule {
20
19
  exports.DelegateErrorExampleModule = DelegateErrorExampleModule;
21
20
  exports.DelegateErrorExampleModule = DelegateErrorExampleModule = __decorate([
22
21
  (0, common_1.Module)({
23
- imports: [core_1.LoopCoreModule, claude_module_1.ClaudeModule],
22
+ imports: [claude_module_1.ClaudeModule],
24
23
  providers: [strict_schema_tool_1.StrictSchemaTool, runtime_error_tool_1.RuntimeErrorTool, failing_sub_workflow_tool_1.FailingSubWorkflowTool, failing_workflow_1.FailingWorkflow, delegate_error_workflow_1.DelegateErrorWorkflow],
25
24
  exports: [delegate_error_workflow_1.DelegateErrorWorkflow],
26
25
  })
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-error-example.module.js","sourceRoot":"","sources":["../src/delegate-error-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD,0CAAiD;AACjD,uEAAkE;AAClE,iFAA2E;AAC3E,mEAA8D;AAC9D,mEAA8D;AAC9D,mEAA+D;AAOxD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;CAAG,CAAA;AAA7B,gEAA0B;qCAA1B,0BAA0B;IALtC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAc,EAAE,4BAAY,CAAC;QACvC,SAAS,EAAE,CAAC,qCAAgB,EAAE,qCAAgB,EAAE,kDAAsB,EAAE,kCAAe,EAAE,+CAAqB,CAAC;QAC/G,OAAO,EAAE,CAAC,+CAAqB,CAAC;KACjC,CAAC;GACW,0BAA0B,CAAG"}
1
+ {"version":3,"file":"delegate-error-example.module.js","sourceRoot":"","sources":["../src/delegate-error-example.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD,uEAAkE;AAClE,iFAA2E;AAC3E,mEAA8D;AAC9D,mEAA8D;AAC9D,mEAA+D;AAOxD,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;CAAG,CAAA;AAA7B,gEAA0B;qCAA1B,0BAA0B;IALtC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,SAAS,EAAE,CAAC,qCAAgB,EAAE,qCAAgB,EAAE,kDAAsB,EAAE,kCAAe,EAAE,+CAAqB,CAAC;QAC/G,OAAO,EAAE,CAAC,+CAAqB,CAAC;KACjC,CAAC;GACW,0BAA0B,CAAG"}
@@ -1,17 +1,19 @@
1
- import { ClaudeGenerateText, ClaudeGenerateTextResult, DelegateToolCalls, DelegateToolCallsResult, UpdateToolResult } from '@loopstack/claude-module';
2
1
  import { BaseWorkflow } from '@loopstack/common';
2
+ import type { LlmDelegateResult, LlmGenerateTextResult, LlmResultMeta } from '@loopstack/llm-provider-module';
3
+ import { LlmDelegateToolCallsTool, LlmGenerateTextTool, LlmUpdateToolResultTool } from '@loopstack/llm-provider-module';
3
4
  import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
4
5
  import { RuntimeErrorTool } from './tools/runtime-error.tool';
5
6
  import { StrictSchemaTool } from './tools/strict-schema.tool';
6
7
  export declare class DelegateErrorWorkflow extends BaseWorkflow {
7
- claudeGenerateText: ClaudeGenerateText;
8
- delegateToolCalls: DelegateToolCalls;
9
- updateToolResult: UpdateToolResult;
8
+ llmGenerateText: LlmGenerateTextTool;
9
+ llmDelegateToolCalls: LlmDelegateToolCallsTool;
10
+ llmUpdateToolResult: LlmUpdateToolResultTool;
10
11
  strictSchema: StrictSchemaTool;
11
12
  runtimeError: RuntimeErrorTool;
12
13
  failingSubWorkflow: FailingSubWorkflowTool;
13
- llmResult?: ClaudeGenerateTextResult;
14
- delegateResult?: DelegateToolCallsResult;
14
+ llmResult?: LlmGenerateTextResult;
15
+ llmMeta?: LlmResultMeta;
16
+ delegateResult?: LlmDelegateResult;
15
17
  turnCount: number;
16
18
  setup(): Promise<void>;
17
19
  llmTurn(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-error.workflow.d.ts","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EAExB,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,YAAY,EASb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAU9D,qBAGa,qBAAsB,SAAQ,YAAY;IACvC,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,YAAY,EAAE,gBAAgB,CAAC;IAC/B,kBAAkB,EAAE,sBAAsB,CAAC;IAEzD,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,SAAS,EAAG,MAAM,CAAC;IAGb,KAAK;IAoBL,OAAO;IAwBP,gBAAgB;IAUhB,kBAAkB,CAAC,OAAO,EAAE,OAAO;IAWnC,aAAa;IAGb,kBAAkB;IASlB,OAAO;IAIb,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,SAAS;CAGlB"}
1
+ {"version":3,"file":"delegate-error.workflow.d.ts","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EASb,MAAM,mBAAmB,CAAC;AAC3B,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;AAU9D,qBAGa,qBAAsB,SAAQ,YAAY;IAMrD,eAAe,EAAE,mBAAmB,CAAC;IACD,oBAAoB,EAAE,wBAAwB,CAAC;IAC/C,mBAAmB,EAAE,uBAAuB,CAAC;IACnE,YAAY,EAAE,gBAAgB,CAAC;IAC/B,YAAY,EAAE,gBAAgB,CAAC;IAC/B,kBAAkB,EAAE,sBAAsB,CAAC;IAEzD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,SAAS,EAAG,MAAM,CAAC;IAGb,KAAK;IAoBL,OAAO;IAgBP,gBAAgB;IAahB,kBAAkB,CAAC,OAAO,EAAE,OAAO;IAUnC,aAAa;IAab,kBAAkB;IASlB,OAAO;IAMb,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,SAAS;CAGlB"}
@@ -10,19 +10,20 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DelegateErrorWorkflow = void 0;
13
- const claude_module_1 = require("@loopstack/claude-module");
14
13
  const common_1 = require("@loopstack/common");
14
+ const llm_provider_module_1 = require("@loopstack/llm-provider-module");
15
15
  const failing_sub_workflow_tool_1 = require("./tools/failing-sub-workflow.tool");
16
16
  const runtime_error_tool_1 = require("./tools/runtime-error.tool");
17
17
  const strict_schema_tool_1 = require("./tools/strict-schema.tool");
18
18
  let DelegateErrorWorkflow = class DelegateErrorWorkflow extends common_1.BaseWorkflow {
19
- claudeGenerateText;
20
- delegateToolCalls;
21
- updateToolResult;
19
+ llmGenerateText;
20
+ llmDelegateToolCalls;
21
+ llmUpdateToolResult;
22
22
  strictSchema;
23
23
  runtimeError;
24
24
  failingSubWorkflow;
25
25
  llmResult;
26
+ llmMeta;
26
27
  delegateResult;
27
28
  turnCount;
28
29
  async setup() {
@@ -33,7 +34,7 @@ let DelegateErrorWorkflow = class DelegateErrorWorkflow extends common_1.BaseWor
33
34
  'This workflow tests how tool errors are handled and fed back to the LLM.\n\n' +
34
35
  'The LLM will deliberately trigger errors, then self-correct.',
35
36
  });
36
- await this.repository.save(claude_module_1.ClaudeMessageDocument, {
37
+ await this.repository.save(llm_provider_module_1.LlmMessageDocument, {
37
38
  role: 'user',
38
39
  content: 'Follow the instructions in your system prompt exactly. ' +
39
40
  'Start with step 1: call strictSchema with no arguments.',
@@ -41,41 +42,42 @@ let DelegateErrorWorkflow = class DelegateErrorWorkflow extends common_1.BaseWor
41
42
  }
42
43
  async llmTurn() {
43
44
  this.turnCount++;
44
- const result = await this.claudeGenerateText.call({
45
- system: 'You are a test assistant that follows instructions precisely. ' +
46
- 'You are fully autonomous — do NOT ask the user for input or confirmation. ' +
47
- 'Just proceed through each step on your own.\n\n' +
48
- 'Complete these steps IN ORDER. Do exactly one step per turn:\n\n' +
49
- '1. Call the `strictSchema` tool with NO arguments (empty object {}). This will fail — that is expected.\n' +
50
- '2. After seeing the validation error, call `strictSchema` correctly with { "name": "World" }.\n' +
51
- '3. Call the `runtimeError` tool with { "shouldFail": true }. This will fail — that is expected.\n' +
52
- '4. After seeing the runtime error, call `runtimeError` with { "shouldFail": false }.\n' +
53
- '5. Call the `failingSubWorkflow` tool with {}. This launches a sub-workflow that will fail — that is expected.\n' +
54
- '6. After seeing the sub-workflow error, respond with a brief summary of what happened (do NOT call any tools).\n\n' +
55
- 'IMPORTANT: Only perform ONE step per turn. Do NOT skip steps. Do NOT wait for user input between steps.',
56
- claude: { model: 'claude-sonnet-4-6' },
57
- messagesSearchTag: 'message',
58
- tools: ['strictSchema', 'runtimeError', 'failingSubWorkflow'],
45
+ const result = await this.llmGenerateText.call({}, {
46
+ config: {
47
+ system: this.render(__dirname + '/templates/system.md'),
48
+ },
59
49
  });
60
50
  this.llmResult = result.data;
51
+ this.llmMeta = result.metadata;
61
52
  }
62
53
  async executeToolCalls() {
63
- const result = await this.delegateToolCalls.call({
64
- message: this.llmResult,
65
- document: claude_module_1.ClaudeMessageDocument,
54
+ await this.repository.save(llm_provider_module_1.LlmMessageDocument, this.llmResult.message, {
55
+ meta: { response: this.llmResult.response, provider: this.llmMeta.provider },
56
+ });
57
+ const result = await this.llmDelegateToolCalls.call({
58
+ message: this.llmResult.message,
66
59
  callback: { transition: 'toolResultReceived' },
67
60
  });
68
61
  this.delegateResult = result.data;
69
62
  }
70
63
  async toolResultReceived(payload) {
71
- const result = await this.updateToolResult.call({
64
+ const result = await this.llmUpdateToolResult.call({
72
65
  delegateResult: this.delegateResult,
73
66
  completedTool: payload,
74
- document: claude_module_1.ClaudeMessageDocument,
75
67
  });
76
68
  this.delegateResult = result.data;
77
69
  }
78
- async toolsComplete() { }
70
+ async toolsComplete() {
71
+ await this.repository.save(llm_provider_module_1.LlmMessageDocument, {
72
+ role: 'user',
73
+ content: this.delegateResult.toolResults.map((tr) => ({
74
+ type: 'tool_result',
75
+ toolCallId: tr.toolCallId,
76
+ content: tr.content ?? '',
77
+ isError: tr.isError ?? false,
78
+ })),
79
+ });
80
+ }
79
81
  async cancelPendingTools() {
80
82
  const workflowId = this.ctx.context.workflowId;
81
83
  if (workflowId) {
@@ -83,31 +85,37 @@ let DelegateErrorWorkflow = class DelegateErrorWorkflow extends common_1.BaseWor
83
85
  }
84
86
  }
85
87
  async respond() {
86
- await this.repository.save(claude_module_1.ClaudeMessageDocument, this.llmResult, { id: this.llmResult.id });
88
+ await this.repository.save(llm_provider_module_1.LlmMessageDocument, this.llmResult.message, {
89
+ meta: { response: this.llmResult.response, provider: this.llmMeta.provider },
90
+ });
87
91
  }
88
92
  hasToolCalls() {
89
- return this.llmResult?.stop_reason === 'tool_use';
93
+ return this.llmResult?.message.stopReason === 'tool_use';
90
94
  }
91
95
  allToolsComplete() {
92
96
  return !!this.delegateResult?.allCompleted;
93
97
  }
94
98
  isEndTurn() {
95
- return this.llmResult?.stop_reason === 'end_turn';
99
+ return this.llmResult?.message.stopReason === 'end_turn';
96
100
  }
97
101
  };
98
102
  exports.DelegateErrorWorkflow = DelegateErrorWorkflow;
99
103
  __decorate([
100
- (0, common_1.InjectTool)(),
101
- __metadata("design:type", claude_module_1.ClaudeGenerateText)
102
- ], DelegateErrorWorkflow.prototype, "claudeGenerateText", void 0);
104
+ (0, common_1.InjectTool)({
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);
103
111
  __decorate([
104
- (0, common_1.InjectTool)(),
105
- __metadata("design:type", claude_module_1.DelegateToolCalls)
106
- ], DelegateErrorWorkflow.prototype, "delegateToolCalls", void 0);
112
+ (0, common_1.InjectTool)({ provider: 'claude' }),
113
+ __metadata("design:type", llm_provider_module_1.LlmDelegateToolCallsTool)
114
+ ], DelegateErrorWorkflow.prototype, "llmDelegateToolCalls", void 0);
107
115
  __decorate([
108
- (0, common_1.InjectTool)(),
109
- __metadata("design:type", claude_module_1.UpdateToolResult)
110
- ], DelegateErrorWorkflow.prototype, "updateToolResult", void 0);
116
+ (0, common_1.InjectTool)({ provider: 'claude' }),
117
+ __metadata("design:type", llm_provider_module_1.LlmUpdateToolResultTool)
118
+ ], DelegateErrorWorkflow.prototype, "llmUpdateToolResult", void 0);
111
119
  __decorate([
112
120
  (0, common_1.InjectTool)(),
113
121
  __metadata("design:type", strict_schema_tool_1.StrictSchemaTool)
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-error.workflow.js","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"delegate-error.workflow.js","sourceRoot":"","sources":["../src/delegate-error.workflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ You are a test assistant that follows instructions precisely. You are fully autonomous — do NOT ask the user for input or confirmation. Just proceed through each step on your own.
2
+
3
+ Complete these steps IN ORDER. Do exactly one step per turn:
4
+
5
+ 1. Call the `strictSchema` tool with NO arguments (empty object {}). This will fail — that is expected.
6
+ 2. After seeing the validation error, call `strictSchema` correctly with { "name": "World" }.
7
+ 3. Call the `runtimeError` tool with { "shouldFail": true }. This will fail — that is expected.
8
+ 4. After seeing the runtime error, call `runtimeError` with { "shouldFail": false }.
9
+ 5. Call the `failingSubWorkflow` tool with {}. This launches a sub-workflow that will fail — that is expected.
10
+ 6. After seeing the sub-workflow error, respond with a brief summary of what happened (do NOT call any tools).
11
+
12
+ IMPORTANT: Only perform ONE step per turn. Do NOT skip steps. Do NOT wait for user input between steps.
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "example",
10
10
  "workflow"
11
11
  ],
12
- "version": "0.21.6",
12
+ "version": "0.22.0",
13
13
  "license": "MIT",
14
14
  "author": {
15
15
  "name": "Jakob Klippel",
@@ -26,13 +26,14 @@
26
26
  "compile": "tsc --noEmit",
27
27
  "format": "prettier --write .",
28
28
  "lint": "eslint .",
29
- "test": "jest --passWithNoTests",
29
+ "test": "vitest run",
30
30
  "watch": "nest build --watch"
31
31
  },
32
32
  "dependencies": {
33
- "@loopstack/claude-module": "^0.22.5",
34
- "@loopstack/common": "^0.28.0",
35
- "@loopstack/core": "^0.28.0",
33
+ "@loopstack/claude-module": "^0.24.0",
34
+ "@loopstack/llm-provider-module": "^0.3.0",
35
+ "@loopstack/common": "^0.30.0",
36
+ "@loopstack/core": "^0.30.0",
36
37
  "@nestjs/common": "^11.1.19",
37
38
  "zod": "^4.3.6"
38
39
  },
@@ -40,34 +41,9 @@
40
41
  "dist",
41
42
  "src"
42
43
  ],
43
- "jest": {
44
- "testEnvironment": "node",
45
- "rootDir": "src",
46
- "testRegex": ".*\\.spec\\.ts$",
47
- "transform": {
48
- "^.+\\.ts$": "ts-jest"
49
- },
50
- "testTimeout": 10000,
51
- "forceExit": true,
52
- "maxWorkers": 1
53
- },
54
- "loopstack": {
55
- "modules": [
56
- {
57
- "path": "src/delegate-error-example.module.ts",
58
- "className": "DelegateErrorExampleModule"
59
- }
60
- ],
61
- "workflows": [
62
- {
63
- "path": "src/delegate-error.workflow.ts",
64
- "className": "DelegateErrorWorkflow",
65
- "propertyName": "delegateError"
66
- }
67
- ],
68
- "installModes": [
69
- "add",
70
- "install"
71
- ]
44
+ "devDependencies": {
45
+ "vitest": "^4.1.6",
46
+ "@swc/core": "^1.15.33",
47
+ "unplugin-swc": "^1.5.9"
72
48
  }
73
49
  }
@@ -1,6 +1,8 @@
1
1
  import { TestingModule } from '@nestjs/testing';
2
- import { ClaudeGenerateText, ClaudeModule } from '@loopstack/claude-module';
3
- import { LoopCoreModule, WorkflowProcessorService } from '@loopstack/core';
2
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
+ import { ClaudeModule } from '@loopstack/claude-module';
4
+ import { WorkflowProcessorService } from '@loopstack/core';
5
+ import { LlmGenerateTextTool } from '@loopstack/llm-provider-module';
4
6
  import { ToolMock, createStatelessContext, createWorkflowTest } from '@loopstack/testing';
5
7
  import { DelegateErrorWorkflow } from '../delegate-error.workflow';
6
8
  import { FailingSubWorkflowTool } from '../tools/failing-sub-workflow.tool';
@@ -11,17 +13,20 @@ import { FailingWorkflow } from '../workflows/failing.workflow';
11
13
  /**
12
14
  * Helper to create a mock LLM response with a single tool_use block.
13
15
  */
14
- function mockToolUseResponse(toolName: string, input: Record<string, unknown>, toolUseId = 'toolu_test_1') {
16
+ function mockToolUseResponse(toolName: string, args: Record<string, unknown>, toolCallId = 'toolu_test_1') {
15
17
  return {
16
18
  data: {
17
- id: 'msg_test',
18
- role: 'assistant',
19
- stop_reason: 'tool_use',
20
- content: [
21
- { type: 'text', text: `Calling ${toolName}...` },
22
- { type: 'tool_use', id: toolUseId, name: toolName, input },
23
- ],
19
+ message: {
20
+ id: 'msg_test',
21
+ role: 'assistant',
22
+ content: [
23
+ { type: 'text', text: `Calling ${toolName}...` },
24
+ { type: 'tool_call', id: toolCallId, name: toolName, args },
25
+ ],
26
+ stopReason: 'tool_use',
27
+ },
24
28
  },
29
+ metadata: { provider: 'claude', model: 'claude-sonnet-4-6' },
25
30
  };
26
31
  }
27
32
 
@@ -31,11 +36,14 @@ function mockToolUseResponse(toolName: string, input: Record<string, unknown>, t
31
36
  function mockEndTurnResponse(text: string) {
32
37
  return {
33
38
  data: {
34
- id: 'msg_final',
35
- role: 'assistant',
36
- stop_reason: 'end_turn',
37
- content: [{ type: 'text', text }],
39
+ message: {
40
+ id: 'msg_final',
41
+ role: 'assistant',
42
+ content: [{ type: 'text', text }],
43
+ stopReason: 'end_turn',
44
+ },
38
45
  },
46
+ metadata: { provider: 'claude', model: 'claude-sonnet-4-6' },
39
47
  };
40
48
  }
41
49
 
@@ -43,20 +51,20 @@ describe('DelegateErrorWorkflow', () => {
43
51
  let module: TestingModule;
44
52
  let workflow: DelegateErrorWorkflow;
45
53
  let processor: WorkflowProcessorService;
46
- let mockClaude: ToolMock;
54
+ let mockLlm: ToolMock;
47
55
 
48
56
  beforeEach(async () => {
49
57
  module = await createWorkflowTest()
50
58
  .forWorkflow(DelegateErrorWorkflow)
51
- .withImports(LoopCoreModule, ClaudeModule)
52
- .withToolOverride(ClaudeGenerateText)
59
+ .withImports(ClaudeModule)
60
+ .withToolOverride(LlmGenerateTextTool)
53
61
  // Real tools — we want to test actual validation and runtime errors
54
62
  .withProviders(StrictSchemaTool, RuntimeErrorTool, FailingSubWorkflowTool, FailingWorkflow)
55
63
  .compile();
56
64
 
57
65
  workflow = module.get(DelegateErrorWorkflow);
58
66
  processor = module.get(WorkflowProcessorService);
59
- mockClaude = module.get(ClaudeGenerateText);
67
+ mockLlm = module.get(LlmGenerateTextTool);
60
68
  });
61
69
 
62
70
  afterEach(async () => {
@@ -68,9 +76,8 @@ describe('DelegateErrorWorkflow', () => {
68
76
  });
69
77
 
70
78
  describe('validation error (bad schema args)', () => {
71
- it('should capture validation error as is_error tool result and loop back to ready', async () => {
72
- // LLM calls strictSchema with empty args — Zod validation will fail
73
- mockClaude.call
79
+ it('should capture validation error as isError tool result and loop back to ready', async () => {
80
+ mockLlm.call
74
81
  .mockResolvedValueOnce(mockToolUseResponse('strictSchema', {}))
75
82
  .mockResolvedValueOnce(mockEndTurnResponse('Done.'));
76
83
 
@@ -79,24 +86,20 @@ describe('DelegateErrorWorkflow', () => {
79
86
 
80
87
  expect(result.hasError).toBe(false);
81
88
  expect(result.place).toBe('end');
89
+ expect(mockLlm.call).toHaveBeenCalledTimes(2);
82
90
 
83
- // ClaudeGenerateText should have been called twice:
84
- // 1st: LLM returns bad tool call → error fed back → loops to ready
85
- // 2nd: LLM sees the error and responds with end_turn
86
- expect(mockClaude.call).toHaveBeenCalledTimes(2);
87
-
88
- // Should have tool result documents with is_error
89
- const toolResultDocs = result.documents.filter((d) =>
90
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
91
+ const toolResultDocs = result.documents.filter(
92
+ (d) =>
93
+ Array.isArray(d.content?.content) &&
94
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
91
95
  );
92
96
  expect(toolResultDocs.length).toBeGreaterThan(0);
93
97
  });
94
98
  });
95
99
 
96
100
  describe('runtime error (tool throws)', () => {
97
- it('should capture runtime error as is_error tool result and loop back to ready', async () => {
98
- // LLM calls runtimeError with shouldFail: true — tool will throw
99
- mockClaude.call
101
+ it('should capture runtime error as isError tool result and loop back to ready', async () => {
102
+ mockLlm.call
100
103
  .mockResolvedValueOnce(mockToolUseResponse('runtimeError', { shouldFail: true }))
101
104
  .mockResolvedValueOnce(mockEndTurnResponse('Done.'));
102
105
 
@@ -105,10 +108,12 @@ describe('DelegateErrorWorkflow', () => {
105
108
 
106
109
  expect(result.hasError).toBe(false);
107
110
  expect(result.place).toBe('end');
108
- expect(mockClaude.call).toHaveBeenCalledTimes(2);
111
+ expect(mockLlm.call).toHaveBeenCalledTimes(2);
109
112
 
110
- const toolResultDocs = result.documents.filter((d) =>
111
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
113
+ const toolResultDocs = result.documents.filter(
114
+ (d) =>
115
+ Array.isArray(d.content?.content) &&
116
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
112
117
  );
113
118
  expect(toolResultDocs.length).toBeGreaterThan(0);
114
119
  });
@@ -116,8 +121,7 @@ describe('DelegateErrorWorkflow', () => {
116
121
 
117
122
  describe('successful tool call', () => {
118
123
  it('should process successful tool call without errors', async () => {
119
- // LLM calls strictSchema with valid args
120
- mockClaude.call
124
+ mockLlm.call
121
125
  .mockResolvedValueOnce(mockToolUseResponse('strictSchema', { name: 'World' }))
122
126
  .mockResolvedValueOnce(mockEndTurnResponse('Done.'));
123
127
 
@@ -126,19 +130,20 @@ describe('DelegateErrorWorkflow', () => {
126
130
 
127
131
  expect(result.hasError).toBe(false);
128
132
  expect(result.place).toBe('end');
129
- expect(mockClaude.call).toHaveBeenCalledTimes(2);
133
+ expect(mockLlm.call).toHaveBeenCalledTimes(2);
130
134
 
131
- // No error tool results
132
- const errorToolResults = result.documents.filter((d) =>
133
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
135
+ const errorToolResults = result.documents.filter(
136
+ (d) =>
137
+ Array.isArray(d.content?.content) &&
138
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
134
139
  );
135
140
  expect(errorToolResults).toHaveLength(0);
136
141
  });
137
142
  });
138
143
 
139
144
  describe('error metadata in tool result documents', () => {
140
- it('should include validation error message in is_error tool result', async () => {
141
- mockClaude.call
145
+ it('should include validation error message in isError tool result', async () => {
146
+ mockLlm.call
142
147
  .mockResolvedValueOnce(mockToolUseResponse('strictSchema', {}))
143
148
  .mockResolvedValueOnce(mockEndTurnResponse('Done.'));
144
149
 
@@ -147,19 +152,22 @@ describe('DelegateErrorWorkflow', () => {
147
152
 
148
153
  expect(result.hasError).toBe(false);
149
154
 
150
- const toolResultDocs = result.documents.filter((d) =>
151
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
155
+ const toolResultDocs = result.documents.filter(
156
+ (d) =>
157
+ Array.isArray(d.content?.content) &&
158
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
152
159
  );
153
160
  expect(toolResultDocs.length).toBeGreaterThan(0);
154
161
 
155
- const errorResult = toolResultDocs[0].content.toolResults.find((tr: { is_error?: boolean }) => tr.is_error);
162
+ const errorResult = toolResultDocs[0].content.content.find(
163
+ (b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError,
164
+ );
156
165
  expect(errorResult.content).toBeDefined();
157
- // Zod v4 error message for missing required string field
158
166
  expect(errorResult.content).toContain('invalid_type');
159
167
  });
160
168
 
161
- it('should include runtime error message in is_error tool result', async () => {
162
- mockClaude.call
169
+ it('should include runtime error message in isError tool result', async () => {
170
+ mockLlm.call
163
171
  .mockResolvedValueOnce(mockToolUseResponse('runtimeError', { shouldFail: true }))
164
172
  .mockResolvedValueOnce(mockEndTurnResponse('Done.'));
165
173
 
@@ -168,49 +176,60 @@ describe('DelegateErrorWorkflow', () => {
168
176
 
169
177
  expect(result.hasError).toBe(false);
170
178
 
171
- const toolResultDocs = result.documents.filter((d) =>
172
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
179
+ const toolResultDocs = result.documents.filter(
180
+ (d) =>
181
+ Array.isArray(d.content?.content) &&
182
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
173
183
  );
174
184
  expect(toolResultDocs.length).toBeGreaterThan(0);
175
185
 
176
- const errorResult = toolResultDocs[0].content.toolResults.find((tr: { is_error?: boolean }) => tr.is_error);
186
+ const errorResult = toolResultDocs[0].content.content.find(
187
+ (b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError,
188
+ );
177
189
  expect(errorResult.content).toContain('external service unavailable');
178
190
  });
179
191
  });
180
192
 
181
193
  describe('validation and runtime errors produce identical structure', () => {
182
- it('should produce the same is_error tool result shape for both error types', async () => {
183
- // Run validation error
184
- mockClaude.call.mockResolvedValueOnce(mockToolUseResponse('strictSchema', {}));
194
+ it('should produce the same isError tool result shape for both error types', async () => {
195
+ mockLlm.call
196
+ .mockResolvedValueOnce(mockToolUseResponse('strictSchema', {}))
197
+ .mockResolvedValueOnce(mockEndTurnResponse('Recovered.'));
185
198
  const context1 = createStatelessContext();
186
199
  const result1 = await processor.process(workflow, {}, context1);
187
200
 
188
- const validationErrorDoc = result1.documents.find((d) =>
189
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
201
+ const validationErrorDoc = result1.documents.find(
202
+ (d) =>
203
+ Array.isArray(d.content?.content) &&
204
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
205
+ );
206
+ const validationError = validationErrorDoc?.content.content.find(
207
+ (b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError,
190
208
  );
191
- const validationError = validationErrorDoc?.content.toolResults.find((tr: { is_error?: boolean }) => tr.is_error);
192
209
 
193
- // Run runtime error (fresh module needed for clean state)
194
- mockClaude.call.mockResolvedValueOnce(mockToolUseResponse('runtimeError', { shouldFail: true }));
210
+ mockLlm.call
211
+ .mockResolvedValueOnce(mockToolUseResponse('runtimeError', { shouldFail: true }))
212
+ .mockResolvedValueOnce(mockEndTurnResponse('Recovered.'));
195
213
  const context2 = createStatelessContext();
196
214
  const result2 = await processor.process(workflow, {}, context2);
197
215
 
198
- const runtimeErrorDoc = result2.documents.find((d) =>
199
- d.content?.toolResults?.some((tr: { is_error?: boolean }) => tr.is_error),
216
+ const runtimeErrorDoc = result2.documents.find(
217
+ (d) =>
218
+ Array.isArray(d.content?.content) &&
219
+ d.content.content.some((b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError),
220
+ );
221
+ const runtimeError = runtimeErrorDoc?.content.content.find(
222
+ (b: { type?: string; isError?: boolean }) => b.type === 'tool_result' && b.isError,
200
223
  );
201
- const runtimeError = runtimeErrorDoc?.content.toolResults.find((tr: { is_error?: boolean }) => tr.is_error);
202
224
 
203
- // Both should have the same structure
204
225
  expect(validationError).toBeDefined();
205
226
  expect(runtimeError).toBeDefined();
206
- expect(validationError.type).toBe('tool_result');
207
- expect(runtimeError.type).toBe('tool_result');
208
- expect(validationError.is_error).toBe(true);
209
- expect(runtimeError.is_error).toBe(true);
227
+ expect(validationError.isError).toBe(true);
228
+ expect(runtimeError.isError).toBe(true);
210
229
  expect(typeof validationError.content).toBe('string');
211
230
  expect(typeof runtimeError.content).toBe('string');
212
- expect(typeof validationError.tool_use_id).toBe('string');
213
- expect(typeof runtimeError.tool_use_id).toBe('string');
231
+ expect(typeof validationError.toolCallId).toBe('string');
232
+ expect(typeof runtimeError.toolCallId).toBe('string');
214
233
  });
215
234
  });
216
235
  });
@@ -1,6 +1,5 @@
1
1
  import { Module } from '@nestjs/common';
2
2
  import { ClaudeModule } from '@loopstack/claude-module';
3
- import { LoopCoreModule } from '@loopstack/core';
4
3
  import { DelegateErrorWorkflow } from './delegate-error.workflow';
5
4
  import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
6
5
  import { RuntimeErrorTool } from './tools/runtime-error.tool';
@@ -8,7 +7,7 @@ import { StrictSchemaTool } from './tools/strict-schema.tool';
8
7
  import { FailingWorkflow } from './workflows/failing.workflow';
9
8
 
10
9
  @Module({
11
- imports: [LoopCoreModule, ClaudeModule],
10
+ imports: [ClaudeModule],
12
11
  providers: [StrictSchemaTool, RuntimeErrorTool, FailingSubWorkflowTool, FailingWorkflow, DelegateErrorWorkflow],
13
12
  exports: [DelegateErrorWorkflow],
14
13
  })
@@ -1,11 +1,3 @@
1
- import {
2
- ClaudeGenerateText,
3
- ClaudeGenerateTextResult,
4
- ClaudeMessageDocument,
5
- DelegateToolCalls,
6
- DelegateToolCallsResult,
7
- UpdateToolResult,
8
- } from '@loopstack/claude-module';
9
1
  import {
10
2
  BaseWorkflow,
11
3
  Final,
@@ -17,6 +9,13 @@ import {
17
9
  Transition,
18
10
  Workflow,
19
11
  } from '@loopstack/common';
12
+ import type { LlmDelegateResult, LlmGenerateTextResult, LlmResultMeta } from '@loopstack/llm-provider-module';
13
+ import {
14
+ LlmDelegateToolCallsTool,
15
+ LlmGenerateTextTool,
16
+ LlmMessageDocument,
17
+ LlmUpdateToolResultTool,
18
+ } from '@loopstack/llm-provider-module';
20
19
  import { FailingSubWorkflowTool } from './tools/failing-sub-workflow.tool';
21
20
  import { RuntimeErrorTool } from './tools/runtime-error.tool';
22
21
  import { StrictSchemaTool } from './tools/strict-schema.tool';
@@ -33,15 +32,21 @@ import { StrictSchemaTool } from './tools/strict-schema.tool';
33
32
  uiConfig: __dirname + '/delegate-error.ui.yaml',
34
33
  })
35
34
  export class DelegateErrorWorkflow extends BaseWorkflow {
36
- @InjectTool() claudeGenerateText: ClaudeGenerateText;
37
- @InjectTool() delegateToolCalls: DelegateToolCalls;
38
- @InjectTool() updateToolResult: UpdateToolResult;
35
+ @InjectTool({
36
+ provider: 'claude',
37
+ model: 'claude-sonnet-4-6',
38
+ tools: ['strictSchema', 'runtimeError', 'failingSubWorkflow'],
39
+ })
40
+ llmGenerateText: LlmGenerateTextTool;
41
+ @InjectTool({ provider: 'claude' }) llmDelegateToolCalls: LlmDelegateToolCallsTool;
42
+ @InjectTool({ provider: 'claude' }) llmUpdateToolResult: LlmUpdateToolResultTool;
39
43
  @InjectTool() strictSchema: StrictSchemaTool;
40
44
  @InjectTool() runtimeError: RuntimeErrorTool;
41
45
  @InjectTool() failingSubWorkflow: FailingSubWorkflowTool;
42
46
 
43
- llmResult?: ClaudeGenerateTextResult;
44
- delegateResult?: DelegateToolCallsResult;
47
+ llmResult?: LlmGenerateTextResult;
48
+ llmMeta?: LlmResultMeta;
49
+ delegateResult?: LlmDelegateResult;
45
50
  turnCount!: number;
46
51
 
47
52
  @Initial({ to: 'ready' })
@@ -56,7 +61,7 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
56
61
  'The LLM will deliberately trigger errors, then self-correct.',
57
62
  });
58
63
 
59
- await this.repository.save(ClaudeMessageDocument, {
64
+ await this.repository.save(LlmMessageDocument, {
60
65
  role: 'user',
61
66
  content:
62
67
  'Follow the instructions in your system prompt exactly. ' +
@@ -67,32 +72,27 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
67
72
  @Transition({ from: 'ready', to: 'prompt_executed' })
68
73
  async llmTurn() {
69
74
  this.turnCount++;
70
- const result: ToolResult<ClaudeGenerateTextResult> = await this.claudeGenerateText.call({
71
- system:
72
- 'You are a test assistant that follows instructions precisely. ' +
73
- 'You are fully autonomous — do NOT ask the user for input or confirmation. ' +
74
- 'Just proceed through each step on your own.\n\n' +
75
- 'Complete these steps IN ORDER. Do exactly one step per turn:\n\n' +
76
- '1. Call the `strictSchema` tool with NO arguments (empty object {}). This will fail — that is expected.\n' +
77
- '2. After seeing the validation error, call `strictSchema` correctly with { "name": "World" }.\n' +
78
- '3. Call the `runtimeError` tool with { "shouldFail": true }. This will fail — that is expected.\n' +
79
- '4. After seeing the runtime error, call `runtimeError` with { "shouldFail": false }.\n' +
80
- '5. Call the `failingSubWorkflow` tool with {}. This launches a sub-workflow that will fail — that is expected.\n' +
81
- '6. After seeing the sub-workflow error, respond with a brief summary of what happened (do NOT call any tools).\n\n' +
82
- 'IMPORTANT: Only perform ONE step per turn. Do NOT skip steps. Do NOT wait for user input between steps.',
83
- claude: { model: 'claude-sonnet-4-6' },
84
- messagesSearchTag: 'message',
85
- tools: ['strictSchema', 'runtimeError', 'failingSubWorkflow'],
86
- });
75
+ const result: ToolResult<LlmGenerateTextResult, LlmResultMeta> = await this.llmGenerateText.call(
76
+ {},
77
+ {
78
+ config: {
79
+ system: this.render(__dirname + '/templates/system.md'),
80
+ },
81
+ },
82
+ );
87
83
  this.llmResult = result.data;
84
+ this.llmMeta = result.metadata;
88
85
  }
89
86
 
90
87
  @Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
91
88
  @Guard('hasToolCalls')
92
89
  async executeToolCalls() {
93
- const result: ToolResult<DelegateToolCallsResult> = await this.delegateToolCalls.call({
94
- message: this.llmResult!,
95
- document: ClaudeMessageDocument,
90
+ await this.repository.save(LlmMessageDocument, this.llmResult!.message, {
91
+ meta: { response: this.llmResult!.response, provider: this.llmMeta!.provider },
92
+ });
93
+
94
+ const result: ToolResult<LlmDelegateResult> = await this.llmDelegateToolCalls.call({
95
+ message: this.llmResult!.message,
96
96
  callback: { transition: 'toolResultReceived' },
97
97
  });
98
98
  this.delegateResult = result.data;
@@ -100,17 +100,26 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
100
100
 
101
101
  @Transition({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true })
102
102
  async toolResultReceived(payload: unknown) {
103
- const result = await this.updateToolResult.call({
103
+ const result = await this.llmUpdateToolResult.call({
104
104
  delegateResult: this.delegateResult!,
105
105
  completedTool: payload,
106
- document: ClaudeMessageDocument,
107
106
  });
108
- this.delegateResult = result.data as DelegateToolCallsResult;
107
+ this.delegateResult = result.data as LlmDelegateResult;
109
108
  }
110
109
 
111
110
  @Transition({ from: 'awaiting_tools', to: 'ready' })
112
111
  @Guard('allToolsComplete')
113
- async toolsComplete() {}
112
+ async toolsComplete() {
113
+ await this.repository.save(LlmMessageDocument, {
114
+ role: 'user',
115
+ content: this.delegateResult!.toolResults.map((tr) => ({
116
+ type: 'tool_result' as const,
117
+ toolCallId: tr.toolCallId,
118
+ content: tr.content ?? '',
119
+ isError: tr.isError ?? false,
120
+ })),
121
+ });
122
+ }
114
123
 
115
124
  @Transition({ from: 'awaiting_tools', to: 'ready', wait: true })
116
125
  async cancelPendingTools() {
@@ -123,11 +132,13 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
123
132
  @Final({ from: 'prompt_executed' })
124
133
  @Guard('isEndTurn')
125
134
  async respond() {
126
- await this.repository.save(ClaudeMessageDocument, this.llmResult!, { id: this.llmResult!.id });
135
+ await this.repository.save(LlmMessageDocument, this.llmResult!.message, {
136
+ meta: { response: this.llmResult!.response, provider: this.llmMeta!.provider },
137
+ });
127
138
  }
128
139
 
129
140
  private hasToolCalls(): boolean {
130
- return this.llmResult?.stop_reason === 'tool_use';
141
+ return this.llmResult?.message.stopReason === 'tool_use';
131
142
  }
132
143
 
133
144
  private allToolsComplete(): boolean {
@@ -135,6 +146,6 @@ export class DelegateErrorWorkflow extends BaseWorkflow {
135
146
  }
136
147
 
137
148
  private isEndTurn(): boolean {
138
- return this.llmResult?.stop_reason === 'end_turn';
149
+ return this.llmResult?.message.stopReason === 'end_turn';
139
150
  }
140
151
  }
@@ -0,0 +1,12 @@
1
+ You are a test assistant that follows instructions precisely. You are fully autonomous — do NOT ask the user for input or confirmation. Just proceed through each step on your own.
2
+
3
+ Complete these steps IN ORDER. Do exactly one step per turn:
4
+
5
+ 1. Call the `strictSchema` tool with NO arguments (empty object {}). This will fail — that is expected.
6
+ 2. After seeing the validation error, call `strictSchema` correctly with { "name": "World" }.
7
+ 3. Call the `runtimeError` tool with { "shouldFail": true }. This will fail — that is expected.
8
+ 4. After seeing the runtime error, call `runtimeError` with { "shouldFail": false }.
9
+ 5. Call the `failingSubWorkflow` tool with {}. This launches a sub-workflow that will fail — that is expected.
10
+ 6. After seeing the sub-workflow error, respond with a brief summary of what happened (do NOT call any tools).
11
+
12
+ IMPORTANT: Only perform ONE step per turn. Do NOT skip steps. Do NOT wait for user input between steps.