Skip to content

Commit 563e28b

Browse files
committed
not really working well - aborting this path.
1 parent 40d0d68 commit 563e28b

File tree

3 files changed

+93
-119
lines changed

3 files changed

+93
-119
lines changed

src/tools/interaction/subAgentMessage.ts

Lines changed: 21 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Anthropic from "@anthropic-ai/sdk";
21
import { Tool } from "../../core/types.js";
32
import { z } from "zod";
43
import { zodToJsonSchema } from "zod-to-json-schema";
@@ -11,7 +10,9 @@ const parameterSchema = z.object({
1110
message: z
1211
.string()
1312
.optional()
14-
.describe("The message to send to the sub-agent (required unless aborting)"),
13+
.describe(
14+
"The message to send to the sub-agent (required unless aborting)"
15+
),
1516
description: z
1617
.string()
1718
.max(80)
@@ -24,97 +25,54 @@ const parameterSchema = z.object({
2425

2526
const returnSchema = z
2627
.object({
27-
response: z.string().describe("Response from the sub-agent or abort confirmation"),
28+
messages: z.array(z.string()).describe("Output from the sub-agent"),
2829
})
2930
.describe("Result containing the sub-agent's response or abort status");
3031

3132
type Parameters = z.infer<typeof parameterSchema>;
3233
type ReturnType = z.infer<typeof returnSchema>;
3334

34-
export const subAgentMessageTool: Tool<Parameters, ReturnType> = {
35+
export const subAgentStatusTool: Tool<Parameters, ReturnType> = {
3536
name: "subAgentMessage",
3637
description: "Sends a message to or aborts an existing sub-agent",
3738
parameters: zodToJsonSchema(parameterSchema),
3839
returns: zodToJsonSchema(returnSchema),
3940

40-
execute: async (
41-
params,
42-
{ logger },
43-
): Promise<ReturnType> => {
44-
if (!process.env.ANTHROPIC_API_KEY) {
45-
throw new Error("ANTHROPIC_API_KEY environment variable is not set");
46-
}
47-
41+
execute: async (params, { logger }): Promise<ReturnType> => {
4842
const state = subAgentStates.get(params.instanceId);
4943
if (!state) {
50-
throw new Error("Sub-agent not found");
44+
throw new Error(`Sub-agent not found with ID: ${params.instanceId}`);
5145
}
5246

5347
if (state.aborted) {
54-
throw new Error("Sub-agent has been aborted");
48+
throw new Error(`Sub-agent ${params.instanceId} has been aborted`);
5549
}
5650

5751
if (params.abort) {
5852
logger.verbose(`Aborting sub-agent ${params.instanceId}`);
53+
state.toolAgentState.inMessages.write({ abort: true });
5954
state.aborted = true;
60-
return {
61-
response: "Sub-agent aborted",
62-
};
6355
}
6456

65-
if (!params.message) {
66-
throw new Error("Message is required when not aborting");
67-
}
68-
69-
const anthropic = new Anthropic({
70-
apiKey: process.env.ANTHROPIC_API_KEY,
71-
});
72-
73-
// Create messages array with conversation history
74-
const messages = [
75-
{
76-
role: "user" as const,
77-
content: state.prompt,
78-
},
79-
...state.messages,
80-
{
81-
role: "user" as const,
82-
content: params.message,
83-
},
84-
];
57+
if (params.message) {
58+
// Send message
59+
logger.verbose(`Sending message to tool agent`);
60+
state.toolAgentState.inMessages.write(params.message);
8561

86-
// Get response
87-
logger.verbose(`Sending message to Anthropic API`);
88-
const response = await anthropic.messages.create({
89-
model: "claude-3-opus-20240229",
90-
max_tokens: 4096,
91-
messages,
92-
});
93-
94-
// Check if response content exists and has the expected structure
95-
if (!response.content?.[0]?.text) {
96-
throw new Error("Invalid response from Anthropic API");
62+
// Store the interaction
63+
state.messages.push({ role: "user", content: params.message });
9764
}
98-
99-
const responseText = response.content[0].text;
100-
logger.verbose(`Received response from sub-agent`);
101-
102-
// Store the interaction
103-
state.messages.push(
104-
{ role: "user", content: params.message },
105-
{ role: "assistant", content: responseText }
106-
);
107-
108-
return {
109-
response: responseText,
110-
};
11165
},
11266

11367
logParameters: (input, { logger }) => {
11468
if (input.abort) {
115-
logger.info(`Aborting sub-agent ${input.instanceId}: ${input.description}`);
69+
logger.info(
70+
`Aborting sub-agent ${input.instanceId}: ${input.description}`
71+
);
11672
} else {
117-
logger.info(`Sending message to sub-agent ${input.instanceId}: ${input.description}`);
73+
logger.info(
74+
`Sending message to sub-agent ${input.instanceId}: ${input.description}`
75+
);
11876
logger.verbose(`Message: ${input.message}`);
11977
}
12078
},

src/tools/interaction/subAgentStart.ts

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import Anthropic from "@anthropic-ai/sdk";
21
import { Tool } from "../../core/types.js";
32
import { z } from "zod";
43
import { zodToJsonSchema } from "zod-to-json-schema";
5-
import { subAgentStates } from "./subAgentState.js";
4+
import { subAgentStates, SubAgentState } from "./subAgentState.js";
65
import { v4 as uuidv4 } from "uuid";
6+
import { toolAgent } from "../../core/toolAgent.js";
7+
import { getTools } from "../getTools.js";
78

89
const parameterSchema = z.object({
9-
prompt: z
10-
.string()
11-
.describe("The prompt/task for the sub-agent"),
10+
prompt: z.string().describe("The prompt/task for the sub-agent"),
1211
description: z
1312
.string()
1413
.max(80)
@@ -17,7 +16,9 @@ const parameterSchema = z.object({
1716

1817
const returnSchema = z
1918
.object({
20-
instanceId: z.string().describe("Unique identifier for the sub-agent instance"),
19+
instanceId: z
20+
.string()
21+
.describe("Unique identifier for the sub-agent instance"),
2122
response: z.string().describe("Initial response from the sub-agent"),
2223
})
2324
.describe("Result containing sub-agent instance ID and initial response");
@@ -27,65 +28,77 @@ type ReturnType = z.infer<typeof returnSchema>;
2728

2829
export const subAgentStartTool: Tool<Parameters, ReturnType> = {
2930
name: "subAgentStart",
30-
description: "Creates a sub-agent that has access to all tools to solve a specific task",
31+
description:
32+
"Creates a sub-agent that has access to all tools to solve a specific task",
3133
parameters: zodToJsonSchema(parameterSchema),
3234
returns: zodToJsonSchema(returnSchema),
3335

34-
execute: async (
35-
params,
36-
{ logger },
37-
): Promise<ReturnType> => {
38-
if (!process.env.ANTHROPIC_API_KEY) {
39-
throw new Error("ANTHROPIC_API_KEY environment variable is not set");
40-
}
41-
42-
const anthropic = new Anthropic({
43-
apiKey: process.env.ANTHROPIC_API_KEY,
44-
});
45-
46-
// Create new instance ID
36+
execute: async (params, { logger }): Promise<ReturnType> => {
4737
const instanceId = uuidv4();
4838
logger.verbose(`Creating new sub-agent with instance ID: ${instanceId}`);
4939

50-
// Initialize sub-agent state
51-
subAgentStates.set(instanceId, {
52-
prompt: params.prompt,
53-
messages: [],
54-
aborted: false,
55-
});
56-
57-
// Get initial response
58-
logger.verbose(`Getting initial response from Anthropic API`);
59-
const response = await anthropic.messages.create({
60-
model: "claude-3-opus-20240229",
61-
max_tokens: 4096,
62-
messages: [
63-
{
64-
role: "user",
65-
content: params.prompt,
66-
},
67-
],
68-
});
69-
70-
// Check if response content exists and has the expected structure
71-
if (!response.content?.[0]?.text) {
72-
throw new Error("Invalid response from Anthropic API");
73-
}
40+
try {
41+
const tools = (await getTools()).filter(
42+
(tool) => tool.name !== "userPrompt"
43+
);
44+
45+
// Initialize toolAgent
46+
const toolAgentState = toolAgent(params.prompt, tools, logger);
7447

75-
const responseText = response.content[0].text;
76-
logger.verbose(`Received response from sub-agent`);
48+
// Initialize sub-agent state
49+
const state: SubAgentState = {
50+
prompt: params.prompt,
51+
messages: [],
52+
aborted: false,
53+
toolAgentState,
54+
};
55+
subAgentStates.set(instanceId, state);
7756

78-
// Store the interaction
79-
const state = subAgentStates.get(instanceId)!;
80-
state.messages.push(
81-
{ role: "user", content: params.prompt },
82-
{ role: "assistant", content: responseText },
83-
);
57+
// Set up message handling
58+
return new Promise((resolve, reject) => {
59+
let messageReceived = false;
8460

85-
return {
86-
instanceId,
87-
response: responseText,
88-
};
61+
const messageHandler = (message: any) => {
62+
if (message.type === "assistant" && !messageReceived) {
63+
messageReceived = true;
64+
const initialResponse = message.content;
65+
66+
// Store the interaction
67+
state.messages.push(
68+
{ role: "user", content: params.prompt },
69+
{ role: "assistant", content: initialResponse }
70+
);
71+
72+
resolve({
73+
instanceId,
74+
response: initialResponse,
75+
});
76+
}
77+
};
78+
79+
const errorHandler = (error: Error) => {
80+
state.aborted = true;
81+
reject(error);
82+
};
83+
84+
const endHandler = () => {
85+
if (!messageReceived) {
86+
state.aborted = true;
87+
reject(
88+
new Error("Stream ended without receiving assistant message")
89+
);
90+
}
91+
};
92+
93+
toolAgentState.outMessages
94+
.on("data", messageHandler)
95+
.on("error", errorHandler)
96+
.on("end", endHandler);
97+
});
98+
} catch (error) {
99+
logger.error(`Failed to start sub-agent: ${error}`);
100+
throw error;
101+
}
89102
},
90103

91104
logParameters: (input, { logger }) => {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import { ToolAgentState } from "../../core/toolAgent.js";
2+
13
// Map to store sub-agent states
24
export interface SubAgentState {
35
prompt: string;
46
messages: Array<{ role: "user" | "assistant"; content: string }>;
57
aborted: boolean;
8+
toolAgentState: ToolAgentState;
69
}
710

811
export const subAgentStates = new Map<string, SubAgentState>();

0 commit comments

Comments
 (0)