@loopstack/claude-module 0.21.0 → 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.
Files changed (60) hide show
  1. package/dist/claude.module.d.ts.map +1 -1
  2. package/dist/claude.module.js +5 -12
  3. package/dist/claude.module.js.map +1 -1
  4. package/dist/documents/claude-message-document.d.ts +3 -1
  5. package/dist/documents/claude-message-document.d.ts.map +1 -1
  6. package/dist/documents/claude-message-document.js +6 -18
  7. package/dist/documents/claude-message-document.js.map +1 -1
  8. package/dist/documents/claude-message-document.yaml +2 -2
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/claude-tools-helper.service.d.ts.map +1 -1
  14. package/dist/services/claude-tools-helper.service.js +6 -8
  15. package/dist/services/claude-tools-helper.service.js.map +1 -1
  16. package/dist/tools/claude-generate-document.tool.d.ts +3 -6
  17. package/dist/tools/claude-generate-document.tool.d.ts.map +1 -1
  18. package/dist/tools/claude-generate-document.tool.js +9 -31
  19. package/dist/tools/claude-generate-document.tool.js.map +1 -1
  20. package/dist/tools/claude-generate-object.tool.d.ts +4 -5
  21. package/dist/tools/claude-generate-object.tool.d.ts.map +1 -1
  22. package/dist/tools/claude-generate-object.tool.js +7 -17
  23. package/dist/tools/claude-generate-object.tool.js.map +1 -1
  24. package/dist/tools/claude-generate-text.tool.d.ts +5 -4
  25. package/dist/tools/claude-generate-text.tool.d.ts.map +1 -1
  26. package/dist/tools/claude-generate-text.tool.js +27 -13
  27. package/dist/tools/claude-generate-text.tool.js.map +1 -1
  28. package/dist/tools/delegate-tool-calls.tool.d.ts +23 -0
  29. package/dist/tools/delegate-tool-calls.tool.d.ts.map +1 -0
  30. package/dist/tools/delegate-tool-calls.tool.js +117 -0
  31. package/dist/tools/delegate-tool-calls.tool.js.map +1 -0
  32. package/dist/tools/index.d.ts +2 -1
  33. package/dist/tools/index.d.ts.map +1 -1
  34. package/dist/tools/index.js +2 -1
  35. package/dist/tools/index.js.map +1 -1
  36. package/dist/tools/update-tool-result.tool.d.ts +19 -0
  37. package/dist/tools/update-tool-result.tool.d.ts.map +1 -0
  38. package/dist/tools/update-tool-result.tool.js +89 -0
  39. package/dist/tools/update-tool-result.tool.js.map +1 -0
  40. package/dist/types/claude.types.d.ts +19 -0
  41. package/dist/types/claude.types.d.ts.map +1 -1
  42. package/dist/types/claude.types.js.map +1 -1
  43. package/package.json +3 -3
  44. package/src/claude.module.ts +12 -15
  45. package/src/documents/claude-message-document.ts +6 -12
  46. package/src/documents/claude-message-document.yaml +2 -2
  47. package/src/index.ts +1 -0
  48. package/src/services/claude-tools-helper.service.ts +6 -8
  49. package/src/tools/claude-generate-document.tool.ts +11 -48
  50. package/src/tools/claude-generate-object.tool.ts +13 -29
  51. package/src/tools/claude-generate-text.tool.ts +33 -25
  52. package/src/tools/delegate-tool-calls.tool.ts +139 -0
  53. package/src/tools/index.ts +2 -1
  54. package/src/tools/update-tool-result.tool.ts +99 -0
  55. package/src/types/claude.types.ts +26 -0
  56. package/dist/tools/claude-delegate-tool-call.tool.d.ts +0 -19
  57. package/dist/tools/claude-delegate-tool-call.tool.d.ts.map +0 -1
  58. package/dist/tools/claude-delegate-tool-call.tool.js +0 -102
  59. package/dist/tools/claude-delegate-tool-call.tool.js.map +0 -1
  60. package/src/tools/claude-delegate-tool-call.tool.ts +0 -125
@@ -1,19 +1,12 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
2
  import { Inject } from '@nestjs/common';
3
3
  import { z } from 'zod';
4
- import {
5
- Input,
6
- RunContext,
7
- Tool,
8
- ToolInterface,
9
- ToolResult,
10
- WorkflowInterface,
11
- WorkflowMetadataInterface,
12
- } from '@loopstack/common';
4
+ import { BaseTool, Tool, ToolCallEntry, ToolCallsMap, ToolResult } from '@loopstack/common';
13
5
  import { ClaudeGenerateToolBaseSchema } from '../schemas/claude-generate-tool-base.schema';
14
6
  import { ClaudeClientService } from '../services';
15
7
  import { ClaudeMessagesHelperService } from '../services';
16
8
  import { ClaudeToolsHelperService } from '../services';
9
+ import { ClaudeGenerateTextResult } from '../types';
17
10
  import { applyCacheBreakpoints } from '../utils/cache.utils';
18
11
 
19
12
  export const ClaudeGenerateTextSchema = ClaudeGenerateToolBaseSchema.extend({
@@ -23,11 +16,12 @@ export const ClaudeGenerateTextSchema = ClaudeGenerateToolBaseSchema.extend({
23
16
  type ClaudeGenerateTextArgsType = z.infer<typeof ClaudeGenerateTextSchema>;
24
17
 
25
18
  @Tool({
26
- config: {
19
+ uiConfig: {
27
20
  description: 'Generates text using the Anthropic Claude API',
28
21
  },
22
+ schema: ClaudeGenerateTextSchema,
29
23
  })
30
- export class ClaudeGenerateText implements ToolInterface<ClaudeGenerateTextArgsType> {
24
+ export class ClaudeGenerateText extends BaseTool {
31
25
  @Inject()
32
26
  private readonly claudeClientService: ClaudeClientService;
33
27
  @Inject()
@@ -35,17 +29,7 @@ export class ClaudeGenerateText implements ToolInterface<ClaudeGenerateTextArgsT
35
29
  @Inject()
36
30
  private readonly claudeToolsHelperService: ClaudeToolsHelperService;
37
31
 
38
- @Input({
39
- schema: ClaudeGenerateTextSchema,
40
- })
41
- args: ClaudeGenerateTextArgsType;
42
-
43
- async execute(
44
- args: ClaudeGenerateTextArgsType,
45
- ctx: RunContext,
46
- parent: WorkflowInterface,
47
- runtime: WorkflowMetadataInterface,
48
- ): Promise<ToolResult> {
32
+ async call(args: ClaudeGenerateTextArgsType): Promise<ToolResult<ClaudeGenerateTextResult>> {
49
33
  const client = this.claudeClientService.getClient(args.claude);
50
34
  const model = this.claudeClientService.getModel(args.claude);
51
35
 
@@ -54,14 +38,14 @@ export class ClaudeGenerateText implements ToolInterface<ClaudeGenerateTextArgsT
54
38
  if (args.prompt) {
55
39
  messages.push({ role: 'user', content: args.prompt });
56
40
  } else {
57
- const resolved = this.claudeMessagesHelperService.getMessages(runtime.documents, {
41
+ const resolved = this.claudeMessagesHelperService.getMessages(this.ctx.runtime.documents, {
58
42
  messages: args.messages as Anthropic.MessageParam[],
59
43
  messagesSearchTag: args.messagesSearchTag,
60
44
  });
61
45
  messages.push(...resolved);
62
46
  }
63
47
 
64
- const tools = args.tools ? this.claudeToolsHelperService.getTools(args.tools, parent) : undefined;
48
+ const tools = args.tools ? this.claudeToolsHelperService.getTools(args.tools, this.ctx.parent) : undefined;
65
49
 
66
50
  const response = await this.handleGenerateText(client, {
67
51
  model,
@@ -72,8 +56,13 @@ export class ClaudeGenerateText implements ToolInterface<ClaudeGenerateTextArgsT
72
56
  cache: args.claude?.cache,
73
57
  });
74
58
 
59
+ const toolCalls = this.extractToolCalls(response);
60
+
75
61
  return {
76
- data: response,
62
+ data: {
63
+ ...response,
64
+ ...(toolCalls ? { toolCalls } : {}),
65
+ },
77
66
  metadata: {
78
67
  usage: {
79
68
  inputTokens: response.usage.input_tokens,
@@ -85,6 +74,25 @@ export class ClaudeGenerateText implements ToolInterface<ClaudeGenerateTextArgsT
85
74
  };
86
75
  }
87
76
 
77
+ private extractToolCalls(response: Anthropic.Message): ToolCallsMap | null {
78
+ if (response.stop_reason !== 'tool_use') {
79
+ return null;
80
+ }
81
+
82
+ const toolCalls: ToolCallsMap = {};
83
+ for (const block of response.content) {
84
+ if (block.type === 'tool_use') {
85
+ toolCalls[block.name] = {
86
+ id: block.id,
87
+ name: block.name,
88
+ input: block.input,
89
+ } satisfies ToolCallEntry;
90
+ }
91
+ }
92
+
93
+ return Object.keys(toolCalls).length > 0 ? toolCalls : null;
94
+ }
95
+
88
96
  private async handleGenerateText(
89
97
  client: Anthropic,
90
98
  options: {
@@ -0,0 +1,139 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ import { Injectable, Logger } from '@nestjs/common';
3
+ import { z } from 'zod';
4
+ import {
5
+ BaseTool,
6
+ DocumentClass,
7
+ Tool,
8
+ ToolCallOptions,
9
+ ToolResult,
10
+ getBlockTool,
11
+ getBlockTypeFromMetadata,
12
+ } from '@loopstack/common';
13
+ import type { DelegateToolCallsResult, DelegateToolResultEntry } from '../types';
14
+
15
+ const DelegateToolCallsSchema = z.object({
16
+ message: z.object({
17
+ id: z.string().optional(),
18
+ content: z.array(z.any()),
19
+ }),
20
+ document: z
21
+ .custom<DocumentClass>((val) => typeof val === 'function' && getBlockTypeFromMetadata(val as object) === 'document')
22
+ .optional(),
23
+ skipResponseMessage: z.boolean().optional(),
24
+ callback: z
25
+ .object({
26
+ transition: z.string(),
27
+ })
28
+ .optional(),
29
+ });
30
+
31
+ type DelegateToolCallsArgs = z.infer<typeof DelegateToolCallsSchema>;
32
+
33
+ @Injectable()
34
+ @Tool({
35
+ uiConfig: {
36
+ description: 'Delegate tool calls from an LLM response. Handles both sync tools and async task tools.',
37
+ },
38
+ schema: DelegateToolCallsSchema,
39
+ })
40
+ export class DelegateToolCalls extends BaseTool {
41
+ private readonly logger = new Logger(DelegateToolCalls.name);
42
+
43
+ async call(args: DelegateToolCallsArgs): Promise<ToolResult<DelegateToolCallsResult>> {
44
+ const contentBlocks = args.message.content as Anthropic.ContentBlock[];
45
+ const toolUseBlocks = contentBlocks.filter((b): b is Anthropic.ToolUseBlock => b.type === 'tool_use');
46
+
47
+ if (toolUseBlocks.length === 0) {
48
+ return {
49
+ data: {
50
+ allCompleted: true,
51
+ toolResults: [],
52
+ message: args.message as DelegateToolCallsResult['message'],
53
+ pendingCount: 0,
54
+ },
55
+ };
56
+ }
57
+
58
+ // 1. Execute ALL tools in parallel, passing callback via options (not args)
59
+ const results = await Promise.all(
60
+ toolUseBlocks.map((block) => {
61
+ const toolCallback = args.callback
62
+ ? {
63
+ transition: args.callback.transition,
64
+ metadata: { toolUseId: block.id, toolName: block.name },
65
+ }
66
+ : undefined;
67
+ return this.executeTool(block, toolCallback ? { callback: toolCallback } : undefined);
68
+ }),
69
+ );
70
+
71
+ // 2. Build toolResults array — async tools signal via result.pending
72
+ let pendingCount = 0;
73
+ const toolResults: DelegateToolResultEntry[] = [];
74
+
75
+ for (let i = 0; i < toolUseBlocks.length; i++) {
76
+ const block = toolUseBlocks[i];
77
+ const result = results[i];
78
+
79
+ if (result.pending) {
80
+ pendingCount++;
81
+ } else {
82
+ toolResults.push({
83
+ type: 'tool_result',
84
+ tool_use_id: block.id,
85
+ content: result.data ? JSON.stringify(result.data, null, 2) : '',
86
+ is_error: !!result.error,
87
+ });
88
+ }
89
+ }
90
+
91
+ // 3. Create response document (tool call message)
92
+ if (args.document && !args.skipResponseMessage) {
93
+ await this.createResponseDocument(args.document, args, toolResults);
94
+ }
95
+
96
+ return {
97
+ data: {
98
+ allCompleted: pendingCount === 0,
99
+ toolResults,
100
+ message: args.message as DelegateToolCallsResult['message'],
101
+ pendingCount,
102
+ },
103
+ };
104
+ }
105
+
106
+ private async executeTool(block: Anthropic.ToolUseBlock, options?: ToolCallOptions): Promise<ToolResult> {
107
+ try {
108
+ const tool = getBlockTool<BaseTool>(this.ctx.parent, block.name);
109
+ if (!tool) {
110
+ throw new Error(`Tool with name ${block.name} not found.`);
111
+ }
112
+
113
+ return await tool.call(block.input as Record<string, unknown>, options);
114
+ } catch (error) {
115
+ const errorMessage = error instanceof Error ? error.message : String(error);
116
+ this.logger.error(`Tool "${block.name}" failed: ${errorMessage}`);
117
+ return {
118
+ data: errorMessage,
119
+ error: errorMessage,
120
+ };
121
+ }
122
+ }
123
+
124
+ private async createResponseDocument(
125
+ document: DocumentClass,
126
+ args: DelegateToolCallsArgs,
127
+ toolResults: DelegateToolResultEntry[],
128
+ ): Promise<void> {
129
+ await this.repository.save(
130
+ document,
131
+ {
132
+ role: 'assistant',
133
+ content: args.message.content,
134
+ toolResults,
135
+ },
136
+ { id: args.message.id, validate: 'skip' },
137
+ );
138
+ }
139
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './claude-generate-text.tool';
2
2
  export * from './claude-generate-object.tool';
3
3
  export * from './claude-generate-document.tool';
4
- export * from './claude-delegate-tool-call.tool';
4
+ export * from './delegate-tool-calls.tool';
5
+ export * from './update-tool-result.tool';
@@ -0,0 +1,99 @@
1
+ import { Injectable, Logger } from '@nestjs/common';
2
+ import { z } from 'zod';
3
+ import { BaseTool, DocumentClass, Tool, ToolResult, getBlockTool, getBlockTypeFromMetadata } from '@loopstack/common';
4
+
5
+ const UpdateToolResultSchema = z.object({
6
+ delegateResult: z.object({
7
+ allCompleted: z.boolean(),
8
+ toolResults: z.array(z.any()),
9
+ message: z.any(),
10
+ pendingCount: z.number(),
11
+ }),
12
+ completedTool: z.any(),
13
+ document: z
14
+ .custom<DocumentClass>((val) => typeof val === 'function' && getBlockTypeFromMetadata(val as object) === 'document')
15
+ .optional(),
16
+ });
17
+
18
+ type UpdateToolResultArgs = z.infer<typeof UpdateToolResultSchema>;
19
+
20
+ @Injectable()
21
+ @Tool({
22
+ uiConfig: {
23
+ description: 'Handle async tool completion callback. Updates the response document and tracks completion state.',
24
+ },
25
+ schema: UpdateToolResultSchema,
26
+ })
27
+ export class UpdateToolResult extends BaseTool {
28
+ private readonly logger = new Logger(UpdateToolResult.name);
29
+
30
+ async call(args: UpdateToolResultArgs): Promise<ToolResult> {
31
+ const { delegateResult } = args;
32
+ const completedToolRecord = args.completedTool as Record<string, unknown>;
33
+
34
+ // 1. Extract tool identity from subscriber metadata
35
+ const subscriberMetadata = completedToolRecord._subscriberMetadata as
36
+ | { toolUseId: string; toolName: string }
37
+ | undefined;
38
+ if (!subscriberMetadata?.toolUseId || !subscriberMetadata?.toolName) {
39
+ throw new Error(
40
+ 'Callback payload is missing _subscriberMetadata with toolUseId and toolName. ' +
41
+ 'Ensure the event subscriber was registered with metadata by delegateToolCalls.',
42
+ );
43
+ }
44
+
45
+ const { toolUseId, toolName } = subscriberMetadata;
46
+
47
+ // 2. Resolve tool and call complete()
48
+ const tool = getBlockTool<BaseTool>(this.ctx.parent, toolName);
49
+ if (!tool) {
50
+ throw new Error(`Tool with name ${toolName} not found.`);
51
+ }
52
+ let toolResult: ToolResult;
53
+ try {
54
+ toolResult = await tool.complete(completedToolRecord);
55
+ } catch (error) {
56
+ const errorMessage = error instanceof Error ? error.message : String(error);
57
+ this.logger.error(`Tool "${toolName}" complete() failed: ${errorMessage}`);
58
+ toolResult = {
59
+ data: errorMessage,
60
+ error: errorMessage,
61
+ };
62
+ }
63
+
64
+ // 3. Merge into toolResults (append completed result)
65
+ const completedEntry = {
66
+ type: 'tool_result' as const,
67
+ tool_use_id: toolUseId,
68
+ content: toolResult.data ? JSON.stringify(toolResult.data, null, 2) : '',
69
+ is_error: !!toolResult.error,
70
+ };
71
+ const updatedResults = [...(delegateResult.toolResults as Record<string, unknown>[]), completedEntry];
72
+
73
+ // 4. Update completion state
74
+ const pendingCount = delegateResult.pendingCount - 1;
75
+ const allCompleted = pendingCount === 0;
76
+
77
+ // 5. Update response document (invalidates previous)
78
+ if (args.document) {
79
+ await this.repository.save(
80
+ args.document,
81
+ {
82
+ role: 'assistant',
83
+ content: (delegateResult.message as Record<string, unknown>).content,
84
+ toolResults: updatedResults,
85
+ },
86
+ { id: (delegateResult.message as Record<string, unknown>).id as string, validate: 'skip' },
87
+ );
88
+ }
89
+
90
+ return {
91
+ data: {
92
+ ...delegateResult,
93
+ toolResults: updatedResults,
94
+ allCompleted,
95
+ pendingCount,
96
+ },
97
+ };
98
+ }
99
+ }
@@ -1,4 +1,5 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
+ import type { ToolCallsMap } from '@loopstack/common';
2
3
 
3
4
  /**
4
5
  * Configuration for creating a Claude client and selecting a model.
@@ -30,5 +31,30 @@ export interface ClaudeToolDefinition {
30
31
  input_schema: Anthropic.Tool['input_schema'];
31
32
  }
32
33
 
34
+ /**
35
+ * Result data from ClaudeGenerateText tool.
36
+ * Extends the Anthropic Message with optional tool call metadata.
37
+ */
38
+ export interface ClaudeGenerateTextResult extends Anthropic.Message {
39
+ toolCalls?: ToolCallsMap;
40
+ }
41
+
42
+ /**
43
+ * Result data from DelegateToolCalls tool.
44
+ */
45
+ export interface DelegateToolCallsResult {
46
+ allCompleted: boolean;
47
+ toolResults: DelegateToolResultEntry[];
48
+ message: { id?: string; content: Anthropic.ContentBlock[] };
49
+ pendingCount: number;
50
+ }
51
+
52
+ export interface DelegateToolResultEntry {
53
+ type: 'tool_result';
54
+ tool_use_id: string;
55
+ content?: string;
56
+ is_error?: boolean;
57
+ }
58
+
33
59
  // Re-export Anthropic namespace for consumer convenience
34
60
  export { default as Anthropic } from '@anthropic-ai/sdk';
@@ -1,19 +0,0 @@
1
- import { z } from 'zod';
2
- import { RunContext, ToolInterface, ToolResult, WorkflowInterface, WorkflowMetadataInterface } from '@loopstack/common';
3
- declare const ClaudeDelegateToolCallSchema: z.ZodObject<{
4
- message: z.ZodObject<{
5
- id: z.ZodOptional<z.ZodString>;
6
- content: z.ZodArray<z.ZodAny>;
7
- }, z.core.$strip>;
8
- document: z.ZodOptional<z.ZodString>;
9
- skipResponseMessage: z.ZodOptional<z.ZodBoolean>;
10
- }, z.core.$strip>;
11
- type ClaudeDelegateToolCallArgs = z.infer<typeof ClaudeDelegateToolCallSchema>;
12
- export declare class ClaudeDelegateToolCall implements ToolInterface<ClaudeDelegateToolCallArgs> {
13
- private readonly logger;
14
- args: ClaudeDelegateToolCallArgs;
15
- execute(args: ClaudeDelegateToolCallArgs, ctx: RunContext, parent: WorkflowInterface, runtime: WorkflowMetadataInterface): Promise<ToolResult>;
16
- private createResponseMessage;
17
- }
18
- export {};
19
- //# sourceMappingURL=claude-delegate-tool-call.tool.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude-delegate-tool-call.tool.d.ts","sourceRoot":"","sources":["../../src/tools/claude-delegate-tool-call.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAEL,UAAU,EAEV,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,yBAAyB,EAE1B,MAAM,mBAAmB,CAAC;AAE3B,QAAA,MAAM,4BAA4B;;;;;;;iBAOhC,CAAC;AAEH,KAAK,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAE/E,qBAKa,sBAAuB,YAAW,aAAa,CAAC,0BAA0B,CAAC;IACtF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAKlE,IAAI,EAAE,0BAA0B,CAAC;IAE3B,OAAO,CACX,IAAI,EAAE,0BAA0B,EAChC,GAAG,EAAE,UAAU,EACf,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,UAAU,CAAC;YAoDR,qBAAqB;CA6BpC"}
@@ -1,102 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- var ClaudeDelegateToolCall_1;
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.ClaudeDelegateToolCall = void 0;
14
- const common_1 = require("@nestjs/common");
15
- const zod_1 = require("zod");
16
- const common_2 = require("@loopstack/common");
17
- const ClaudeDelegateToolCallSchema = zod_1.z.object({
18
- message: zod_1.z.object({
19
- id: zod_1.z.string().optional(),
20
- content: zod_1.z.array(zod_1.z.any()),
21
- }),
22
- document: zod_1.z.string().optional(),
23
- skipResponseMessage: zod_1.z.boolean().optional(),
24
- });
25
- let ClaudeDelegateToolCall = ClaudeDelegateToolCall_1 = class ClaudeDelegateToolCall {
26
- logger = new common_1.Logger(ClaudeDelegateToolCall_1.name);
27
- args;
28
- async execute(args, ctx, parent, runtime) {
29
- const contentBlocks = args.message.content;
30
- const toolResults = [];
31
- for (const block of contentBlocks) {
32
- if (block.type !== 'tool_use') {
33
- continue;
34
- }
35
- const tool = (0, common_2.getBlockTool)(parent, block.name);
36
- if (!tool) {
37
- throw new Error(`Tool ${block.name} not found.`);
38
- }
39
- try {
40
- const result = await tool.execute(block.input, ctx, parent, runtime);
41
- toolResults.push({
42
- type: 'tool_result',
43
- tool_use_id: block.id,
44
- content: JSON.stringify(result.data, null, 2),
45
- });
46
- }
47
- catch (error) {
48
- const errorMessage = error instanceof Error ? error.message : String(error);
49
- this.logger.error(`Tool "${block.name}" failed: ${errorMessage}`);
50
- toolResults.push({
51
- type: 'tool_result',
52
- tool_use_id: block.id,
53
- content: errorMessage,
54
- is_error: true,
55
- });
56
- }
57
- }
58
- const resultData = { toolResults };
59
- if (args.document && !args.skipResponseMessage) {
60
- const docResult = await this.createResponseMessage(args, toolResults, ctx, parent, runtime);
61
- return {
62
- data: resultData,
63
- effects: docResult.effects,
64
- };
65
- }
66
- return {
67
- data: resultData,
68
- };
69
- }
70
- async createResponseMessage(args, toolResults, ctx, parent, runtime) {
71
- const createDocumentTool = (0, common_2.getBlockTool)(parent, 'createDocument');
72
- if (!createDocumentTool) {
73
- throw new Error('createDocument tool not found in parent context.');
74
- }
75
- return createDocumentTool.execute({
76
- id: args.message.id,
77
- document: args.document,
78
- update: {
79
- content: {
80
- role: 'assistant',
81
- content: args.message.content,
82
- toolResults,
83
- },
84
- },
85
- }, ctx, parent, runtime);
86
- }
87
- };
88
- exports.ClaudeDelegateToolCall = ClaudeDelegateToolCall;
89
- __decorate([
90
- (0, common_2.Input)({
91
- schema: ClaudeDelegateToolCallSchema,
92
- }),
93
- __metadata("design:type", Object)
94
- ], ClaudeDelegateToolCall.prototype, "args", void 0);
95
- exports.ClaudeDelegateToolCall = ClaudeDelegateToolCall = ClaudeDelegateToolCall_1 = __decorate([
96
- (0, common_2.Tool)({
97
- config: {
98
- description: 'Delegate tool calls from a Claude response.',
99
- },
100
- })
101
- ], ClaudeDelegateToolCall);
102
- //# sourceMappingURL=claude-delegate-tool-call.tool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude-delegate-tool-call.tool.js","sourceRoot":"","sources":["../../src/tools/claude-delegate-tool-call.tool.ts"],"names":[],"mappings":"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"}
@@ -1,125 +0,0 @@
1
- import Anthropic from '@anthropic-ai/sdk';
2
- import { Logger } from '@nestjs/common';
3
- import { z } from 'zod';
4
- import {
5
- Input,
6
- RunContext,
7
- Tool,
8
- ToolInterface,
9
- ToolResult,
10
- WorkflowInterface,
11
- WorkflowMetadataInterface,
12
- getBlockTool,
13
- } from '@loopstack/common';
14
-
15
- const ClaudeDelegateToolCallSchema = z.object({
16
- message: z.object({
17
- id: z.string().optional(),
18
- content: z.array(z.any()),
19
- }),
20
- document: z.string().optional(),
21
- skipResponseMessage: z.boolean().optional(),
22
- });
23
-
24
- type ClaudeDelegateToolCallArgs = z.infer<typeof ClaudeDelegateToolCallSchema>;
25
-
26
- @Tool({
27
- config: {
28
- description: 'Delegate tool calls from a Claude response.',
29
- },
30
- })
31
- export class ClaudeDelegateToolCall implements ToolInterface<ClaudeDelegateToolCallArgs> {
32
- private readonly logger = new Logger(ClaudeDelegateToolCall.name);
33
-
34
- @Input({
35
- schema: ClaudeDelegateToolCallSchema,
36
- })
37
- args: ClaudeDelegateToolCallArgs;
38
-
39
- async execute(
40
- args: ClaudeDelegateToolCallArgs,
41
- ctx: RunContext,
42
- parent: WorkflowInterface,
43
- runtime: WorkflowMetadataInterface,
44
- ): Promise<ToolResult> {
45
- const contentBlocks = args.message.content as Anthropic.ContentBlock[];
46
- const toolResults: Anthropic.ToolResultBlockParam[] = [];
47
-
48
- for (const block of contentBlocks) {
49
- if (block.type !== 'tool_use') {
50
- continue;
51
- }
52
-
53
- const tool = getBlockTool<ToolInterface>(parent, block.name);
54
-
55
- if (!tool) {
56
- throw new Error(`Tool ${block.name} not found.`);
57
- }
58
-
59
- try {
60
- const result: ToolResult = await tool.execute(block.input as Record<string, unknown>, ctx, parent, runtime);
61
-
62
- toolResults.push({
63
- type: 'tool_result',
64
- tool_use_id: block.id,
65
- content: JSON.stringify(result.data, null, 2),
66
- });
67
- } catch (error) {
68
- const errorMessage = error instanceof Error ? error.message : String(error);
69
- this.logger.error(`Tool "${block.name}" failed: ${errorMessage}`);
70
-
71
- toolResults.push({
72
- type: 'tool_result',
73
- tool_use_id: block.id,
74
- content: errorMessage,
75
- is_error: true,
76
- });
77
- }
78
- }
79
-
80
- const resultData = { toolResults };
81
-
82
- if (args.document && !args.skipResponseMessage) {
83
- const docResult = await this.createResponseMessage(args, toolResults, ctx, parent, runtime);
84
-
85
- return {
86
- data: resultData,
87
- effects: docResult.effects,
88
- };
89
- }
90
-
91
- return {
92
- data: resultData,
93
- };
94
- }
95
-
96
- private async createResponseMessage(
97
- args: ClaudeDelegateToolCallArgs,
98
- toolResults: Anthropic.ToolResultBlockParam[],
99
- ctx: RunContext,
100
- parent: WorkflowInterface,
101
- runtime: WorkflowMetadataInterface,
102
- ): Promise<ToolResult> {
103
- const createDocumentTool = getBlockTool<ToolInterface>(parent, 'createDocument');
104
- if (!createDocumentTool) {
105
- throw new Error('createDocument tool not found in parent context.');
106
- }
107
-
108
- return createDocumentTool.execute(
109
- {
110
- id: args.message.id,
111
- document: args.document,
112
- update: {
113
- content: {
114
- role: 'assistant',
115
- content: args.message.content,
116
- toolResults,
117
- },
118
- },
119
- },
120
- ctx,
121
- parent,
122
- runtime,
123
- );
124
- }
125
- }